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