mdns_common.c
Go to the documentation of this file.
1 /**
2  * @file mdns_common.c
3  * @brief Definitions common to mDNS client and mDNS responder
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Multicast DNS and its companion technology DNS-Based Service Discovery
30  * were created to provide ease-of-use and autoconfiguration to IP networks.
31  * Refer to the following RFCs for complete details:
32  * - RFC 6762: Multicast DNS
33  * - RFC 6763: DNS-Based Service Discovery
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 1.9.6
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL MDNS_TRACE_LEVEL
41 
42 //Dependencies
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include "core/net.h"
47 #include "ipv4/ipv4_misc.h"
48 #include "ipv6/ipv6_misc.h"
49 #include "mdns/mdns_client.h"
50 #include "mdns/mdns_responder.h"
51 #include "mdns/mdns_common.h"
52 #include "dns/dns_debug.h"
53 #include "debug.h"
54 
55 //Check TCP/IP stack configuration
56 #if (MDNS_CLIENT_SUPPORT == ENABLED || MDNS_RESPONDER_SUPPORT == ENABLED)
57 
58 //mDNS IPv6 multicast group (ff02::fb)
60  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00FB);
61 
62 
63 /**
64  * @brief mDNS related initialization
65  * @param[in] interface Underlying network interface
66  * @return Error code
67  **/
68 
70 {
71  error_t error;
72 
73 #if (IPV4_SUPPORT == ENABLED)
74  //Join the mDNS IPv4 multicast group
76  //Any error to report?
77  if(error)
78  return error;
79 #endif
80 
81 #if (IPV6_SUPPORT == ENABLED)
82  //Join the mDNS IPv6 multicast group
84  //Any error to report?
85  if(error)
86  return error;
87 #endif
88 
89  //Callback function to be called when a mDNS message is received
90  error = udpAttachRxCallback(interface, MDNS_PORT, mdnsProcessMessage, NULL);
91  //Any error to report?
92  if(error)
93  return error;
94 
95  //Successful initialization
96  return NO_ERROR;
97 }
98 
99 
100 /**
101  * @brief Process incoming mDNS message
102  * @param[in] interface Underlying network interface
103  * @param[in] pseudoHeader UDP pseudo header
104  * @param[in] udpHeader UDP header
105  * @param[in] buffer Multi-part buffer containing the incoming mDNS message
106  * @param[in] offset Offset to the first byte of the mDNS message
107  * @param[in] param Callback function parameter (not used)
108  **/
109 
110 void mdnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
111  const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *param)
112 {
113  size_t length;
114  DnsHeader *dnsHeader;
116 
117  //Retrieve the length of the mDNS message
118  length = netBufferGetLength(buffer) - offset;
119 
120  //Ensure the mDNS message is valid
121  if(length < sizeof(DnsHeader))
122  return;
124  return;
125 
126  //Point to the mDNS message header
127  dnsHeader = netBufferAt(buffer, offset);
128  //Sanity check
129  if(dnsHeader == NULL)
130  return;
131 
132  //Debug message
133  TRACE_INFO("mDNS message received (%" PRIuSIZE " bytes)...\r\n", length);
134  //Dump message
135  dnsDumpMessage(dnsHeader, length);
136 
137  //mDNS messages received with an opcode other than zero must be silently
138  //ignored
139  if(dnsHeader->opcode != DNS_OPCODE_QUERY)
140  return;
141 
142  //mDNS messages received with non-zero response codes must be silently
143  //ignored
144  if(dnsHeader->rcode != DNS_RCODE_NO_ERROR)
145  return;
146 
147  //Save mDNS message
148  message.buffer = (NetBuffer *) buffer;
149  message.offset = offset;
150  message.length = length;
151  message.pseudoHeader = pseudoHeader;
152  message.udpHeader = udpHeader;
153  message.dnsHeader = dnsHeader;
154 
155  //mDNS query received?
156  if(!dnsHeader->qr)
157  {
158 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
159  //Process incoming mDNS query message
160  mdnsResponderProcessQuery(interface, &message);
161 #endif
162  }
163  //mDNS response received?
164  else
165  {
166  //Process incoming mDNS response message
167  mdnsProcessResponse(interface, &message);
168  }
169 }
170 
171 
172 /**
173  * @brief Process mDNS response message
174  * @param[in] interface Underlying network interface
175  * @param[in] response Incoming mDNS response message
176  **/
177 
178 void mdnsProcessResponse(NetInterface *interface, MdnsMessage *response)
179 {
180  uint_t i;
181  uint_t k;
182  size_t n;
183  size_t offset;
184  DnsResourceRecord *record;
185 
186  //Source address check (refer to RFC 6762 section 11)
187  if(!mdnsCheckSourceAddr(interface, response->pseudoHeader))
188  return;
189 
190  //mDNS implementations must silently ignore any mDNS responses they
191  //receive where the source UDP port is not 5353
192  if(ntohs(response->udpHeader->srcPort) != MDNS_PORT)
193  return;
194 
195  //Point to the question section
196  offset = sizeof(DnsHeader);
197 
198  //Any questions in the question section of a received mDNS response
199  //must be silently ignored
200  for(i = 0; i < ntohs(response->dnsHeader->qdcount); i++)
201  {
202  //Parse domain name
203  offset = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
204  //Invalid name?
205  if(!offset)
206  break;
207 
208  //Point to the next question
209  offset += sizeof(DnsQuestion);
210  //Make sure the mDNS message is valid
211  if(offset > response->length)
212  break;
213  }
214 
215  //Malformed mDNS message?
216  if(i != ntohs(response->dnsHeader->qdcount))
217  return;
218 
219  //Compute the total number of resource records
220  k = ntohs(response->dnsHeader->ancount) +
221  ntohs(response->dnsHeader->nscount) +
222  ntohs(response->dnsHeader->arcount);
223 
224  //Loop through the resource records
225  for(i = 0; i < k; i++)
226  {
227  //Parse resource record name
228  n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
229  //Invalid name?
230  if(!n)
231  break;
232 
233  //Point to the associated resource record
234  record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
235  //Point to the resource data
236  n += sizeof(DnsResourceRecord);
237 
238  //Make sure the resource record is valid
239  if(n > response->length)
240  break;
241  if((n + ntohs(record->rdlength)) > response->length)
242  break;
243 
244 #if (MDNS_CLIENT_SUPPORT == ENABLED)
245  //Parse the resource record
246  mdnsClientParseAnRecord(interface, response, offset, record);
247 #endif
248 
249 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
250  //Parse the resource record
251  mdnsResponderParseAnRecord(interface, response, offset, record);
252 #endif
253 
254 #if (DNS_SD_SUPPORT == ENABLED)
255  //Parse the resource record
256  dnsSdParseAnRecord(interface, response, offset, record);
257 #endif
258 
259  //Point to the next resource record
260  offset = n + ntohs(record->rdlength);
261  }
262 }
263 
264 
265 /**
266  * @brief Source address check
267  * @param[in] interface Underlying network interface
268  * @param[in] pseudoHeader UDP pseudo header
269  * @return TRUE if the source address is valid, else FALSE
270  **/
271 
273  const IpPseudoHeader *pseudoHeader)
274 {
275  bool_t valid;
276 
277 #if (IPV4_SUPPORT == ENABLED)
278  //IPv4 packet received?
279  if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
280  {
281  //Perform source address check (refer to RFC 6762 section 11)
282  if(pseudoHeader->ipv4Data.destAddr == MDNS_IPV4_MULTICAST_ADDR)
283  {
284  //All responses received with the destination address 224.0.0.251
285  //are necessarily deemed to have originated on the local link,
286  //regardless of source IP address
287  valid = TRUE;
288  }
289  else if(ipv4IsLinkLocalAddr(pseudoHeader->ipv4Data.srcAddr) ||
290  ipv4IsLinkLocalAddr(pseudoHeader->ipv4Data.destAddr))
291  {
292  //Packets with a link-local source or destination address
293  //originate from the local link
294  valid = TRUE;
295  }
296  else if(ipv4IsOnLink(interface, pseudoHeader->ipv4Data.srcAddr))
297  {
298  //The source IP address is on the local link
299  valid = TRUE;
300  }
301  else
302  {
303  //Only accept responses that originate from the local link, and
304  //silently discard any other response packets
305  valid = FALSE;
306  }
307  }
308  else
309 #endif
310 #if (IPV6_SUPPORT == ENABLED)
311  //IPv6 packet received?
312  if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
313  {
314  //Perform source address check (refer to RFC 6762 section 11)
315  if(ipv6CompAddr(&pseudoHeader->ipv6Data.destAddr, &MDNS_IPV6_MULTICAST_ADDR))
316  {
317  //All responses received with the destination address ff02::fb
318  //are necessarily deemed to have originated on the local link,
319  //regardless of source IP address
320  valid = TRUE;
321  }
322  else if(ipv6IsOnLink(interface, &pseudoHeader->ipv6Data.srcAddr))
323  {
324  //The source IP address is on the local link
325  valid = TRUE;
326  }
327  else
328  {
329  //Only accept responses that originate from the local link, and
330  //silently discard any other response packets
331  valid = FALSE;
332  }
333  }
334  else
335 #endif
336  //Invalid packet received?
337  {
338  //Discard the response packet
339  valid = FALSE;
340  }
341 
342  //Return flag value
343  return valid;
344 }
345 
346 
347 /**
348  * @brief Create an empty mDNS message
349  * @param[in,out] message Newly created mDNS message
350  * @param[in] queryResponse This flag specifies whether the message is a query or a response
351  * @return Error code
352  **/
353 
355 {
356  error_t error;
357 
358  //Allocate a memory buffer to hold the mDNS message
360 
361  //Successful memory allocation?
362  if(message->buffer != NULL)
363  {
364  //Point to the mDNS message header
365  message->dnsHeader = netBufferAt(message->buffer, message->offset);
366 
367  //Sanity check
368  if(message->dnsHeader != NULL)
369  {
370  //Format mDNS message header
371  message->dnsHeader->id = 0;
372  message->dnsHeader->opcode = DNS_OPCODE_QUERY;
373  message->dnsHeader->tc = 0;
374  message->dnsHeader->rd = 0;
375  message->dnsHeader->ra = 0;
376  message->dnsHeader->z = 0;
377  message->dnsHeader->rcode = DNS_RCODE_NO_ERROR;
378  message->dnsHeader->qdcount = 0;
379  message->dnsHeader->ancount = 0;
380  message->dnsHeader->nscount = 0;
381  message->dnsHeader->arcount = 0;
382 
383  //Query or response mDNS message?
384  if(!queryResponse)
385  {
386  //In query messages, QR and AA bits must be set to zero
387  message->dnsHeader->qr = 0;
388  message->dnsHeader->aa = 0;
389  }
390  else
391  {
392  //In response messages, QR and AA bits must be set to one
393  message->dnsHeader->qr = 1;
394  message->dnsHeader->aa = 1;
395  }
396 
397  //Number of shared resource records
398  message->sharedRecordCount = 0;
399  //Length of the mDNS message
400  message->length = sizeof(DnsHeader);
401 
402  //Successful processing
403  error = NO_ERROR;
404  }
405  else
406  {
407  //Clean up side effects
409 
410  //Report an error
411  error = ERROR_FAILURE;
412  }
413  }
414  else
415  {
416  //Failed to allocate memory
417  error = ERROR_OUT_OF_RESOURCES;
418  }
419 
420  //Return status code
421  return error;
422 }
423 
424 
425 /**
426  * @brief release a mDNS message
427  * @param[in] message mDNS message to be released
428  **/
429 
431 {
432  //Valid mDNS message?
433  if(message->buffer != NULL)
434  {
435  //Free previously allocated memory
436  netBufferFree(message->buffer);
437 
438  //The mDNS message is no more valid
439  message->buffer = NULL;
440  message->length = 0;
441  }
442 }
443 
444 
445 /**
446  * @brief Send mDNS message
447  * @param[in] interface Underlying network interface
448  * @param[in] message mDNS message to be sent
449  * @param[in] destIpAddr Destination IP address (optional parameter)
450  * @param[in] destPort Destination port
451  * @return Error code
452  **/
453 
456 {
457  error_t error;
458  IpAddr ipAddr;
459 
460  //Make sure the mDNS message is valid
461  if(message->buffer == NULL)
462  return ERROR_FAILURE;
463 
464  //Convert 16-bit values to network byte order
465  message->dnsHeader->qdcount = htons(message->dnsHeader->qdcount);
466  message->dnsHeader->nscount = htons(message->dnsHeader->nscount);
467  message->dnsHeader->ancount = htons(message->dnsHeader->ancount);
468  message->dnsHeader->arcount = htons(message->dnsHeader->arcount);
469 
470  //Start of exception handling block
471  do
472  {
473  //Adjust the length of the multi-part buffer
474  error = netBufferSetLength(message->buffer, message->offset + message->length);
475  //Any error to report?
476  if(error)
477  break;
478 
479  //Debug message
480  TRACE_INFO("Sending mDNS message (%" PRIuSIZE " bytes)...\r\n", message->length);
481  //Dump message
482  dnsDumpMessage(message->dnsHeader, message->length);
483 
484  //Check whether the message should be sent to a specific IP address
485  if(destIpAddr != NULL)
486  {
487  //All multicast DNS responses should be sent with an IP TTL set to 255
488  error = udpSendDatagramEx(interface, NULL, MDNS_PORT, destIpAddr,
489  destPort, message->buffer, message->offset, MDNS_DEFAULT_IP_TTL);
490  //Any error to report?
491  if(error)
492  break;
493  }
494  else
495  {
496 #if (IPV4_SUPPORT == ENABLED)
497  //Select the relevant multicast address (224.0.0.251)
498  ipAddr.length = sizeof(Ipv4Addr);
499  ipAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;
500 
501  //All multicast DNS queries should be sent with an IP TTL set to 255
502  error = udpSendDatagramEx(interface, NULL, MDNS_PORT, &ipAddr,
503  MDNS_PORT, message->buffer, message->offset, MDNS_DEFAULT_IP_TTL);
504  //Any error to report?
505  if(error)
506  break;
507 #endif
508 
509 #if (IPV6_SUPPORT == ENABLED)
510  //Select the relevant multicast address (ff02::fb)
511  ipAddr.length = sizeof(Ipv6Addr);
512  ipAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;
513 
514  //All multicast DNS queries should be sent with an IP TTL set to 255
515  error = udpSendDatagramEx(interface, NULL, MDNS_PORT, &ipAddr,
516  MDNS_PORT, message->buffer, message->offset, MDNS_DEFAULT_IP_TTL);
517  //Any error to report?
518  if(error)
519  break;
520 #endif
521  }
522 
523  //End of exception handling block
524  } while(0);
525 
526  //Return status code
527  return error;
528 }
529 
530 
531 /**
532  * @brief Encode instance, service and domain names using the DNS name notation
533  * @param[in] instance Instance name
534  * @param[in] service Service name
535  * @param[in] domain Domain name
536  * @param[out] dest Pointer to the encoded name (optional parameter)
537  * @return Length of the encoded domain name
538  **/
539 
540 size_t mdnsEncodeName(const char_t *instance, const char_t *service,
541  const char_t *domain, uint8_t *dest)
542 {
543  size_t n;
544  size_t length;
545 
546  //Total length of the encoded name
547  length = 0;
548 
549  //Any instance name?
550  if(*instance != '\0')
551  {
552  //Encode instance name
553  n = dnsEncodeName(instance, dest);
554 
555  //Failed to encode instance name?
556  if(!n)
557  return 0;
558 
559  //Update the length of the encoded name
560  length += n;
561  }
562 
563  //Any service name?
564  if(*service != '\0')
565  {
566  //If an instance name precedes the service name, then
567  //remove the null label
568  if(length > 0)
569  length--;
570 
571  //Encode service name
572  if(dest != NULL)
573  n = dnsEncodeName(service, dest + length);
574  else
575  n = dnsEncodeName(service, NULL);
576 
577  //Failed to encode instance name?
578  if(!n)
579  return 0;
580 
581  //Update the length of the encoded name
582  length += n;
583  }
584 
585  //Skip the separator that may precede the domain name
586  if(*domain == '.')
587  domain++;
588 
589  //Any domain name to encode?
590  if(*domain != '\0')
591  {
592  //If an instance or a service name precedes the domain name, then
593  //remove the null label
594  if(length > 0)
595  length--;
596 
597  //Encode domain name
598  if(dest != NULL)
599  n = dnsEncodeName(domain, dest + length);
600  else
601  n = dnsEncodeName(domain, NULL);
602 
603  //Failed to encode instance name?
604  if(!n)
605  return 0;
606 
607  //Update the length of the encoded name
608  length += n;
609  }
610 
611  //Return the length of the encoded string
612  return length;
613 }
614 
615 
616 /**
617  * @brief Compare instance, service and domain names
618  * @param[in] message Pointer to the DNS message
619  * @param[in] length Length of the DNS message
620  * @param[in] pos Offset of the encoded name
621  * @param[in] instance Instance name
622  * @param[in] service Service name
623  * @param[in] domain Domain name
624  * @param[in] level Current level of recursion
625  * @return The function returns 0 if the domain names match, -1 if the first
626  * domain name lexicographically precedes the second name, or 1 if the
627  * second domain name lexicographically precedes the first name
628  **/
629 
630 int_t mdnsCompareName(const DnsHeader *message, size_t length, size_t pos,
631  const char_t *instance, const char_t *service, const char_t *domain, uint_t level)
632 {
633  int_t res;
634  size_t n;
635  size_t pointer;
636  uint8_t *p;
637 
638  //Check parameters
639  if(instance == NULL || service == NULL || domain == NULL)
640  return -2;
641 
642  //Recursion limit exceeded?
644  return -2;
645 
646  //Cast the DNS message to byte array
647  p = (uint8_t *) message;
648 
649  //Skip the separator that may precede the domain name
650  if(*domain == '.')
651  domain++;
652 
653  //Parse encoded domain name
654  while(pos < length)
655  {
656  //Retrieve the length of the current label
657  n = p[pos];
658 
659  //End marker found?
660  if(n == 0)
661  {
662  //The domain name which still has remaining data is deemed
663  //lexicographically later
664  if(*instance != '\0' || *service != '\0' || *domain != '\0')
665  return -1;
666 
667  //The domain names match each other
668  return 0;
669  }
670  //Compression tag found?
671  if(n >= DNS_COMPRESSION_TAG)
672  {
673  //Malformed DNS message?
674  if((pos + 1) >= length)
675  return -2;
676 
677  //Read the most significant byte of the pointer
678  pointer = (p[pos] & ~DNS_COMPRESSION_TAG) << 8;
679  //Read the least significant byte of the pointer
680  pointer |= p[pos + 1];
681 
682  //Compare the remaining part
684  instance, service, domain, level + 1);
685 
686  //Return comparison result
687  return res;
688  }
689  else
690  {
691  //Advance data pointer
692  pos++;
693 
694  //Malformed DNS message?
695  if((pos + n) > length)
696  return -2;
697 
698  //Compare current label
699  if(*instance != '\0')
700  {
701  //Compare instance name
702  res = strncasecmp((char_t *) p + pos, instance, n);
703  //Any mismatch?
704  if(res)
705  return res;
706 
707  //Advance data pointer
708  instance += n;
709 
710  //The instance name which still has remaining data is deemed
711  //lexicographically later
712  if(*instance != '\0' && *instance != '.')
713  return -1;
714 
715  //Skip the separator character, if any
716  if(*instance == '.')
717  instance++;
718  }
719  else if(*service != '\0')
720  {
721  //Compare service name
722  res = strncasecmp((char_t *) p + pos, service, n);
723  //Any mismatch?
724  if(res)
725  return res;
726 
727  //Advance data pointer
728  service += n;
729 
730  //The service name which still has remaining data is deemed
731  //lexicographically later
732  if(*service != '\0' && *service != '.')
733  return -1;
734 
735  //Any separator in service name?
736  if(*service == '.')
737  service++;
738  }
739  else
740  {
741  //Compare domain name
742  res = strncasecmp((char_t *) p + pos, domain, n);
743  //Any mismatch?
744  if(res)
745  return res;
746 
747  //Advance data pointer
748  domain += n;
749 
750  //The domain name which still has remaining data is deemed
751  //lexicographically later
752  if(*domain != '\0' && *domain != '.')
753  return -1;
754 
755  //Any separator in domain name?
756  if(*domain == '.')
757  domain++;
758  }
759 
760  //Advance data pointer
761  pos += n;
762  }
763  }
764 
765  //Malformed DNS message
766  return -2;
767 }
768 
769 
770 /**
771  * @brief Compare resource records
772  * @param[in] message1 Pointer to the first mDNS message
773  * @param[in] offset1 Offset of the first but of the resource record
774  * @param[in] record1 Pointer the first resource record
775  * @param[in] message2 Pointer to the second mDNS message
776  * @param[in] offset2 Offset of the first but of the resource record
777  * @param[in] record2 Pointer the second resource record
778  * @return The function returns 0 if the resource records match, -1 if the first
779  * resource record lexicographically precedes the second one, or 1 if the
780  * second resource record lexicographically precedes the first one
781  **/
782 
783 int_t mdnsCompareRecord(const MdnsMessage *message1, size_t offset1,
784  const DnsResourceRecord *record1, const MdnsMessage *message2,
785  size_t offset2, const DnsResourceRecord *record2)
786 {
787  int_t res;
788  size_t n1;
789  size_t n2;
790  uint16_t value1;
791  uint16_t value2;
792 
793  //Convert the record class to host byte order
794  value1 = ntohs(record1->rclass);
795  value2 = ntohs(record2->rclass);
796 
797  //Discard cache-flush bit
798  value1 &= ~MDNS_RCLASS_CACHE_FLUSH;
799  value2 &= ~MDNS_RCLASS_CACHE_FLUSH;
800 
801  //The determination of lexicographically later record is performed by
802  //first comparing the record class (excluding the cache-flush bit)
803  if(value1 < value2)
804  return -1;
805  else if(value1 > value2)
806  return 1;
807 
808  //Convert the record type to host byte order
809  value1 = ntohs(record1->rtype);
810  value2 = ntohs(record2->rtype);
811 
812  //Then compare the record type
813  if(value1 < value2)
814  return -1;
815  else if(value1 > value2)
816  return 1;
817 
818  //If the rrtype and rrclass both match, then the rdata is compared
819  if(value1 == DNS_RR_TYPE_NS || value1 == DNS_RR_TYPE_SOA ||
820  value1 == DNS_RR_TYPE_CNAME || value1 == DNS_RR_TYPE_PTR)
821  {
822  //Compute the offset of the first byte of the rdata
823  n1 = record1->rdata - (uint8_t *) message1->dnsHeader;
824  n2 = record2->rdata - (uint8_t *) message2->dnsHeader;
825 
826  //The names must be uncompressed before comparison
827  res = dnsCompareEncodedName(message1->dnsHeader, message1->length,
828  n1, message2->dnsHeader, message2->length, n2, 0);
829  }
830  else
831  {
832  //Retrieve the length of the rdata fields
833  n1 = htons(record1->rdlength);
834  n2 = htons(record2->rdlength);
835 
836  //The bytes of the raw uncompressed rdata are compared in turn, interpreting
837  //the bytes as eight-bit unsigned values, until a byte is found whose value
838  //is greater than that of its counterpart (in which case, the rdata whose
839  //byte has the greater value is deemed lexicographically later) or one of the
840  //resource records runs out of rdata (in which case, the resource record which
841  //still has remaining data first is deemed lexicographically later)
842  if(n1 < n2)
843  {
844  //Raw comparison of the binary content of the rdata
845  res = memcmp(record1->rdata, record2->rdata, n1);
846 
847  //Check comparison result
848  if(!res)
849  {
850  //The first resource records runs out of rdata
851  res = -1;
852  }
853  }
854  else if(n1 > n2)
855  {
856  //Raw comparison of the binary content of the rdata
857  res = memcmp(record1->rdata, record2->rdata, n2);
858 
859  //Check comparison result
860  if(!res)
861  {
862  //The second resource records runs out of rdata
863  res = 1;
864  }
865  }
866  else
867  {
868  //Raw comparison of the binary content of the rdata
869  res = memcmp(record1->rdata, record2->rdata, n1);
870  }
871  }
872 
873  //Return comparison result
874  return res;
875 }
876 
877 
878 /**
879  * @brief Check for duplicate resource records
880  * @param[in] message Pointer to the mDNS message
881  * @param[in] instance Instance name
882  * @param[in] service Service name
883  * @param[in] domain Domain name
884  * @param[in] rtype Resource record type
885  * @return The function returns TRUE is the specified resource record is a
886  * duplicate. Otherwise FALSE is returned
887  **/
888 
890  const char_t *service, const char_t *domain, uint16_t rtype)
891 {
892  uint_t i;
893  uint_t k;
894  size_t n;
895  size_t offset;
896  uint16_t rclass;
897  bool_t duplicate;
898  DnsResourceRecord *record;
899 
900  //Clear flag
901  duplicate = FALSE;
902 
903  //Point to the first question
904  offset = sizeof(DnsHeader);
905 
906  //Parse the Question Section
907  for(i = 0; i < message->dnsHeader->qdcount; i++)
908  {
909  //Parse domain name
910  offset = dnsParseName(message->dnsHeader, message->length, offset, NULL, 0);
911  //Invalid name?
912  if(!offset)
913  break;
914 
915  //Point to the next question
916  offset += sizeof(DnsQuestion);
917  //Make sure the mDNS message is valid
918  if(offset > message->length)
919  break;
920  }
921 
922  //Successful processing?
923  if(i == message->dnsHeader->qdcount)
924  {
925  //Compute the total number of resource records
926  k = message->dnsHeader->ancount + message->dnsHeader->nscount +
927  message->dnsHeader->arcount;
928 
929  //Loop through the resource records
930  for(i = 0; i < k; i++)
931  {
932  //Parse resource record name
933  n = dnsParseName(message->dnsHeader, message->length, offset, NULL, 0);
934  //Invalid name?
935  if(!n)
936  break;
937 
938  //Point to the associated resource record
939  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, n);
940  //Point to the resource data
941  n += sizeof(DnsResourceRecord);
942 
943  //Make sure the resource record is valid
944  if(n > message->length)
945  break;
946  if((n + ntohs(record->rdlength)) > message->length)
947  break;
948 
949  //Convert the record class to host byte order
950  rclass = ntohs(record->rclass);
951  //Discard cache-flush bit
953 
954  //Check the class and the type of the resource record
955  if(rclass == DNS_RR_CLASS_IN && ntohs(record->rtype) == rtype)
956  {
957  //Compare resource record name
958  if(!mdnsCompareName(message->dnsHeader, message->length,
959  offset, instance, service, domain, 0))
960  {
961  //The resource record is already present in the Answer Section
962  duplicate = TRUE;
963  //We are done
964  break;
965  }
966  }
967 
968  //Point to the next resource record
969  offset = n + ntohs(record->rdlength);
970  }
971  }
972 
973  //The function returns TRUE is the specified resource record is a duplicate
974  return duplicate;
975 }
976 
977 #endif
error_t udpSendDatagramEx(NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, uint_t flags)
Send a UDP datagram (raw interface)
Definition: udp.c:463
void mdnsClientParseAnRecord(NetInterface *interface, const MdnsMessage *message, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
Definition: mdns_client.c:258
#define htons(value)
Definition: cpu_endian.h:392
uint8_t length
Definition: dtls_misc.h:149
Ipv6PseudoHeader ipv6Data
Definition: ip.h:99
int bool_t
Definition: compiler_port.h:49
const Ipv6Addr MDNS_IPV6_MULTICAST_ADDR
Definition: mdns_common.c:59
void mdnsResponderProcessQuery(NetInterface *interface, MdnsMessage *query)
Process mDNS query message.
signed int int_t
Definition: compiler_port.h:44
int_t mdnsCompareName(const DnsHeader *message, size_t length, size_t pos, const char_t *instance, const char_t *service, const char_t *domain, uint_t level)
Compare instance, service and domain names.
Definition: mdns_common.c:630
IP network address.
Definition: ip.h:71
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:112
@ DNS_OPCODE_QUERY
Definition: dns_common.h:81
@ DNS_RR_TYPE_SOA
Start of a zone of authority.
Definition: dns_common.h:126
uint8_t p
Definition: ndp.h:298
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
#define TRUE
Definition: os_port.h:50
#define strncasecmp
__start_packed struct @146 DnsHeader
DNS message header.
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
size_t dnsParseName(const DnsHeader *message, size_t length, size_t pos, char_t *dest, uint_t level)
Decode a domain name that uses the DNS name encoding.
Definition: dns_common.c:130
DnsHeader * dnsHeader
Definition: mdns_common.h:84
uint16_t rclass
Definition: dns_common.h:204
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:121
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:110
#define ipv4IsLinkLocalAddr(ipAddr)
Definition: ipv4.h:158
uint16_t destPort
Definition: tcp.h:303
uint16_t rtype
Definition: dns_common.h:203
size_t length
Definition: ip.h:92
const uint8_t res[]
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:239
__start_packed struct @148 DnsResourceRecord
Resource record format.
#define MDNS_DEFAULT_IP_TTL
Definition: mdns_common.h:55
Definitions common to mDNS client and mDNS responder.
void mdnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *param)
Process incoming mDNS message.
Definition: mdns_common.c:110
uint8_t level
Definition: tls.h:1702
#define DNS_NAME_MAX_RECURSION
Definition: dns_common.h:39
IP pseudo header.
Definition: ip.h:90
#define MDNS_PORT
Definition: mdns_common.h:53
Helper functions for IPv4.
#define FALSE
Definition: os_port.h:46
error_t
Error codes.
Definition: error.h:42
void dnsSdParseAnRecord(NetInterface *interface, const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
Definition: dns_sd.c:1337
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
#define Ipv6PseudoHeader
Definition: ipv6.h:42
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:413
error_t mdnsInit(NetInterface *interface)
mDNS related initialization
Definition: mdns_common.c:69
const IpPseudoHeader * pseudoHeader
Definition: mdns_common.h:82
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
size_t length
Definition: mdns_common.h:81
void mdnsResponderParseAnRecord(NetInterface *interface, const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
#define NetInterface
Definition: net.h:36
#define DNS_COMPRESSION_TAG
Definition: dns_common.h:60
error_t udpAttachRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *param)
Register user callback.
Definition: udp.c:764
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
bool_t mdnsCheckDuplicateRecord(const MdnsMessage *message, const char_t *instance, const char_t *service, const char_t *domain, uint16_t rtype)
Check for duplicate resource records.
Definition: mdns_common.c:889
Helper functions for IPv6.
@ DNS_RR_TYPE_PTR
Domain name pointer.
Definition: dns_common.h:128
error_t mdnsCreateMessage(MdnsMessage *message, bool_t queryResponse)
Create an empty mDNS message.
Definition: mdns_common.c:354
mDNS client (Multicast DNS)
__start_packed struct @179 Ipv6Addr
IPv6 network address.
__start_packed struct @122 UdpHeader
UDP header.
error_t ipv6JoinMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
Join an IPv6 multicast group.
Definition: ipv6.c:1928
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:94
int_t mdnsCompareRecord(const MdnsMessage *message1, size_t offset1, const DnsResourceRecord *record1, const MdnsMessage *message2, size_t offset2, const DnsResourceRecord *record2)
Compare resource records.
Definition: mdns_common.c:783
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
void dnsDumpMessage(const DnsHeader *message, size_t length)
Dump DNS message for debugging purpose.
Definition: dns_debug.c:52
bool_t ipv4IsOnLink(NetInterface *interface, Ipv4Addr ipAddr)
Check whether an IPv4 address is on-link.
Definition: ipv4_misc.c:351
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:697
@ DNS_RR_TYPE_NS
Authoritative name server.
Definition: dns_common.h:124
int_t dnsCompareEncodedName(const DnsHeader *message1, size_t length1, size_t pos1, const DnsHeader *message2, size_t length2, size_t pos2, uint_t level)
Compare domain names encoded with DNS notation.
Definition: dns_common.c:339
size_t dnsEncodeName(const char_t *src, uint8_t *dest)
Encode a domain name using the DNS name notation.
Definition: dns_common.c:56
#define ntohs(value)
Definition: cpu_endian.h:398
mDNS message
Definition: mdns_common.h:77
char char_t
Definition: compiler_port.h:43
void mdnsDeleteMessage(MdnsMessage *message)
release a mDNS message
Definition: mdns_common.c:430
uint8_t n
uint32_t pointer
Definition: icmp.h:166
const UdpHeader * udpHeader
Definition: mdns_common.h:83
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:320
#define MDNS_MESSAGE_MAX_SIZE
Definition: mdns_common.h:40
uint8_t message[]
Definition: chap.h:152
@ DNS_RR_TYPE_CNAME
Canonical name for an alias.
Definition: dns_common.h:125
bool_t mdnsCheckSourceAddr(NetInterface *interface, const IpPseudoHeader *pseudoHeader)
Source address check.
Definition: mdns_common.c:272
__start_packed struct @147 DnsQuestion
Question format.
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
Join the specified host group.
Definition: ipv4.c:1194
#define MDNS_IPV4_MULTICAST_ADDR
Definition: mdns_common.h:65
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
@ DNS_RCODE_NO_ERROR
Definition: dns_common.h:95
bool_t ipv6IsOnLink(NetInterface *interface, const Ipv6Addr *ipAddr)
Check whether an IPv6 address is on-link.
Definition: ipv6_misc.c:1032
Data logging functions for debugging purpose (DNS)
size_t mdnsEncodeName(const char_t *instance, const char_t *service, const char_t *domain, uint8_t *dest)
Encode instance, service and domain names using the DNS name notation.
Definition: mdns_common.c:540
uint8_t ipAddr[4]
Definition: mib_common.h:187
Ipv4PseudoHeader ipv4Data
Definition: ip.h:96
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void mdnsProcessResponse(NetInterface *interface, MdnsMessage *response)
Process mDNS response message.
Definition: mdns_common.c:178
error_t mdnsSendMessage(NetInterface *interface, const MdnsMessage *message, const IpAddr *destIpAddr, uint_t destPort)
Send mDNS message.
Definition: mdns_common.c:454
mDNS responder (Multicast DNS)
#define MDNS_RCLASS_CACHE_FLUSH
Definition: mdns_common.h:62
Ipv4Addr destIpAddr
Definition: ipcp.h:78