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