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.4
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_multicast.h"
45 #include "ipv4/ipv4_misc.h"
46 #include "ipv6/ipv6_multicast.h"
47 #include "ipv6/ipv6_misc.h"
48 #include "mdns/mdns_client.h"
49 #include "mdns/mdns_responder.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] ancillary Additional options passed to the stack along with
108  * the packet
109  * @param[in] param Callback function parameter (not used)
110  **/
111 
113  const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
114  const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary,
115  void *param)
116 {
117  size_t length;
118  DnsHeader *dnsHeader;
120 
121  //Retrieve the length of the mDNS message
122  length = netBufferGetLength(buffer) - offset;
123 
124  //Malformed mDNS message?
125  if(length < sizeof(DnsHeader))
126  return;
127 
128  //Point to the mDNS message header
129  dnsHeader = netBufferAt(buffer, offset, length);
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_RESPONDER_SUPPORT == ENABLED)
258  //Parse the resource record
259  dnsSdResponderParseAnRecord(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,
370 
371  //Sanity check
372  if(message->dnsHeader != NULL)
373  {
374  //Format mDNS message header
375  message->dnsHeader->id = 0;
376  message->dnsHeader->opcode = DNS_OPCODE_QUERY;
377  message->dnsHeader->tc = 0;
378  message->dnsHeader->rd = 0;
379  message->dnsHeader->ra = 0;
380  message->dnsHeader->z = 0;
381  message->dnsHeader->rcode = DNS_RCODE_NOERROR;
382  message->dnsHeader->qdcount = 0;
383  message->dnsHeader->ancount = 0;
384  message->dnsHeader->nscount = 0;
385  message->dnsHeader->arcount = 0;
386 
387  //Query or response mDNS message?
388  if(!queryResponse)
389  {
390  //In query messages, QR and AA bits must be set to zero
391  message->dnsHeader->qr = 0;
392  message->dnsHeader->aa = 0;
393  }
394  else
395  {
396  //In response messages, QR and AA bits must be set to one
397  message->dnsHeader->qr = 1;
398  message->dnsHeader->aa = 1;
399  }
400 
401  //Number of shared resource records
402  message->sharedRecordCount = 0;
403  //Length of the mDNS message
404  message->length = sizeof(DnsHeader);
405 
406  //Successful processing
407  error = NO_ERROR;
408  }
409  else
410  {
411  //Clean up side effects
413 
414  //Report an error
415  error = ERROR_FAILURE;
416  }
417  }
418  else
419  {
420  //Failed to allocate memory
421  error = ERROR_OUT_OF_RESOURCES;
422  }
423 
424  //Return status code
425  return error;
426 }
427 
428 
429 /**
430  * @brief release a mDNS message
431  * @param[in] message mDNS message to be released
432  **/
433 
435 {
436  //Valid mDNS message?
437  if(message->buffer != NULL)
438  {
439  //Free previously allocated memory
440  netBufferFree(message->buffer);
441 
442  //The mDNS message is no more valid
443  message->buffer = NULL;
444  message->length = 0;
445  }
446 }
447 
448 
449 /**
450  * @brief Send mDNS message
451  * @param[in] interface Underlying network interface
452  * @param[in] message mDNS message to be sent
453  * @param[in] destIpAddr Destination IP address (optional parameter)
454  * @param[in] destPort Destination port
455  * @return Error code
456  **/
457 
460 {
461  error_t error;
462  IpAddr ipAddr;
463  NetTxAncillary ancillary;
464 
465  //Convert 16-bit values to network byte order
466  message->dnsHeader->qdcount = htons(message->dnsHeader->qdcount);
467  message->dnsHeader->nscount = htons(message->dnsHeader->nscount);
468  message->dnsHeader->ancount = htons(message->dnsHeader->ancount);
469  message->dnsHeader->arcount = htons(message->dnsHeader->arcount);
470 
471  //Adjust the length of the multi-part buffer
472  error = netBufferSetLength(message->buffer, message->offset + message->length);
473 
474  //Check status code
475  if(!error)
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  //Additional options can be passed to the stack along with the packet
486  ancillary = NET_DEFAULT_TX_ANCILLARY;
487 
488  //All multicast DNS responses should be sent with an IP TTL set to 255
489  //(refer to RFC 6762, section 11)
490  ancillary.ttl = MDNS_DEFAULT_IP_TTL;
491 
492  //Send mDNS message
493  udpSendBuffer(interface, NULL, MDNS_PORT, destIpAddr, destPort,
494  message->buffer, message->offset, &ancillary);
495  }
496  else
497  {
498 #if (IPV4_SUPPORT == ENABLED)
499  //Select the relevant multicast address (224.0.0.251)
500  ipAddr.length = sizeof(Ipv4Addr);
501  ipAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR;
502 
503  //Additional options can be passed to the stack along with the packet
504  ancillary = NET_DEFAULT_TX_ANCILLARY;
505  //Set the TTL value to be used
506  ancillary.ttl = MDNS_DEFAULT_IP_TTL;
507 
508  //Send mDNS message
509  udpSendBuffer(interface, NULL, MDNS_PORT, &ipAddr, MDNS_PORT,
510  message->buffer, message->offset, &ancillary);
511 #endif
512 
513 #if (IPV6_SUPPORT == ENABLED)
514  //Select the relevant multicast address (ff02::fb)
515  ipAddr.length = sizeof(Ipv6Addr);
516  ipAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR;
517 
518  //Additional options can be passed to the stack along with the packet
519  ancillary = NET_DEFAULT_TX_ANCILLARY;
520  //Set the TTL value to be used
521  ancillary.ttl = MDNS_DEFAULT_IP_TTL;
522 
523  //Send mDNS message
524  udpSendBuffer(interface, NULL, MDNS_PORT, &ipAddr, MDNS_PORT,
525  message->buffer, message->offset, &ancillary);
526 #endif
527  }
528  }
529 
530  //Return status code
531  return error;
532 }
533 
534 
535 /**
536  * @brief Encode instance, service and domain names using the DNS name notation
537  * @param[in] instance Instance name
538  * @param[in] service Service name
539  * @param[in] domain Domain name
540  * @param[out] dest Pointer to the encoded name (optional parameter)
541  * @return Length of the encoded domain name
542  **/
543 
544 size_t mdnsEncodeName(const char_t *instance, const char_t *service,
545  const char_t *domain, uint8_t *dest)
546 {
547  size_t n;
548  size_t length;
549 
550  //Total length of the encoded name
551  length = 0;
552 
553  //Any instance name?
554  if(*instance != '\0')
555  {
556  //Encode instance name
557  n = dnsEncodeName(instance, dest);
558 
559  //Failed to encode instance name?
560  if(!n)
561  return 0;
562 
563  //Update the length of the encoded name
564  length += n;
565  }
566 
567  //Any service name?
568  if(*service != '\0')
569  {
570  //If an instance name precedes the service name, then
571  //remove the null label
572  if(length > 0)
573  {
574  length--;
575  }
576 
577  //Encode service name
578  if(dest != NULL)
579  {
580  n = dnsEncodeName(service, dest + length);
581  }
582  else
583  {
584  n = dnsEncodeName(service, NULL);
585  }
586 
587  //Failed to encode instance name?
588  if(!n)
589  return 0;
590 
591  //Update the length of the encoded name
592  length += n;
593  }
594 
595  //Skip the separator that may precede the domain name
596  if(*domain == '.')
597  {
598  domain++;
599  }
600 
601  //Any domain name to encode?
602  if(*domain != '\0')
603  {
604  //If an instance or a service name precedes the domain name, then
605  //remove the null label
606  if(length > 0)
607  {
608  length--;
609  }
610 
611  //Encode domain name
612  if(dest != NULL)
613  {
614  n = dnsEncodeName(domain, dest + length);
615  }
616  else
617  {
618  n = dnsEncodeName(domain, NULL);
619  }
620 
621  //Failed to encode instance name?
622  if(!n)
623  return 0;
624 
625  //Update the length of the encoded name
626  length += n;
627  }
628 
629  //Return the length of the encoded string
630  return length;
631 }
632 
633 
634 /**
635  * @brief Compare instance, service and domain names
636  * @param[in] message Pointer to the DNS message
637  * @param[in] length Length of the DNS message
638  * @param[in] pos Offset of the encoded name
639  * @param[in] instance Instance name
640  * @param[in] service Service name
641  * @param[in] domain Domain name
642  * @param[in] level Current level of recursion
643  * @return The function returns 0 if the domain names match, -1 if the first
644  * domain name lexicographically precedes the second name, or 1 if the
645  * second domain name lexicographically precedes the first name
646  **/
647 
648 int_t mdnsCompareName(const DnsHeader *message, size_t length, size_t pos,
649  const char_t *instance, const char_t *service, const char_t *domain, uint_t level)
650 {
651  int_t res;
652  size_t n;
653  size_t pointer;
654  uint8_t *p;
655 
656  //Check parameters
657  if(instance == NULL || service == NULL || domain == NULL)
658  return -2;
659 
660  //Recursion limit exceeded?
661  if(level >= DNS_NAME_MAX_RECURSION)
662  return -2;
663 
664  //Cast the DNS message to byte array
665  p = (uint8_t *) message;
666 
667  //Skip the separator that may precede the domain name
668  if(*domain == '.')
669  domain++;
670 
671  //Parse encoded domain name
672  while(pos < length)
673  {
674  //Retrieve the length of the current label
675  n = p[pos];
676 
677  //End marker found?
678  if(n == 0)
679  {
680  //The domain name which still has remaining data is deemed
681  //lexicographically later
682  if(*instance != '\0' || *service != '\0' || *domain != '\0')
683  return -1;
684 
685  //The domain names match each other
686  return 0;
687  }
688  //Compression tag found?
689  if(n >= DNS_COMPRESSION_TAG)
690  {
691  //Malformed DNS message?
692  if((pos + 1) >= length)
693  return -2;
694 
695  //Read the most significant byte of the pointer
696  pointer = (p[pos] & ~DNS_COMPRESSION_TAG) << 8;
697  //Read the least significant byte of the pointer
698  pointer |= p[pos + 1];
699 
700  //Compare the remaining part
702  instance, service, domain, level + 1);
703 
704  //Return comparison result
705  return res;
706  }
707  else
708  {
709  //Advance data pointer
710  pos++;
711 
712  //Malformed DNS message?
713  if((pos + n) > length)
714  return -2;
715 
716  //Compare current label
717  if(*instance != '\0')
718  {
719  //Compare instance name
720  res = osStrncasecmp((char_t *) p + pos, instance, n);
721  //Any mismatch?
722  if(res)
723  return res;
724 
725  //Advance data pointer
726  instance += n;
727 
728  //The instance name which still has remaining data is deemed
729  //lexicographically later
730  if(*instance != '\0' && *instance != '.')
731  return -1;
732 
733  //Skip the separator character, if any
734  if(*instance == '.')
735  instance++;
736  }
737  else if(*service != '\0')
738  {
739  //Compare service name
740  res = osStrncasecmp((char_t *) p + pos, service, n);
741  //Any mismatch?
742  if(res)
743  return res;
744 
745  //Advance data pointer
746  service += n;
747 
748  //The service name which still has remaining data is deemed
749  //lexicographically later
750  if(*service != '\0' && *service != '.')
751  return -1;
752 
753  //Any separator in service name?
754  if(*service == '.')
755  service++;
756  }
757  else
758  {
759  //Compare domain name
760  res = osStrncasecmp((char_t *) p + pos, domain, n);
761  //Any mismatch?
762  if(res)
763  return res;
764 
765  //Advance data pointer
766  domain += n;
767 
768  //The domain name which still has remaining data is deemed
769  //lexicographically later
770  if(*domain != '\0' && *domain != '.')
771  return -1;
772 
773  //Any separator in domain name?
774  if(*domain == '.')
775  domain++;
776  }
777 
778  //Advance data pointer
779  pos += n;
780  }
781  }
782 
783  //Malformed DNS message
784  return -2;
785 }
786 
787 
788 /**
789  * @brief Compare resource records
790  * @param[in] message1 Pointer to the first mDNS message
791  * @param[in] record1 Pointer the first resource record
792  * @param[in] message2 Pointer to the second mDNS message
793  * @param[in] record2 Pointer the second resource record
794  * @return The function returns 0 if the resource records match, -1 if the first
795  * resource record lexicographically precedes the second one, or 1 if the
796  * second resource record lexicographically precedes the first one
797  **/
798 
800  const DnsResourceRecord *record1, const MdnsMessage *message2,
801  const DnsResourceRecord *record2)
802 {
803  int_t res;
804  size_t n1;
805  size_t n2;
806  uint16_t value1;
807  uint16_t value2;
808 
809  //Convert the record class to host byte order
810  value1 = ntohs(record1->rclass);
811  value2 = ntohs(record2->rclass);
812 
813  //Discard cache-flush bit
814  value1 &= ~MDNS_RCLASS_CACHE_FLUSH;
815  value2 &= ~MDNS_RCLASS_CACHE_FLUSH;
816 
817  //The determination of lexicographically later record is performed by
818  //first comparing the record class (excluding the cache-flush bit)
819  if(value1 < value2)
820  {
821  return -1;
822  }
823  else if(value1 > value2)
824  {
825  return 1;
826  }
827  else
828  {
829  }
830 
831  //Convert the record type to host byte order
832  value1 = ntohs(record1->rtype);
833  value2 = ntohs(record2->rtype);
834 
835  //Then compare the record type
836  if(value1 < value2)
837  {
838  return -1;
839  }
840  else if(value1 > value2)
841  {
842  return 1;
843  }
844  else
845  {
846  }
847 
848  //If the rrtype and rrclass both match, then the rdata is compared
849  if(value1 == DNS_RR_TYPE_NS || value1 == DNS_RR_TYPE_SOA ||
850  value1 == DNS_RR_TYPE_CNAME || value1 == DNS_RR_TYPE_PTR)
851  {
852  //Compute the offset of the first byte of the rdata
853  n1 = record1->rdata - (uint8_t *) message1->dnsHeader;
854  n2 = record2->rdata - (uint8_t *) message2->dnsHeader;
855 
856  //The names must be uncompressed before comparison
857  res = dnsCompareEncodedName(message1->dnsHeader, message1->length,
858  n1, message2->dnsHeader, message2->length, n2, 0);
859  }
860  else
861  {
862  //Retrieve the length of the rdata fields
863  n1 = htons(record1->rdlength);
864  n2 = htons(record2->rdlength);
865 
866  //The bytes of the raw uncompressed rdata are compared in turn, interpreting
867  //the bytes as eight-bit unsigned values, until a byte is found whose value
868  //is greater than that of its counterpart (in which case, the rdata whose
869  //byte has the greater value is deemed lexicographically later) or one of the
870  //resource records runs out of rdata (in which case, the resource record which
871  //still has remaining data first is deemed lexicographically later)
872  if(n1 < n2)
873  {
874  //Raw comparison of the binary content of the rdata
875  res = osMemcmp(record1->rdata, record2->rdata, n1);
876 
877  //Check comparison result
878  if(res == 0)
879  {
880  //The first resource records runs out of rdata
881  res = -1;
882  }
883  }
884  else if(n1 > n2)
885  {
886  //Raw comparison of the binary content of the rdata
887  res = osMemcmp(record1->rdata, record2->rdata, n2);
888 
889  //Check comparison result
890  if(res == 0)
891  {
892  //The second resource records runs out of rdata
893  res = 1;
894  }
895  }
896  else
897  {
898  //Raw comparison of the binary content of the rdata
899  res = osMemcmp(record1->rdata, record2->rdata, n1);
900  }
901  }
902 
903  //Return comparison result
904  return res;
905 }
906 
907 
908 /**
909  * @brief Check for duplicate resource records
910  * @param[in] message Pointer to the mDNS message
911  * @param[in] instance Instance name
912  * @param[in] service Service name
913  * @param[in] domain Domain name
914  * @param[in] rtype Resource record type
915  * @param[in] rdata Resource record data
916  * @param[in] rdlength Length of the resource record data, in bytes
917  * @return The function returns TRUE is the specified resource record is a
918  * duplicate. Otherwise FALSE is returned
919  **/
920 
922  const char_t *instance, const char_t *service, const char_t *domain,
923  uint16_t rtype, const uint8_t *rdata, size_t rdlength)
924 {
925  uint_t i;
926  uint_t k;
927  size_t n;
928  size_t offset;
929  uint16_t rclass;
930  bool_t duplicate;
931  DnsResourceRecord *record;
932 
933  //Clear flag
934  duplicate = FALSE;
935 
936  //Point to the first question
937  offset = sizeof(DnsHeader);
938 
939  //Parse the Question Section
940  for(i = 0; i < message->dnsHeader->qdcount; i++)
941  {
942  //Parse domain name
943  offset = dnsParseName(message->dnsHeader, message->length, offset, NULL, 0);
944  //Invalid name?
945  if(!offset)
946  break;
947 
948  //Point to the next question
949  offset += sizeof(DnsQuestion);
950  //Make sure the mDNS message is valid
951  if(offset > message->length)
952  break;
953  }
954 
955  //Successful processing?
956  if(i == message->dnsHeader->qdcount)
957  {
958  //Compute the total number of resource records
959  k = message->dnsHeader->ancount + message->dnsHeader->nscount +
960  message->dnsHeader->arcount;
961 
962  //Loop through the resource records
963  for(i = 0; i < k; i++)
964  {
965  //Parse resource record name
966  n = dnsParseName(message->dnsHeader, message->length, offset, NULL, 0);
967  //Invalid name?
968  if(!n)
969  break;
970 
971  //Point to the associated resource record
972  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, n);
973  //Point to the resource data
974  n += sizeof(DnsResourceRecord);
975 
976  //Make sure the resource record is valid
977  if(n > message->length)
978  break;
979  if((n + ntohs(record->rdlength)) > message->length)
980  break;
981 
982  //Convert the record class to host byte order
983  rclass = ntohs(record->rclass);
984  //Discard cache-flush bit
986 
987  //Check the class and the type of the resource record
988  if(rclass == DNS_RR_CLASS_IN && ntohs(record->rtype) == rtype)
989  {
990  //Compare resource record name
991  if(!mdnsCompareName(message->dnsHeader, message->length,
992  offset, instance, service, domain, 0))
993  {
994  //Valid resource record data?
995  if(rdata != NULL)
996  {
997  //Compare resource record data
998  if(ntohs(record->rdlength) == rdlength &&
999  !osMemcmp(record->rdata, rdata, rdlength))
1000  {
1001  //The resource record is already present in the Answer Section
1002  duplicate = TRUE;
1003  //We are done
1004  break;
1005  }
1006  }
1007  else
1008  {
1009  //The resource record is already present in the Answer Section
1010  duplicate = TRUE;
1011  //We are done
1012  break;
1013  }
1014  }
1015  }
1016 
1017  //Point to the next resource record
1018  offset = n + ntohs(record->rdlength);
1019  }
1020  }
1021 
1022  //The function returns TRUE is the specified resource record is a duplicate
1023  return duplicate;
1024 }
1025 
1026 #endif
void mdnsResponderProcessQuery(NetInterface *interface, MdnsMessage *query)
Process mDNS query message.
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
#define htons(value)
Definition: cpu_endian.h:413
Ipv6PseudoHeader ipv6Data
Definition: ip.h:118
int bool_t
Definition: compiler_port.h:53
const Ipv6Addr MDNS_IPV6_MULTICAST_ADDR
Definition: mdns_common.c:59
uint8_t pointer
Definition: icmp.h:168
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
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:112
signed int int_t
Definition: compiler_port.h:49
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:648
IP network address.
Definition: ip.h:90
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:118
@ DNS_OPCODE_QUERY
Query.
Definition: dns_common.h:81
@ DNS_RR_TYPE_SOA
Start of a zone of authority.
Definition: dns_common.h:140
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t message[]
Definition: chap.h:154
void dnsSdResponderParseAnRecord(NetInterface *interface, const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
#define TRUE
Definition: os_port.h:50
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
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:921
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
Ipv6Addr
Definition: ipv6.h:260
#define osMemcmp(p1, p2, length)
Definition: os_port.h:153
DnsHeader * dnsHeader
Definition: mdns_common.h:84
uint16_t rclass
Definition: dns_common.h:220
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:127
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:124
#define ipv4IsLinkLocalAddr(ipAddr)
Definition: ipv4.h:171
DnsHeader
Definition: dns_common.h:199
uint16_t destPort
Definition: tcp.h:340
size_t length
Definition: ip.h:111
const uint8_t res[]
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:297
uint16_t rdlength
Definition: dns_common.h:222
#define MDNS_DEFAULT_IP_TTL
Definition: mdns_common.h:55
#define DNS_NAME_MAX_RECURSION
Definition: dns_common.h:39
IP pseudo header.
Definition: ip.h:110
IPv4 multicast filtering.
#define MDNS_PORT
Definition: mdns_common.h:53
@ DNS_RCODE_NOERROR
No error.
Definition: dns_common.h:95
IPv6 multicast filtering.
Helper functions for IPv4.
#define FALSE
Definition: os_port.h:46
#define osStrncasecmp(s1, s2, length)
Definition: os_port.h:189
error_t
Error codes.
Definition: error.h:43
error_t ipv6JoinMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
Join an IPv6 multicast group.
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
#define Ipv6PseudoHeader
Definition: ipv6.h:42
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 NetRxAncillary
Definition: net_misc.h:40
#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:1021
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
Helper functions for IPv6.
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:658
@ DNS_RR_TYPE_PTR
Domain name pointer.
Definition: dns_common.h:142
#define NetTxAncillary
Definition: net_misc.h:36
error_t mdnsCreateMessage(MdnsMessage *message, bool_t queryResponse)
Create an empty mDNS message.
Definition: mdns_common.c:357
mDNS client (Multicast DNS)
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
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:438
error_t ipv4JoinMulticastGroup(NetInterface *interface, Ipv4Addr groupAddr)
Join the specified host group.
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:948
@ DNS_RR_TYPE_NS
Authoritative name server.
Definition: dns_common.h:138
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 dnsEncodeName(const char_t *src, uint8_t *dest)
Encode a domain name using the DNS name notation.
Definition: dns_common.c:58
UdpHeader
Definition: udp.h:85
int_t mdnsCompareRecord(const MdnsMessage *message1, const DnsResourceRecord *record1, const MdnsMessage *message2, const DnsResourceRecord *record2)
Compare resource records.
Definition: mdns_common.c:799
#define ntohs(value)
Definition: cpu_endian.h:421
mDNS message
Definition: mdns_common.h:78
char char_t
Definition: compiler_port.h:48
Helper functions for DNS-SD responder.
void mdnsDeleteMessage(MdnsMessage *message)
release a mDNS message
Definition: mdns_common.c:434
uint8_t n
const UdpHeader * udpHeader
Definition: mdns_common.h:83
Helper functions for mDNS responder.
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
DnsQuestion
Definition: dns_common.h:210
#define MDNS_MESSAGE_MAX_SIZE
Definition: mdns_common.h:40
uint8_t rdata[]
Definition: dns_common.h:223
@ DNS_RR_TYPE_CNAME
Canonical name for an alias.
Definition: dns_common.h:139
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
Ipv4Addr ipAddr
Definition: ipcp.h:105
bool_t mdnsCheckSourceAddr(NetInterface *interface, const IpPseudoHeader *pseudoHeader)
Source address check.
Definition: mdns_common.c:275
#define MDNS_IPV4_MULTICAST_ADDR
Definition: mdns_common.h:65
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:224
bool_t ipv6IsOnLink(NetInterface *interface, const Ipv6Addr *ipAddr)
Check whether an IPv6 address is on-link.
Definition: ipv6_misc.c:1020
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:544
Ipv4PseudoHeader ipv4Data
Definition: ip.h:115
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void mdnsProcessResponse(NetInterface *interface, MdnsMessage *response)
Process mDNS response message.
Definition: mdns_common.c:180
error_t mdnsSendMessage(NetInterface *interface, const MdnsMessage *message, const IpAddr *destIpAddr, uint_t destPort)
Send mDNS message.
Definition: mdns_common.c:458
mDNS responder (Multicast DNS)
#define MDNS_RCLASS_CACHE_FLUSH
Definition: mdns_common.h:62
Ipv4Addr destIpAddr
Definition: ipcp.h:80