mdns_responder_misc.c
Go to the documentation of this file.
1 /**
2  * @file mdns_responder_misc.c
3  * @brief Helper functions for 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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL MDNS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "mdns/mdns_responder.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Update FSM state
48  * @param[in] context Pointer to the mDNS responder context
49  * @param[in] newState New state to switch to
50  * @param[in] delay Initial delay
51  **/
52 
54  MdnsState newState, systime_t delay)
55 {
56  NetInterface *interface;
57 
58  //Point to the underlying network interface
59  interface = context->settings.interface;
60 
61  //Set time stamp
62  context->timestamp = osGetSystemTime();
63  //Set initial delay
64  context->timeout = delay;
65  //Reset retransmission counter
66  context->retransmitCount = 0;
67  //Switch to the new state
68  context->state = newState;
69 
70  //Any registered callback?
71  if(context->settings.stateChangeEvent != NULL)
72  {
73  //Release exclusive access
75  //Invoke user callback function
76  context->settings.stateChangeEvent(context, interface, newState);
77  //Get exclusive access
79  }
80 }
81 
82 
83 /**
84  * @brief Programmatically change the host name
85  * @param[in] context Pointer to the mDNS responder context
86  **/
87 
89 {
90  size_t i;
91  size_t m;
92  size_t n;
93  uint32_t index;
94  char_t s[16];
95 
96  //Retrieve the length of the string
97  n = osStrlen(context->hostname);
98 
99  //Parse the string backwards
100  for(i = n; i > 0; i--)
101  {
102  //Check whether the current character is a digit
103  if(!osIsdigit(context->hostname[i - 1]))
104  break;
105  }
106 
107  //Any number following the host name?
108  if(context->hostname[i] != '\0')
109  {
110  //Retrieve the number at the end of the name
111  index = atoi(context->hostname + i);
112  //Increment the value
113  index++;
114 
115  //Strip the digits
116  context->hostname[i] = '\0';
117  }
118  else
119  {
120  //Append the digit "2" to the name
121  index = 2;
122  }
123 
124  //Convert the number to a string of characters
125  m = osSprintf(s, "%" PRIu32, index);
126 
127  //Sanity check
128  if((i + m) <= NET_MAX_HOSTNAME_LEN)
129  {
130  //Add padding if necessary
131  while((i + m) < n)
132  {
133  context->hostname[i++] = '0';
134  }
135 
136  //Properly terminate the string
137  context->hostname[i] = '\0';
138  //Programmatically change the host name
139  osStrcat(context->hostname, s);
140  }
141 }
142 
143 
144 /**
145  * @brief Send probe packet
146  * @param[in] context Pointer to the mDNS responder context
147  * @return Error code
148  **/
149 
151 {
152  error_t error;
153  NetInterface *interface;
154  DnsQuestion *dnsQuestion;
156 
157  //Point to the underlying network interface
158  interface = context->settings.interface;
159 
160  //Create an empty mDNS query message
161  error = mdnsCreateMessage(&message, FALSE);
162  //Any error to report?
163  if(error)
164  return error;
165 
166  //Start of exception handling block
167  do
168  {
169  //Encode the host name using the DNS name notation
170  message.length += mdnsEncodeName(context->hostname, "",
171  ".local", message.dnsHeader->questions);
172 
173  //Point to the corresponding question structure
174  dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length);
175 
176  //The probes should be sent as QU questions with the unicast-response
177  //bit set, to allow a defending host to respond immediately via unicast
178  dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY);
179  dnsQuestion->qclass = HTONS(MDNS_QCLASS_QU | DNS_RR_CLASS_IN);
180 
181  //Update the length of the mDNS query message
182  message.length += sizeof(DnsQuestion);
183 
184  //Generate A resource records
187  //Any error to report?
188  if(error)
189  break;
190 
191  //Generate AAAA resource records
194  //Any error to report?
195  if(error)
196  break;
197 
198  //Number of questions in the Question Section
199  message.dnsHeader->qdcount = 1;
200  //Number of resource records in the Authority Section
201  message.dnsHeader->nscount = message.dnsHeader->ancount;
202  //Number of resource records in the Answer Section
203  message.dnsHeader->ancount = 0;
204 
205  //Send mDNS message
206  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
207 
208  //End of exception handling block
209  } while(0);
210 
211  //Free previously allocated memory
213 
214  //Return status code
215  return error;
216 }
217 
218 
219 /**
220  * @brief Send announcement packet
221  * @param[in] context Pointer to the mDNS responder context
222  * @return Error code
223  **/
224 
226 {
227  error_t error;
228  NetInterface *interface;
230 
231  //Point to the underlying network interface
232  interface = context->settings.interface;
233 
234  //Create an empty mDNS response message
235  error = mdnsCreateMessage(&message, TRUE);
236  //Any error to report?
237  if(error)
238  return error;
239 
240  //Start of exception handling block
241  do
242  {
243  //Generate A resource records
246  //Any error to report?
247  if(error)
248  break;
249 
250  //Generate reverse address mapping PTR resource records (IPv4)
253  //Any error to report?
254  if(error)
255  break;
256 
257  //Generate AAAA resource records
260  //Any error to report?
261  if(error)
262  break;
263 
264  //Generate reverse address mapping PTR resource records (IPv6)
267  //Any error to report?
268  if(error)
269  break;
270 
271  //Send mDNS message
272  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
273 
274  //End of exception handling block
275  } while(0);
276 
277  //Free previously allocated memory
279 
280  //Return status code
281  return error;
282 }
283 
284 
285 /**
286  * @brief Send goodbye packet
287  * @param[in] context Pointer to the mDNS responder context
288  * @return Error code
289  **/
290 
292 {
293  error_t error;
294  NetInterface *interface;
296 
297  //Point to the underlying network interface
298  interface = context->settings.interface;
299 
300  //Create an empty mDNS response message
301  error = mdnsCreateMessage(&message, TRUE);
302  //Any error to report?
303  if(error)
304  return error;
305 
306  //Start of exception handling block
307  do
308  {
309  //Generate A resource records
310  error = mdnsResponderGenerateIpv4AddrRecords(context, &message, TRUE, 0);
311  //Any error to report?
312  if(error)
313  break;
314 
315  //Generate reverse address mapping PTR resource records (IPv4)
316  error = mdnsResponderGenerateIpv4PtrRecords(context, &message, TRUE, 0);
317  //Any error to report?
318  if(error)
319  break;
320 
321  //Generate AAAA resource records
322  error = mdnsResponderGenerateIpv6AddrRecords(context, &message, TRUE, 0);
323  //Any error to report?
324  if(error)
325  break;
326 
327  //Generate reverse address mapping PTR resource records (IPv6)
328  error = mdnsResponderGenerateIpv6PtrRecords(context, &message, TRUE, 0);
329  //Any error to report?
330  if(error)
331  break;
332 
333  //Send mDNS message
334  error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT);
335 
336  //End of exception handling block
337  } while(0);
338 
339  //Free previously allocated memory
341 
342  //Return status code
343  return error;
344 }
345 
346 
347 /**
348  * @brief Process mDNS query message
349  * @param[in] interface Underlying network interface
350  * @param[in] query Incoming mDNS query message
351  **/
352 
354 {
355  error_t error;
356  uint_t i;
357  size_t n;
358  size_t offset;
359  uint16_t destPort;
361  DnsQuestion *question;
362  DnsResourceRecord *record;
363  MdnsResponderContext *context;
364  MdnsMessage *response;
365  MdnsMessage legacyUnicastResponse;
366 
367  //Point to the mDNS responder context
368  context = interface->mdnsResponderContext;
369  //Make sure the mDNS responder has been properly instantiated
370  if(context == NULL)
371  return;
372 
373 #if (IPV4_SUPPORT == ENABLED)
374  //IPv4 query received?
375  if(query->pseudoHeader->length == sizeof(Ipv4PseudoHeader))
376  {
377  //There are two kinds of Multicast DNS queries
378  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
379  {
380  //If the source UDP port in a received Multicast DNS query is not
381  //port 5353, this indicates that the querier originating the query
382  //is a simple resolver
383  response = &legacyUnicastResponse;
384 
385  //The mDNS responder must send a UDP response directly back to the
386  //querier, via unicast, to the query packet's source IP address and
387  //port
388  destIpAddr.length = sizeof(Ipv4Addr);
389  destIpAddr.ipv4Addr = query->pseudoHeader->ipv4Data.srcAddr;
390  }
391  else
392  {
393  //The query is made by a fully compliant Multicast DNS querier
394  response = &context->ipv4Response;
395 
396  //The destination address of the response must be the mDNS IPv4
397  //multicast address
398  destIpAddr.length = sizeof(Ipv4Addr);
400  }
401  }
402  else
403 #endif
404 #if (IPV6_SUPPORT == ENABLED)
405  //IPv6 query received?
406  if(query->pseudoHeader->length == sizeof(Ipv6PseudoHeader))
407  {
408  //There are two kinds of Multicast DNS queries
409  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
410  {
411  //If the source UDP port in a received Multicast DNS query is not
412  //port 5353, this indicates that the querier originating the query
413  //is a simple resolver
414  response = &legacyUnicastResponse;
415 
416  //The mDNS responder must send a UDP response directly back to the
417  //querier, via unicast, to the query packet's source IP address and
418  //port
419  destIpAddr.length = sizeof(Ipv6Addr);
420  destIpAddr.ipv6Addr = query->pseudoHeader->ipv6Data.srcAddr;
421  }
422  else
423  {
424  //The query is made by a fully compliant Multicast DNS querier
425  response = &context->ipv6Response;
426 
427  //The destination address of the response must be the mDNS IPv6
428  //multicast address
429  destIpAddr.length = sizeof(Ipv6Addr);
431  }
432  }
433  else
434 #endif
435  //Invalid query received?
436  {
437  //Discard the mDNS query message
438  return;
439  }
440 
441  //Check whether the querier originating the query is a simple resolver
442  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
443  {
444  //Silently discard malformed one-shot mDNS queries
445  if(ntohs(query->dnsHeader->qdcount) != 1 ||
446  ntohs(query->dnsHeader->ancount) != 0 ||
447  ntohs(query->dnsHeader->nscount) != 0)
448  {
449  return;
450  }
451 
452  //Initialize the legacy unicast response
453  osMemset(response, 0, sizeof(MdnsMessage));
454  }
455 
456  //When possible, a responder should, for the sake of network efficiency,
457  //aggregate as many responses as possible into a single mDNS response message
458  if(response->buffer == NULL)
459  {
460  //Create an empty mDNS response message
461  error = mdnsCreateMessage(response, TRUE);
462  //Any error to report?
463  if(error)
464  return;
465  }
466 
467  //Take the identifier from the query message
468  response->dnsHeader->id = query->dnsHeader->id;
469 
470  //Point to the first question
471  offset = sizeof(DnsHeader);
472 
473  //Start of exception handling block
474  do
475  {
476  //Parse the Question Section
477  for(i = 0; i < ntohs(query->dnsHeader->qdcount); i++)
478  {
479  //Parse resource record name
480  n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
481  //Invalid name?
482  if(!n)
483  break;
484 
485  //Malformed mDNS message?
486  if((n + sizeof(DnsQuestion)) > query->length)
487  break;
488 
489  //Point to the corresponding entry
490  question = DNS_GET_QUESTION(query->dnsHeader, n);
491 
492  //Parse question
493  error = mdnsResponderParseQuestion(interface, query, offset, question,
494  response);
495  //Any error to report?
496  if(error)
497  break;
498 
499 #if (DNS_SD_RESPONDER_SUPPORT == ENABLED)
500  //Parse question
501  error = dnsSdResponderParseQuestion(interface, query, offset,
502  question, response);
503  //Any error to report?
504  if(error)
505  break;
506 #endif
507  //Point to the next question
508  offset = n + sizeof(DnsQuestion);
509  }
510 
511  //Any error while parsing the Question Section?
512  if(i != ntohs(query->dnsHeader->qdcount))
513  break;
514 
515  //Parse the Known-Answer Section
516  for(i = 0; i < ntohs(query->dnsHeader->ancount); i++)
517  {
518  //Parse resource record name
519  n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
520  //Invalid name?
521  if(!n)
522  break;
523 
524  //Point to the associated resource record
525  record = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
526  //Point to the resource data
527  n += sizeof(DnsResourceRecord);
528 
529  //Make sure the resource record is valid
530  if(n > query->length)
531  break;
532  if((n + ntohs(record->rdlength)) > query->length)
533  break;
534 
535  //Parse resource record
536  mdnsResponderParseKnownAnRecord(interface, query, offset, record,
537  response);
538 
539  //Point to the next resource record
540  offset = n + ntohs(record->rdlength);
541  }
542 
543  //Any error while parsing the Answer Section?
544  if(i != ntohs(query->dnsHeader->ancount))
545  break;
546 
547  //When a host that is probing for a record sees another host issue a query
548  //for the same record, it consults the Authority Section of that query.
549  //If it finds any resource record there which answers the query, then it
550  //compares the data of that resource record with its own tentative data
551  mdnsResponderParseNsRecords(context, query, offset);
552 
553 #if (DNS_SD_RESPONDER_SUPPORT == ENABLED)
554  //Check for service instance name conflict
555  dnsSdResponderParseNsRecords(interface, query, offset);
556 #endif
557 
558  //End of exception handling block
559  } while(0);
560 
561  //Should a mDNS message be send in response to the query?
562  if(response->dnsHeader->ancount > 0)
563  {
564  //Legacy unicast response?
565  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
566  {
567 #if (DNS_SD_RESPONDER_SUPPORT == ENABLED)
568  //Generate additional records (DNS-SD)
569  dnsSdResponderGenerateAdditionalRecords(interface, response, TRUE);
570 #endif
571  //Generate additional records (mDNS)
572  mdnsResponderGenerateAdditionalRecords(context, response, TRUE);
573 
574  //Destination port
575  destPort = ntohs(query->udpHeader->srcPort);
576 
577  //Send mDNS response message
578  mdnsSendMessage(interface, response, &destIpAddr, destPort);
579  //Free previously allocated memory
580  mdnsDeleteMessage(response);
581  }
582  else
583  {
584  //Check whether the answer should be delayed
585  if(query->dnsHeader->tc)
586  {
587  //In the case where the query has the TC (truncated) bit set,
588  //indicating that subsequent Known-Answer packets will follow,
589  //responders should delay their responses by a random amount of
590  //time selected with uniform random distribution in the range
591  //400-500 ms
592  response->timeout = netGenerateRandRange(400, 500);
593 
594  //Save current time
595  response->timestamp = osGetSystemTime();
596  }
597  else if(response->sharedRecordCount > 0)
598  {
599  //In any case where there may be multiple responses, such as queries
600  //where the answer is a member of a shared resource record set, each
601  //responder should delay its response by a random amount of time
602  //selected with uniform random distribution in the range 20-120 ms
603  response->timeout = netGenerateRandRange(20, 120);
604 
605  //Save current time
606  response->timestamp = osGetSystemTime();
607  }
608  else
609  {
610 #if (DNS_SD_RESPONDER_SUPPORT == ENABLED)
611  //Generate additional records (refer to RFC 6763, section 12)
612  dnsSdResponderGenerateAdditionalRecords(interface, response, FALSE);
613 #endif
614  //Generate additional records (mDNS)
615  mdnsResponderGenerateAdditionalRecords(context, response, FALSE);
616 
617  //Send mDNS response message
618  mdnsSendMessage(interface, response, &destIpAddr, MDNS_PORT);
619  //Free previously allocated memory
620  mdnsDeleteMessage(response);
621  }
622  }
623  }
624  else
625  {
626  //Free mDNS response message
627  mdnsDeleteMessage(response);
628  }
629 }
630 
631 
632 /**
633  * @brief Parse a question
634  * @param[in] interface Underlying network interface
635  * @param[in] query Incoming mDNS query message
636  * @param[in] offset Offset to first byte of the question
637  * @param[in] question Pointer to the question
638  * @param[in,out] response mDNS response message
639  * @return Error code
640  **/
641 
643  const MdnsMessage *query, size_t offset, const DnsQuestion *question,
644  MdnsMessage *response)
645 {
646  error_t error;
647  uint_t i;
648  uint16_t qclass;
649  uint16_t qtype;
650  uint32_t ttl;
651  bool_t cacheFlush;
652  MdnsResponderContext *context;
653 
654  //Point to the mDNS responder context
655  context = interface->mdnsResponderContext;
656 
657  //Check the state of the mDNS responder
658  if(context->state != MDNS_STATE_ANNOUNCING &&
659  context->state != MDNS_STATE_IDLE)
660  {
661  //Do not respond to mDNS queries during probing
662  return NO_ERROR;
663  }
664 
665  //Convert the query class to host byte order
666  qclass = ntohs(question->qclass);
667  //Discard QU flag
669 
670  //Convert the query type to host byte order
671  qtype = ntohs(question->qtype);
672 
673  //Get the TTL resource record
674  ttl = context->settings.ttl;
675 
676  //Check whether the querier originating the query is a simple resolver
677  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
678  {
679  //The resource record TTL given in a legacy unicast response should
680  //not be greater than ten seconds, even if the true TTL of the mDNS
681  //resource record is higher
683 
684  //The cache-flush bit must not be set in legacy unicast responses
685  cacheFlush = FALSE;
686  }
687  else
688  {
689  //The cache-bit should be set for unique resource records
690  cacheFlush = TRUE;
691  }
692 
693  //Check the class of the query
695  {
696  //Compare domain name
697  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
698  context->hostname, "", ".local", 0))
699  {
700  //Check whether the querier originating the query is a simple resolver
701  if(ntohs(query->udpHeader->srcPort) != MDNS_PORT)
702  {
703  DnsQuestion *dnsQuestion;
704 
705  //This unicast response must be a conventional unicast response as
706  //would be generated by a conventional unicast DNS server. It must
707  //repeat the question given in the query message (refer to RFC 6762,
708  //section 6.7)
709  response->length += mdnsEncodeName(context->hostname, "", ".local",
710  response->dnsHeader->questions);
711 
712  //Point to the corresponding question structure
713  dnsQuestion = DNS_GET_QUESTION(response->dnsHeader, response->length);
714 
715  //Fill in question structure
716  dnsQuestion->qtype = htons(qtype);
717  dnsQuestion->qclass = htons(qclass);
718 
719  //Update the length of the mDNS response message
720  response->length += sizeof(DnsQuestion);
721  //Number of questions in the Question Section
722  response->dnsHeader->qdcount++;
723  }
724 
725 #if (IPV4_SUPPORT == ENABLED)
726  //A query?
727  if(qtype == DNS_RR_TYPE_A)
728  {
729  //Generate A resource records
730  error = mdnsResponderGenerateIpv4AddrRecords(context, response,
731  cacheFlush, ttl);
732  //Any error to report?
733  if(error)
734  return error;
735  }
736  else
737 #endif
738 #if (IPV6_SUPPORT == ENABLED)
739  //AAAA query?
740  if(qtype == DNS_RR_TYPE_AAAA)
741  {
742  //Generate AAAA resource records
743  error = mdnsResponderGenerateIpv6AddrRecords(context, response,
744  cacheFlush, ttl);
745  //Any error to report?
746  if(error)
747  return error;
748  }
749  else
750 #endif
751  //ANY query?
752  if(qtype == DNS_RR_TYPE_ANY)
753  {
754  //Generate A resource records
755  error = mdnsResponderGenerateIpv4AddrRecords(context, response,
756  cacheFlush, ttl);
757  //Any error to report?
758  if(error)
759  return error;
760 
761  //Generate AAAA resource records
762  error = mdnsResponderGenerateIpv6AddrRecords(context, response,
763  cacheFlush, ttl);
764  //Any error to report?
765  if(error)
766  return error;
767 
768  //Generate NSEC resource record
769  error = mdnsResponderFormatNsecRecord(context, response,
770  cacheFlush, ttl);
771  //Any error to report?
772  if(error)
773  return error;
774  }
775  else
776  {
777  //Generate NSEC resource record
778  error = mdnsResponderFormatNsecRecord(context, response,
779  cacheFlush, ttl);
780  //Any error to report?
781  if(error)
782  return error;
783  }
784  }
785 
786  //PTR query?
787  if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
788  {
789 #if (IPV4_SUPPORT == ENABLED)
790  //Loop through the list of IPv4 addresses assigned to the interface
791  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
792  {
793  //Valid entry?
794  if(context->ipv4AddrList[i].valid)
795  {
796  //Reverse DNS lookup?
797  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
798  context->ipv4AddrList[i].reverseName, "in-addr", ".arpa", 0))
799  {
800  //Format reverse address mapping PTR resource record (IPv4)
801  error = mdnsResponderFormatIpv4PtrRecord(context, response,
802  context->ipv4AddrList[i].reverseName, cacheFlush, ttl);
803  //Any error to report?
804  if(error)
805  return error;
806  }
807  }
808  }
809 #endif
810 
811 #if (IPV6_SUPPORT == ENABLED)
812  //Loop through the list of IPv6 addresses assigned to the interface
813  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
814  {
815  //Valid entry?
816  if(context->ipv6AddrList[i].valid)
817  {
818  //Reverse DNS lookup?
819  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
820  context->ipv6AddrList[i].reverseName, "ip6", ".arpa", 0))
821  {
822  //Format reverse address mapping PTR resource record (IPv6)
823  error = mdnsResponderFormatIpv6PtrRecord(context, response,
824  context->ipv6AddrList[i].reverseName, cacheFlush, ttl);
825  //Any error to report?
826  if(error)
827  return error;
828  }
829  }
830  }
831 #endif
832  }
833  }
834 
835  //Successful processing
836  return NO_ERROR;
837 }
838 
839 
840 /**
841  * @brief Parse a resource record from the Known-Answer Section
842  * @param[in] interface Underlying network interface
843  * @param[in] query Incoming mDNS query message
844  * @param[in] queryOffset Offset to first byte of the resource record
845  * @param[in] queryRecord Pointer to the resource record
846  * @param[in,out] response mDNS response message
847  **/
848 
850  const MdnsMessage *query, size_t queryOffset,
851  const DnsResourceRecord *queryRecord, MdnsMessage *response)
852 {
853  size_t i;
854  size_t n;
855  size_t responseOffset;
856  DnsResourceRecord *responseRecord;
857 
858  //mDNS responses must not contain any questions in the Question Section
859  if(response->dnsHeader->qdcount == 0)
860  {
861  //Point to the first resource record
862  responseOffset = sizeof(DnsHeader);
863 
864  //Parse the Answer Section of the response
865  for(i = 0; i < response->dnsHeader->ancount; i++)
866  {
867  //Parse resource record name
868  n = dnsParseName(response->dnsHeader, response->length, responseOffset,
869  NULL, 0);
870  //Invalid name?
871  if(!n)
872  break;
873 
874  //Point to the associated resource record
875  responseRecord = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
876  //Point to the resource data
877  n += sizeof(DnsResourceRecord);
878 
879  //Make sure the resource record is valid
880  if(n > response->length)
881  break;
882 
883  //Point to the end of the resource record
884  n += ntohs(responseRecord->rdlength);
885 
886  //Make sure the resource record is valid
887  if(n > response->length)
888  break;
889 
890  //Compare resource record names
891  if(!dnsCompareEncodedName(query->dnsHeader, query->length, queryOffset,
892  response->dnsHeader, response->length, responseOffset, 0))
893  {
894  //Compare the contents of the resource records
895  if(!mdnsCompareRecord(query, queryRecord, response, responseRecord))
896  {
897  //A mDNS responder must not answer a mDNS query if the answer
898  //it would give is already included in the Answer Section with
899  //an RR TTL at least half the correct value
900  if(ntohl(queryRecord->ttl) >= (ntohl(responseRecord->ttl) / 2))
901  {
902  //Perform Known-Answer Suppression
903  osMemmove((uint8_t *) response->dnsHeader + responseOffset,
904  (uint8_t *) response->dnsHeader + n, response->length - n);
905 
906  //Update the length of the mDNS response message
907  response->length -= (n - responseOffset);
908  //Update the number of resource records in the Answer Section
909  response->dnsHeader->ancount--;
910 
911  //Update the number of shared resource records
912  if(ntohs(queryRecord->rclass) == DNS_RR_TYPE_PTR &&
913  response->sharedRecordCount > 0)
914  {
915  response->sharedRecordCount--;
916  }
917 
918  //Keep at the same position
919  n = responseOffset;
920  i--;
921  }
922  }
923  }
924 
925  //Point to the next resource record
926  responseOffset = n;
927  }
928  }
929 }
930 
931 
932 /**
933  * @brief Parse a resource record from the Answer Section
934  * @param[in] interface Underlying network interface
935  * @param[in] response Incoming mDNS response message
936  * @param[in] offset Offset to first byte of the resource record to be checked
937  * @param[in] record Pointer to the resource record
938  **/
939 
941  const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
942 {
943  uint_t i;
944  size_t n;
945  size_t offset2;
946  bool_t conflict;
947  uint16_t rclass;
948  DnsResourceRecord *record2;
949  MdnsResponderContext *context;
950  MdnsMessage *response2;
951 
952  //Point to the mDNS responder context
953  context = interface->mdnsResponderContext;
954  //Make sure the mDNS responder has been properly instantiated
955  if(context == NULL)
956  return;
957 
958 #if (IPV4_SUPPORT == ENABLED)
959  //IPv4 message received?
960  if(response->pseudoHeader->length == sizeof(Ipv4PseudoHeader))
961  {
962  //Point to the pending mDNS response
963  response2 = &context->ipv4Response;
964  }
965  else
966 #endif
967 #if (IPV6_SUPPORT == ENABLED)
968  //IPv6 message received?
969  if(response->pseudoHeader->length == sizeof(Ipv6PseudoHeader))
970  {
971  //Point to the pending mDNS response
972  response2 = &context->ipv6Response;
973  }
974  else
975 #endif
976  //Invalid message received?
977  {
978  //Discard the mDNS message
979  return;
980  }
981 
982  //Any pending mDNS response?
983  if(response2->buffer != NULL)
984  {
985  //Point to the first resource record
986  offset2 = sizeof(DnsHeader);
987 
988  //Parse the Answer Section of the response
989  for(i = 0; i < response2->dnsHeader->ancount; i++)
990  {
991  //Parse resource record name
992  n = dnsParseName(response2->dnsHeader, response2->length, offset2,
993  NULL, 0);
994  //Invalid name?
995  if(!n)
996  break;
997 
998  //Point to the associated resource record
999  record2 = DNS_GET_RESOURCE_RECORD(response2->dnsHeader, n);
1000  //Point to the resource data
1001  n += sizeof(DnsResourceRecord);
1002 
1003  //Make sure the resource record is valid
1004  if(n > response2->length)
1005  break;
1006 
1007  //Point to the end of the resource record
1008  n += ntohs(record2->rdlength);
1009 
1010  //Make sure the resource record is valid
1011  if(n > response2->length)
1012  break;
1013 
1014  //Compare resource record names
1015  if(!dnsCompareEncodedName(response->dnsHeader, response->length, offset,
1016  response2->dnsHeader, response2->length, offset2, 0))
1017  {
1018  //Compare the contents of the resource records
1019  if(!mdnsCompareRecord(response, record, response2, record2))
1020  {
1021  //If a host is planning to send an answer, and it sees another
1022  //host on the network send a response message containing the same
1023  //answer record, and the TTL in that record is not less than the
1024  //TTL this host would have given, then this host should treat its
1025  //own answer as having been sent, and not also send an identical
1026  //answer itself
1027  if(ntohl(record->ttl) >= ntohl(record2->ttl))
1028  {
1029  //Perform Duplicate Answer Suppression
1030  osMemmove((uint8_t *) response2->dnsHeader + offset2,
1031  (uint8_t *) response2->dnsHeader + n, response2->length - n);
1032 
1033  //Update the length of the mDNS response2 message
1034  response2->length -= (n - offset2);
1035  //Update the number of resource records in the Answer Section
1036  response2->dnsHeader->ancount--;
1037 
1038  //Update the number of shared resource records
1039  if(ntohs(record->rclass) == DNS_RR_TYPE_PTR &&
1040  response2->sharedRecordCount > 0)
1041  {
1042  response2->sharedRecordCount--;
1043  }
1044 
1045  //Keep at the same position
1046  n = offset2;
1047  i--;
1048  }
1049  }
1050  }
1051 
1052  //Point to the next resource record
1053  offset2 = n;
1054  }
1055 
1056  //When multiple responders on the network have the same data, there is no
1057  //need for all of them to respond
1058  if(response2->dnsHeader->ancount == 0)
1059  {
1060  mdnsDeleteMessage(response2);
1061  }
1062  }
1063 
1064  //Check for conflicts
1065  if(!mdnsCompareName(response->dnsHeader, response->length, offset,
1066  context->hostname, "", ".local", 0))
1067  {
1068  //Convert the class to host byte order
1069  rclass = ntohs(record->rclass);
1070  //Discard Cache Flush flag
1072 
1073  //Check the class of the resource record
1074  if(rclass == DNS_RR_CLASS_IN)
1075  {
1076 #if (IPV4_SUPPORT == ENABLED)
1077  //A resource record found?
1078  if(ntohs(record->rtype) == DNS_RR_TYPE_A)
1079  {
1080  //A conflict occurs when a mDNS responder has a unique record for
1081  //which it is currently authoritative, and it receives a mDNS
1082  //response message containing a record with the same name, rrtype
1083  //and rrclass, but inconsistent rdata
1084  conflict = TRUE;
1085 
1086  //Verify the length of the data field
1087  if(ntohs(record->rdlength) == sizeof(Ipv4Addr))
1088  {
1089  //Loop through the list of IPv4 addresses assigned to the interface
1090  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
1091  {
1092  //Valid IPv4 address?
1093  if(context->ipv4AddrList[i].valid)
1094  {
1095  //Check whether the rdata field is consistent
1096  if(ipv4CompAddr(context->ipv4AddrList[i].record.rdata,
1097  record->rdata))
1098  {
1099  conflict = FALSE;
1100  }
1101  }
1102  }
1103  }
1104 
1105  //Check whether the host name is already in use by some other host
1106  if(conflict)
1107  {
1108  context->conflict = TRUE;
1109  }
1110  }
1111 #endif
1112 #if (IPV6_SUPPORT == ENABLED)
1113  //AAAA resource record found?
1114  if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
1115  {
1116  //A conflict occurs when a mDNS responder has a unique record for
1117  //which it is currently authoritative, and it receives a mDNS
1118  //response message containing a record with the same name, rrtype
1119  //and rrclass, but inconsistent rdata
1120  conflict = TRUE;
1121 
1122  //Verify the length of the data field
1123  if(ntohs(record->rdlength) == sizeof(Ipv6Addr))
1124  {
1125  //Loop through the list of IPv6 addresses assigned to the interface
1126  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
1127  {
1128  //Valid IPv6 address?
1129  if(context->ipv6AddrList[i].valid)
1130  {
1131  //Check whether the rdata field is consistent
1132  if(ipv6CompAddr(context->ipv6AddrList[i].record.rdata,
1133  record->rdata))
1134  {
1135  conflict = FALSE;
1136  }
1137  }
1138  }
1139  }
1140 
1141  //Check whether the host name is already in use by some other host
1142  if(conflict)
1143  {
1144  context->conflict = TRUE;
1145  }
1146  }
1147 #endif
1148  }
1149  }
1150 }
1151 
1152 
1153 /**
1154  * @brief Parse the Authority Section
1155  * @param[in] context Pointer to the mDNS responder context
1156  * @param[in] query Incoming mDNS query message
1157  * @param[in] offset Offset to first byte of the Authority Section
1158  **/
1159 
1161  const MdnsMessage *query, size_t offset)
1162 {
1163  int_t res;
1164  DnsResourceRecord *record1;
1165  DnsResourceRecord *record2;
1166 
1167  //Get the first tiebreaker record in lexicographical order
1168  record1 = mdnsResponderGetNextTiebreakerRecord(context, query, offset, NULL);
1169  //Get the first host record in lexicographical order
1170  record2 = mdnsResponderGetNextHostRecord(context, NULL);
1171 
1172  //When a host is probing for a set of records with the same name, or a
1173  //message is received containing multiple tiebreaker records answering
1174  //a given probe question in the Question Section, the host's records
1175  //and the tiebreaker records from the message are each sorted into order
1176  while(1)
1177  {
1178  //The records are compared pairwise
1179  if(record1 == NULL && record2 == NULL)
1180  {
1181  //If both lists run out of records at the same time without any
1182  //difference being found, then this indicates that two devices are
1183  //advertising identical sets of records, as is sometimes done for
1184  //fault tolerance, and there is, in fact, no conflict
1185  break;
1186  }
1187  else if(record1 != NULL && record2 == NULL)
1188  {
1189  //If either list of records runs out of records before any difference
1190  //is found, then the list with records remaining is deemed to have won
1191  //the tiebreak
1192  context->tieBreakLost = TRUE;
1193  break;
1194  }
1195  else if(record1 == NULL && record2 != NULL)
1196  {
1197  //The host has won the tiebreak
1198  break;
1199  }
1200  else
1201  {
1202  //The two records are compared and the lexicographically later data
1203  //wins
1204  res = mdnsCompareRecord(query, record1, NULL, record2);
1205 
1206  //Check comparison result
1207  if(res > 0)
1208  {
1209  //If the host finds that its own data is lexicographically earlier,
1210  //then it defers to the winning host by waiting one second, and
1211  //then begins probing for this record again
1212  context->tieBreakLost = TRUE;
1213  break;
1214  }
1215  else if(res < 0)
1216  {
1217  //If the host finds that its own data is lexicographically later,
1218  //it simply ignores the other host's probe
1219  break;
1220  }
1221  else
1222  {
1223  //When comparing the records, if the first records match perfectly,
1224  //then the second records are compared, and so on
1225  }
1226  }
1227 
1228  //Get the next tiebreaker record in lexicographical order
1229  record1 = mdnsResponderGetNextTiebreakerRecord(context, query, offset,
1230  record1);
1231 
1232  //Get the next host record in lexicographical order
1233  record2 = mdnsResponderGetNextHostRecord(context, record2);
1234  }
1235 }
1236 
1237 
1238 /**
1239  * @brief Generate additional records
1240  * @param[in] context Pointer to the mDNS responder context
1241  * @param[in,out] response mDNS response message
1242  * @param[in] legacyUnicast This flag is set for legacy unicast responses
1243  **/
1244 
1246  MdnsMessage *response, bool_t legacyUnicast)
1247 {
1248 #if (MDNS_ADDITIONAL_RECORDS_SUPPORT == ENABLED)
1249  uint_t i;
1250  uint_t k;
1251  size_t n;
1252  size_t offset;
1253  uint_t ancount;
1254  uint16_t rclass;
1255  uint32_t ttl;
1256  bool_t cacheFlush;
1257  DnsResourceRecord *record;
1258 
1259  //Get the TTL resource record
1260  ttl = context->settings.ttl;
1261 
1262  //Check whether the querier originating the query is a simple resolver
1263  if(legacyUnicast)
1264  {
1265  //The resource record TTL given in a legacy unicast response should
1266  //not be greater than ten seconds, even if the true TTL of the mDNS
1267  //resource record is higher
1269 
1270  //The cache-flush bit must not be set in legacy unicast responses
1271  cacheFlush = FALSE;
1272  }
1273  else
1274  {
1275  //The cache-bit should be set for unique resource records
1276  cacheFlush = TRUE;
1277  }
1278 
1279  //Point to the first question
1280  offset = sizeof(DnsHeader);
1281 
1282  //Skip the question section
1283  for(i = 0; i < response->dnsHeader->qdcount; i++)
1284  {
1285  //Parse domain name
1286  offset = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
1287  //Invalid name?
1288  if(!offset)
1289  break;
1290 
1291  //Point to the next question
1292  offset += sizeof(DnsQuestion);
1293  //Make sure the mDNS message is valid
1294  if(offset > response->length)
1295  break;
1296  }
1297 
1298  //Save the number of resource records in the Answer Section
1299  ancount = response->dnsHeader->ancount;
1300 
1301  //Compute the total number of resource records
1302  k = response->dnsHeader->ancount + response->dnsHeader->nscount +
1303  response->dnsHeader->arcount;
1304 
1305  //Loop through the resource records
1306  for(i = 0; i < k; i++)
1307  {
1308  //Parse resource record name
1309  n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0);
1310  //Invalid name?
1311  if(!n)
1312  break;
1313 
1314  //Point to the associated resource record
1315  record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
1316  //Point to the resource data
1317  n += sizeof(DnsResourceRecord);
1318 
1319  //Make sure the resource record is valid
1320  if(n > response->length)
1321  break;
1322  if((n + ntohs(record->rdlength)) > response->length)
1323  break;
1324 
1325  //Convert the record class to host byte order
1326  rclass = ntohs(record->rclass);
1327  //Discard the cache-flush bit
1329 
1330  //Check the class of the resource record
1331  if(rclass == DNS_RR_CLASS_IN)
1332  {
1333  //A record?
1334  if(ntohs(record->rtype) == DNS_RR_TYPE_A)
1335  {
1336  //When a mDNS responder places an IPv4 address record into a
1337  //response message, it should also place any IPv6 address records
1338  //with the same name into the Additional Section
1339  if(context->ipv6AddrCount > 0)
1340  {
1341  //Generate AAAA resource records
1342  mdnsResponderGenerateIpv6AddrRecords(context, response,
1343  cacheFlush, ttl);
1344  }
1345  else
1346  {
1347  //In the event that a device has only IPv4 addresses but no IPv6
1348  //addresses, then the appropriate NSEC record should be placed
1349  //into the Additional Section
1350  mdnsResponderFormatNsecRecord(context, response, cacheFlush,
1351  ttl);
1352  }
1353  }
1354  //AAAA record?
1355  else if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
1356  {
1357  //When a mDNS responder places an IPv6 address record into a
1358  //response message, it should also place any IPv4 address records
1359  //with the same name into the Additional Section
1360  if(context->ipv4AddrCount > 0)
1361  {
1362  //Generate A resource records
1363  mdnsResponderGenerateIpv4AddrRecords(context, response,
1364  cacheFlush, ttl);
1365  }
1366  else
1367  {
1368  //In the event that a device has only IPv6 addresses but no IPv4
1369  //addresses, then the appropriate NSEC record should be placed
1370  //into the Additional Section
1371  mdnsResponderFormatNsecRecord(context, response, cacheFlush,
1372  ttl);
1373  }
1374  }
1375  //SRV record?
1376  else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
1377  {
1378  //Generate A resource records
1379  mdnsResponderGenerateIpv4AddrRecords(context, response,
1380  cacheFlush, ttl);
1381 
1382  //Generate AAAA resource records
1383  mdnsResponderGenerateIpv6AddrRecords(context, response,
1384  cacheFlush, ttl);
1385 
1386  //In the event that a device has only IPv4 addresses but no IPv6
1387  //addresses, or vice versa, then the appropriate NSEC record should
1388  //be placed into the additional section, so that queriers can know
1389  //with certainty that the device has no addresses of that kind
1390  if(context->ipv4AddrCount == 0 || context->ipv6AddrCount == 0)
1391  {
1392  //Generate NSEC resource record
1393  mdnsResponderFormatNsecRecord(context, response, cacheFlush,
1394  ttl);
1395  }
1396  }
1397  }
1398 
1399  //Point to the next resource record
1400  offset = n + ntohs(record->rdlength);
1401  }
1402 
1403  //Number of resource records in the Additional Section
1404  response->dnsHeader->arcount += response->dnsHeader->ancount - ancount;
1405  //Number of resource records in the Answer Section
1406  response->dnsHeader->ancount = ancount;
1407 #endif
1408 }
1409 
1410 
1411 /**
1412  * @brief Generate A resource records
1413  * @param[in] context Pointer to the mDNS responder context
1414  * @param[in,out] message Pointer to the mDNS message
1415  * @param[in] cacheFlush Cache-flush bit
1416  * @param[in] ttl Resource record TTL (cache lifetime)
1417  * @return Error code
1418  **/
1419 
1421  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1422 {
1423 #if (IPV4_SUPPORT == ENABLED)
1424  error_t error;
1425  uint_t i;
1426 
1427  //Initialize status code
1428  error = NO_ERROR;
1429 
1430  //Loop through the list of IPv4 addresses assigned to the interface
1431  for(i = 0; i < IPV4_ADDR_LIST_SIZE && !error; i++)
1432  {
1433  //Valid entry?
1434  if(context->ipv4AddrList[i].valid)
1435  {
1436  //Format A resource record
1437  error = mdnsResponderFormatIpv4AddrRecord(context, message,
1438  context->ipv4AddrList[i].record.rdata, cacheFlush, ttl);
1439  }
1440  }
1441 
1442  //Return status code
1443  return error;
1444 #else
1445  //Not implemented
1446  return NO_ERROR;
1447 #endif
1448 }
1449 
1450 
1451 /**
1452  * @brief Generate AAAA resource records
1453  * @param[in] context Pointer to the mDNS responder context
1454  * @param[in,out] message Pointer to the mDNS message
1455  * @param[in] cacheFlush Cache-flush bit
1456  * @param[in] ttl Resource record TTL (cache lifetime)
1457  * @return Error code
1458  **/
1459 
1461  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1462 {
1463 #if (IPV6_SUPPORT == ENABLED)
1464  error_t error;
1465  uint_t i;
1466 
1467  //Initialize status code
1468  error = NO_ERROR;
1469 
1470  //Loop through the list of IPv6 addresses assigned to the interface
1471  for(i = 0; i < IPV6_ADDR_LIST_SIZE && !error; i++)
1472  {
1473  //Valid entry?
1474  if(context->ipv6AddrList[i].valid)
1475  {
1476  //Format AAAA resource record
1477  error = mdnsResponderFormatIpv6AddrRecord(context, message,
1478  context->ipv6AddrList[i].record.rdata, cacheFlush, ttl);
1479  }
1480  }
1481 
1482  //Return status code
1483  return error;
1484 #else
1485  //Not implemented
1486  return NO_ERROR;
1487 #endif
1488 }
1489 
1490 
1491 /**
1492  * @brief Generate reverse address mapping PTR resource record (IPv4)
1493  * @param[in] context Pointer to the mDNS responder context
1494  * @param[in,out] message Pointer to the mDNS message
1495  * @param[in] cacheFlush Cache-flush bit
1496  * @param[in] ttl Resource record TTL (cache lifetime)
1497  * @return Error code
1498  **/
1499 
1501  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1502 {
1503 #if (IPV4_SUPPORT == ENABLED)
1504  error_t error;
1505  uint_t i;
1506 
1507  //Initialize status code
1508  error = NO_ERROR;
1509 
1510  //Loop through the list of IPv4 addresses assigned to the interface
1511  for(i = 0; i < IPV4_ADDR_LIST_SIZE && !error; i++)
1512  {
1513  //Valid entry?
1514  if(context->ipv4AddrList[i].valid)
1515  {
1516  //Format reverse address mapping PTR resource record (IPv4)
1517  error = mdnsResponderFormatIpv4PtrRecord(context, message,
1518  context->ipv4AddrList[i].reverseName, cacheFlush, ttl);
1519  }
1520  }
1521 
1522  //Return status code
1523  return error;
1524 #else
1525  //Not implemented
1526  return NO_ERROR;
1527 #endif
1528 }
1529 
1530 
1531 /**
1532  * @brief Generate reverse address mapping PTR resource record (IPv6)
1533  * @param[in] context Pointer to the mDNS responder context
1534  * @param[in,out] message Pointer to the mDNS message
1535  * @param[in] cacheFlush Cache-flush bit
1536  * @param[in] ttl Resource record TTL (cache lifetime)
1537  * @return Error code
1538  **/
1539 
1541  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1542 {
1543 #if (IPV6_SUPPORT == ENABLED)
1544  error_t error;
1545  uint_t i;
1546 
1547  //Initialize status code
1548  error = NO_ERROR;
1549 
1550  //Loop through the list of IPv6 addresses assigned to the interface
1551  for(i = 0; i < IPV6_ADDR_LIST_SIZE && !error; i++)
1552  {
1553  //Valid entry?
1554  if(context->ipv6AddrList[i].valid)
1555  {
1556  //Format reverse address mapping PTR resource record (IPv6)
1557  error = mdnsResponderFormatIpv6PtrRecord(context, message,
1558  context->ipv6AddrList[i].reverseName, cacheFlush, ttl);
1559  }
1560  }
1561 
1562  //Return status code
1563  return error;
1564 #else
1565  //Not implemented
1566  return NO_ERROR;
1567 #endif
1568 }
1569 
1570 
1571 /**
1572  * @brief Format A resource record
1573  * @param[in] context Pointer to the mDNS responder context
1574  * @param[in,out] message Pointer to the mDNS message
1575  * @param[in] ipv4Addr Pointer to the IPv4 address
1576  * @param[in] cacheFlush Cache-flush bit
1577  * @param[in] ttl Resource record TTL (cache lifetime)
1578  * @return Error code
1579  **/
1580 
1582  MdnsMessage *message, const uint8_t *ipv4Addr, bool_t cacheFlush,
1583  uint32_t ttl)
1584 {
1585  size_t n;
1586  size_t offset;
1587  bool_t duplicate;
1588  DnsResourceRecord *record;
1589 
1590  //Check whether the resource record is already present in the Answer
1591  //Section of the message
1592  duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
1593  "", ".local", DNS_RR_TYPE_A, ipv4Addr, sizeof(Ipv4Addr));
1594 
1595  //The duplicates should be suppressed and the resource record should
1596  //appear only once in the list
1597  if(!duplicate)
1598  {
1599  //Set the position to the end of the buffer
1600  offset = message->length;
1601 
1602  //The first pass calculates the length of the DNS encoded host name
1603  n = mdnsEncodeName(context->hostname, "", ".local", NULL);
1604 
1605  //Check the length of the resulting mDNS message
1606  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1607  return ERROR_MESSAGE_TOO_LONG;
1608 
1609  //The second pass encodes the host name using the DNS name notation
1610  offset += mdnsEncodeName(context->hostname, "", ".local",
1611  (uint8_t *) message->dnsHeader + offset);
1612 
1613  //Consider the length of the resource record itself
1614  n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
1615 
1616  //Check the length of the resulting mDNS message
1617  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1618  return ERROR_MESSAGE_TOO_LONG;
1619 
1620  //Point to the corresponding resource record
1621  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1622 
1623  //Fill in resource record
1624  record->rtype = HTONS(DNS_RR_TYPE_A);
1625  record->rclass = HTONS(DNS_RR_CLASS_IN);
1626  record->ttl = htonl(ttl);
1627  record->rdlength = HTONS(sizeof(Ipv4Addr));
1628 
1629  //Check whether the cache-flush bit should be set
1630  if(cacheFlush)
1631  {
1632  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1633  }
1634 
1635  //Copy IPv4 address
1636  ipv4CopyAddr(record->rdata, ipv4Addr);
1637 
1638  //Number of resource records in the answer section
1639  message->dnsHeader->ancount++;
1640  //Update the length of the mDNS response message
1641  message->length = offset + n;
1642  }
1643 
1644  //Successful processing
1645  return NO_ERROR;
1646 }
1647 
1648 
1649 /**
1650  * @brief Format AAAA resource record
1651  * @param[in] context Pointer to the mDNS responder context
1652  * @param[in,out] message Pointer to the mDNS message
1653  * @param[in] ipv6Addr Pointer to the IPv6 address
1654  * @param[in] cacheFlush Cache-flush bit
1655  * @param[in] ttl Resource record TTL (cache lifetime)
1656  * @return Error code
1657  **/
1658 
1660  MdnsMessage *message, const uint8_t *ipv6Addr, bool_t cacheFlush,
1661  uint32_t ttl)
1662 {
1663  size_t n;
1664  size_t offset;
1665  bool_t duplicate;
1666  DnsResourceRecord *record;
1667 
1668  //Check whether the resource record is already present in the Answer
1669  //Section of the message
1670  duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
1671  "", ".local", DNS_RR_TYPE_AAAA, ipv6Addr, sizeof(Ipv6Addr));
1672 
1673  //The duplicates should be suppressed and the resource record should
1674  //appear only once in the list
1675  if(!duplicate)
1676  {
1677  //Set the position to the end of the buffer
1678  offset = message->length;
1679 
1680  //The first pass calculates the length of the DNS encoded host name
1681  n = mdnsEncodeName(context->hostname, "", ".local", NULL);
1682 
1683  //Check the length of the resulting mDNS message
1684  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1685  return ERROR_MESSAGE_TOO_LONG;
1686 
1687  //The second pass encodes the host name using the DNS name notation
1688  offset += mdnsEncodeName(context->hostname, "", ".local",
1689  (uint8_t *) message->dnsHeader + offset);
1690 
1691  //Consider the length of the resource record itself
1692  n = sizeof(DnsResourceRecord) + sizeof(Ipv6Addr);
1693 
1694  //Check the length of the resulting mDNS message
1695  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1696  return ERROR_MESSAGE_TOO_LONG;
1697 
1698  //Point to the corresponding resource record
1699  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1700 
1701  //Fill in resource record
1702  record->rtype = HTONS(DNS_RR_TYPE_AAAA);
1703  record->rclass = HTONS(DNS_RR_CLASS_IN);
1704  record->ttl = htonl(ttl);
1705  record->rdlength = HTONS(sizeof(Ipv6Addr));
1706 
1707  //Check whether the cache-flush bit should be set
1708  if(cacheFlush)
1709  {
1710  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1711  }
1712 
1713  //Copy IPv6 address
1714  ipv6CopyAddr(record->rdata, ipv6Addr);
1715 
1716  //Number of resource records in the answer section
1717  message->dnsHeader->ancount++;
1718  //Update the length of the mDNS response message
1719  message->length = offset + n;
1720  }
1721 
1722  //Successful processing
1723  return NO_ERROR;
1724 }
1725 
1726 
1727 /**
1728  * @brief Format reverse address mapping PTR resource record (IPv4)
1729  * @param[in] context Pointer to the mDNS responder context
1730  * @param[in,out] message Pointer to the mDNS message
1731  * @param[in] reverseName Domain name for reverse DNS lookup
1732  * @param[in] cacheFlush Cache-flush bit
1733  * @param[in] ttl Resource record TTL (cache lifetime)
1734  * @return Error code
1735  **/
1736 
1738  MdnsMessage *message, const char_t *reverseName, bool_t cacheFlush,
1739  uint32_t ttl)
1740 {
1741  size_t n;
1742  size_t offset;
1743  bool_t duplicate;
1744  DnsResourceRecord *record;
1745 
1746  //Check whether the resource record is already present in the Answer Section
1747  //of the message
1748  duplicate = mdnsCheckDuplicateRecord(message, reverseName, "in-addr", ".arpa",
1749  DNS_RR_TYPE_PTR, NULL, 0);
1750 
1751  //The duplicates should be suppressed and the resource record should appear
1752  //only once in the list
1753  if(!duplicate)
1754  {
1755  //Set the position to the end of the buffer
1756  offset = message->length;
1757 
1758  //The first pass calculates the length of the DNS encoded reverse name
1759  n = mdnsEncodeName(reverseName, "in-addr", ".arpa", NULL);
1760 
1761  //Check the length of the resulting mDNS message
1762  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1763  return ERROR_MESSAGE_TOO_LONG;
1764 
1765  //The second pass encodes the reverse name using the DNS name notation
1766  offset += mdnsEncodeName(reverseName, "in-addr", ".arpa",
1767  (uint8_t *) message->dnsHeader + offset);
1768 
1769  //Consider the length of the resource record itself
1770  n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
1771 
1772  //Check the length of the resulting mDNS message
1773  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1774  return ERROR_MESSAGE_TOO_LONG;
1775 
1776  //Point to the corresponding resource record
1777  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1778 
1779  //Fill in resource record
1780  record->rtype = HTONS(DNS_RR_TYPE_PTR);
1781  record->rclass = HTONS(DNS_RR_CLASS_IN);
1782  record->ttl = htonl(ttl);
1783 
1784  //Check whether the cache-flush bit should be set
1785  if(cacheFlush)
1786  {
1787  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1788  }
1789 
1790  //Advance write index
1791  offset += sizeof(DnsResourceRecord);
1792 
1793  //The first pass calculates the length of the DNS encoded host name
1794  n = mdnsEncodeName("", context->hostname, ".local", NULL);
1795 
1796  //Check the length of the resulting mDNS message
1797  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1798  return ERROR_MESSAGE_TOO_LONG;
1799 
1800  //The second pass encodes the host name using DNS notation
1801  n = mdnsEncodeName("", context->hostname, ".local", record->rdata);
1802 
1803  //Convert length field to network byte order
1804  record->rdlength = htons(n);
1805 
1806  //Number of resource records in the answer section
1807  message->dnsHeader->ancount++;
1808  //Update the length of the mDNS response message
1809  message->length = offset + n;
1810  }
1811 
1812  //Successful processing
1813  return NO_ERROR;
1814 }
1815 
1816 
1817 /**
1818  * @brief Format reverse address mapping PTR resource record (IPv6)
1819  * @param[in] context Pointer to the mDNS responder context
1820  * @param[in,out] message Pointer to the mDNS message
1821  * @param[in] reverseName Domain name for reverse DNS lookup
1822  * @param[in] cacheFlush Cache-flush bit
1823  * @param[in] ttl Resource record TTL (cache lifetime)
1824  * @return Error code
1825  **/
1826 
1828  MdnsMessage *message, const char_t *reverseName, bool_t cacheFlush,
1829  uint32_t ttl)
1830 {
1831  size_t n;
1832  size_t offset;
1833  bool_t duplicate;
1834  DnsResourceRecord *record;
1835 
1836  //Check whether the resource record is already present in the Answer Section
1837  //of the message
1838  duplicate = mdnsCheckDuplicateRecord(message, reverseName, "ip6", ".arpa",
1839  DNS_RR_TYPE_PTR, NULL, 0);
1840 
1841  //The duplicates should be suppressed and the resource record should appear
1842  //only once in the list
1843  if(!duplicate)
1844  {
1845  //Set the position to the end of the buffer
1846  offset = message->length;
1847 
1848  //The first pass calculates the length of the DNS encoded reverse name
1849  n = mdnsEncodeName(reverseName, "ip6", ".arpa", NULL);
1850 
1851  //Check the length of the resulting mDNS message
1852  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1853  return ERROR_MESSAGE_TOO_LONG;
1854 
1855  //The second pass encodes the reverse name using the DNS name notation
1856  offset += mdnsEncodeName(reverseName, "ip6", ".arpa",
1857  (uint8_t *) message->dnsHeader + offset);
1858 
1859  //Consider the length of the resource record itself
1860  n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
1861 
1862  //Check the length of the resulting mDNS message
1863  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1864  return ERROR_MESSAGE_TOO_LONG;
1865 
1866  //Point to the corresponding resource record
1867  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1868 
1869  //Fill in resource record
1870  record->rtype = HTONS(DNS_RR_TYPE_PTR);
1871  record->rclass = HTONS(DNS_RR_CLASS_IN);
1872  record->ttl = htonl(ttl);
1873 
1874  //Check whether the cache-flush bit should be set
1875  if(cacheFlush)
1876  {
1877  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1878  }
1879 
1880  //Advance write index
1881  offset += sizeof(DnsResourceRecord);
1882 
1883  //The first pass calculates the length of the DNS encoded host name
1884  n = mdnsEncodeName("", context->hostname, ".local", NULL);
1885 
1886  //Check the length of the resulting mDNS message
1887  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1888  return ERROR_MESSAGE_TOO_LONG;
1889 
1890  //The second pass encodes the host name using DNS notation
1891  n = mdnsEncodeName("", context->hostname, ".local", record->rdata);
1892 
1893  //Convert length field to network byte order
1894  record->rdlength = htons(n);
1895 
1896  //Number of resource records in the answer section
1897  message->dnsHeader->ancount++;
1898  //Update the length of the mDNS response message
1899  message->length = offset + n;
1900  }
1901 
1902  //Successful processing
1903  return NO_ERROR;
1904 }
1905 
1906 
1907 /**
1908  * @brief Format NSEC resource record
1909  * @param[in] context Pointer to the mDNS responder context
1910  * @param[in,out] message Pointer to the mDNS message
1911  * @param[in] cacheFlush Cache-flush bit
1912  * @param[in] ttl Resource record TTL (cache lifetime)
1913  * @return Error code
1914  **/
1915 
1917  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1918 {
1919  size_t n;
1920  size_t offset;
1921  bool_t duplicate;
1922  size_t bitmapLen;
1923  uint8_t bitmap[8];
1924  DnsResourceRecord *record;
1925 
1926  //Check whether the resource record is already present in the Answer
1927  //Section of the message
1928  duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
1929  "", ".local", DNS_RR_TYPE_NSEC, NULL, 0);
1930 
1931  //The duplicates should be suppressed and the resource record should
1932  //appear only once in the list
1933  if(!duplicate)
1934  {
1935  //The bitmap identifies the resource record types that exist
1936  osMemset(bitmap, 0, sizeof(bitmap));
1937 
1938  //Check whether the host has A records
1939  if(context->ipv4AddrCount > 0)
1940  {
1942  }
1943 
1944  //Check whether the host has AAAA records
1945  if(context->ipv6AddrCount > 0)
1946  {
1948  }
1949 
1950  //Compute the length of the bitmap
1951  for(bitmapLen = sizeof(bitmap); bitmapLen > 0; bitmapLen--)
1952  {
1953  //Trailing zero octets in the bitmap must be omitted
1954  if(bitmap[bitmapLen - 1] != 0)
1955  {
1956  break;
1957  }
1958  }
1959 
1960  //Set the position to the end of the buffer
1961  offset = message->length;
1962 
1963  //The first pass calculates the length of the DNS encoded host name
1964  n = mdnsEncodeName(context->hostname, "", ".local", NULL);
1965 
1966  //Check the length of the resulting mDNS message
1967  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1968  return ERROR_MESSAGE_TOO_LONG;
1969 
1970  //The second pass encodes the host name using the DNS name notation
1971  offset += mdnsEncodeName(context->hostname, "", ".local",
1972  (uint8_t *) message->dnsHeader + offset);
1973 
1974  //Consider the length of the resource record itself
1975  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1976  return ERROR_MESSAGE_TOO_LONG;
1977 
1978  //Point to the corresponding resource record
1979  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1980 
1981  //Fill in resource record
1982  record->rtype = HTONS(DNS_RR_TYPE_NSEC);
1983  record->rclass = HTONS(DNS_RR_CLASS_IN);
1984  record->ttl = htonl(ttl);
1985 
1986  //Check whether the cache-flush bit should be set
1987  if(cacheFlush)
1988  {
1989  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1990  }
1991 
1992  //Advance write index
1993  offset += sizeof(DnsResourceRecord);
1994 
1995  //Check the length of the resulting mDNS message
1996  if((offset + n + 2 + bitmapLen) > MDNS_MESSAGE_MAX_SIZE)
1997  return ERROR_MESSAGE_TOO_LONG;
1998 
1999  //The Next Domain Name field contains the record's own name
2000  mdnsEncodeName(context->hostname, "", ".local", record->rdata);
2001 
2002  //DNS NSEC record is limited to Window Block number zero
2003  record->rdata[n++] = 0;
2004  //The Bitmap Length is a value in the range 1-32
2005  record->rdata[n++] = bitmapLen;
2006 
2007  //The Bitmap data identifies the resource record types that exist
2008  osMemcpy(record->rdata + n, bitmap, bitmapLen);
2009 
2010  //Convert length field to network byte order
2011  record->rdlength = htons(n + bitmapLen);
2012 
2013  //Number of resource records in the answer section
2014  message->dnsHeader->ancount++;
2015  //Update the length of the DNS message
2016  message->length = offset + n + bitmapLen;
2017  }
2018 
2019  //Successful processing
2020  return NO_ERROR;
2021 }
2022 
2023 
2024 /**
2025  * @brief Sort the host records in lexicographical order
2026  * @param[in] context Pointer to the mDNS responder context
2027  * @param[in] record Pointer to the current record
2028  * @return Pointer to the next record, if any
2029  **/
2030 
2032  DnsResourceRecord *record)
2033 {
2034  uint_t i;
2035  int_t res;
2036  DnsResourceRecord *curRecord;
2037  DnsResourceRecord *nextRecord;
2038 
2039  //Initialize record pointer
2040  nextRecord = NULL;
2041 
2042 #if (IPV4_SUPPORT == ENABLED)
2043  //Loop through the list of IPv4 addresses assigned to the interface
2044  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
2045  {
2046  //Valid IPv4 address?
2047  if(context->ipv4AddrList[i].valid)
2048  {
2049  //Point to the A resource record
2050  curRecord = (DnsResourceRecord *) &context->ipv4AddrList[i].record;
2051 
2052  //Perform lexicographical comparison
2053  if(record != NULL)
2054  {
2055  res = mdnsCompareRecord(NULL, curRecord, NULL, record);
2056  }
2057  else
2058  {
2059  res = 1;
2060  }
2061 
2062  //Check whether the record is lexicographically later
2063  if(res > 0)
2064  {
2065  if(nextRecord == NULL)
2066  {
2067  nextRecord = curRecord;
2068  }
2069  else if(mdnsCompareRecord(NULL, curRecord, NULL, nextRecord) < 0)
2070  {
2071  nextRecord = curRecord;
2072  }
2073  }
2074  }
2075  }
2076 #endif
2077 
2078 #if (IPV6_SUPPORT == ENABLED)
2079  //Loop through the list of IPv6 addresses assigned to the interface
2080  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
2081  {
2082  //Valid IPv6 address?
2083  if(context->ipv6AddrList[i].valid)
2084  {
2085  //Point to the AAAA resource record
2086  curRecord = (DnsResourceRecord *) &context->ipv6AddrList[i].record;
2087 
2088  //Perform lexicographical comparison
2089  if(record != NULL)
2090  {
2091  res = mdnsCompareRecord(NULL, curRecord, NULL, record);
2092  }
2093  else
2094  {
2095  res = 1;
2096  }
2097 
2098  //Check whether the record is lexicographically later
2099  if(res > 0)
2100  {
2101  if(nextRecord == NULL)
2102  {
2103  nextRecord = curRecord;
2104  }
2105  else if(mdnsCompareRecord(NULL, curRecord, NULL, nextRecord) < 0)
2106  {
2107  nextRecord = curRecord;
2108  }
2109  }
2110  }
2111  }
2112 #endif
2113 
2114  //Return the pointer to the next record
2115  return nextRecord;
2116 }
2117 
2118 
2119 /**
2120  * @brief Sort the tiebreaker records in lexicographical order
2121  * @param[in] context Pointer to the mDNS responder context
2122  * @param[in] query Incoming mDNS query message
2123  * @param[in] offset Offset to first byte of the Authority Section
2124  * @param[in] record Pointer to the current record
2125  * @return Pointer to the next record, if any
2126  **/
2127 
2129  const MdnsMessage *query, size_t offset, DnsResourceRecord *record)
2130 {
2131  uint_t i;
2132  size_t n;
2133  int_t res;
2134  DnsResourceRecord *curRecord;
2135  DnsResourceRecord *nextRecord;
2136 
2137  //Initialize record pointer
2138  nextRecord = NULL;
2139 
2140  //Parse Authority Section
2141  for(i = 0; i < ntohs(query->dnsHeader->nscount); i++)
2142  {
2143  //Parse resource record name
2144  n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0);
2145  //Invalid name?
2146  if(!n)
2147  break;
2148 
2149  //Point to the associated resource record
2150  curRecord = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
2151  //Point to the resource data
2152  n += sizeof(DnsResourceRecord);
2153 
2154  //Make sure the resource record is valid
2155  if(n > query->length)
2156  break;
2157  if((n + ntohs(curRecord->rdlength)) > query->length)
2158  break;
2159 
2160  //Matching host name?
2161  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
2162  context->hostname, "", ".local", 0))
2163  {
2164  //Perform lexicographical comparison
2165  if(record != NULL)
2166  {
2167  res = mdnsCompareRecord(query, curRecord, query, record);
2168  }
2169  else
2170  {
2171  res = 1;
2172  }
2173 
2174  //Check whether the record is lexicographically later
2175  if(res > 0)
2176  {
2177  if(nextRecord == NULL)
2178  {
2179  nextRecord = curRecord;
2180  }
2181  else if(mdnsCompareRecord(query, curRecord, query, nextRecord) < 0)
2182  {
2183  nextRecord = curRecord;
2184  }
2185  }
2186  }
2187 
2188  //Point to the next resource record
2189  offset = n + ntohs(curRecord->rdlength);
2190  }
2191 
2192  //Return the pointer to the next record
2193  return nextRecord;
2194 }
2195 
2196 #endif
#define MdnsResponderContext
void mdnsResponderProcessQuery(NetInterface *interface, MdnsMessage *query)
Process mDNS query message.
#define htons(value)
Definition: cpu_endian.h:413
Ipv6PseudoHeader ipv6Data
Definition: ip.h:118
int bool_t
Definition: compiler_port.h:53
@ DNS_RR_CLASS_ANY
Any class.
Definition: dns_common.h:127
const Ipv6Addr MDNS_IPV6_MULTICAST_ADDR
Definition: mdns_common.c:59
signed int int_t
Definition: compiler_port.h:49
#define netMutex
Definition: net_legacy.h:195
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
error_t mdnsResponderFormatNsecRecord(MdnsResponderContext *context, MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
Format NSEC resource record.
uint_t sharedRecordCount
Definition: mdns_common.h:87
#define DNS_SET_NSEC_BITMAP(bitmap, type)
Definition: dns_common.h:66
uint8_t message[]
Definition: chap.h:154
NetBuffer * buffer
Definition: mdns_common.h:79
#define TRUE
Definition: os_port.h:50
systime_t timeout
Definition: mdns_common.h:86
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
error_t dnsSdResponderParseQuestion(NetInterface *interface, const MdnsMessage *query, size_t offset, const DnsQuestion *question, MdnsMessage *response)
Parse a question.
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
@ DNS_RR_TYPE_NSEC
NSEC record.
Definition: dns_common.h:151
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
DnsHeader
Definition: dns_common.h:199
uint16_t destPort
Definition: tcp.h:340
@ MDNS_STATE_IDLE
error_t mdnsResponderGenerateIpv4AddrRecords(MdnsResponderContext *context, MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
Generate A resource records.
#define osStrlen(s)
Definition: os_port.h:165
size_t length
Definition: ip.h:111
const uint8_t res[]
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:297
MdnsState
mDNS responder states
#define MDNS_LEGACY_UNICAST_RR_TTL
Definition: mdns_common.h:57
#define MDNS_PORT
Definition: mdns_common.h:53
@ DNS_RR_TYPE_ANY
A request for all records.
Definition: dns_common.h:155
error_t mdnsResponderSendGoodbye(MdnsResponderContext *context)
Send goodbye packet.
#define FALSE
Definition: os_port.h:46
#define htonl(value)
Definition: cpu_endian.h:414
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:948
error_t
Error codes.
Definition: error.h:43
#define DNS_GET_QUESTION(message, offset)
Definition: dns_common.h:63
#define osSprintf(dest,...)
Definition: os_port.h:231
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:64
void mdnsResponderChangeHostname(MdnsResponderContext *context)
Programmatically change the host name.
#define Ipv6PseudoHeader
Definition: ipv6.h:42
DNS-SD responder (DNS-Based Service Discovery)
error_t mdnsResponderFormatIpv6PtrRecord(MdnsResponderContext *context, MdnsMessage *message, const char_t *reverseName, bool_t cacheFlush, uint32_t ttl)
Format reverse address mapping PTR resource record (IPv6)
const IpPseudoHeader * pseudoHeader
Definition: mdns_common.h:82
size_t length
Definition: mdns_common.h:81
uint16_t qclass
Definition: dns_common.h:209
void mdnsResponderParseAnRecord(NetInterface *interface, const MdnsMessage *response, size_t offset, const DnsResourceRecord *record)
Parse a resource record from the Answer Section.
#define NetInterface
Definition: net.h:36
error_t mdnsResponderParseQuestion(NetInterface *interface, const MdnsMessage *query, size_t offset, const DnsQuestion *question, MdnsMessage *response)
Parse a question.
@ DNS_RR_TYPE_A
Host address.
Definition: dns_common.h:137
@ DNS_RR_TYPE_PTR
Domain name pointer.
Definition: dns_common.h:142
error_t mdnsCreateMessage(MdnsMessage *message, bool_t queryResponse)
Create an empty mDNS message.
Definition: mdns_common.c:357
void mdnsResponderParseKnownAnRecord(NetInterface *interface, const MdnsMessage *query, size_t queryOffset, const DnsResourceRecord *queryRecord, MdnsMessage *response)
Parse a resource record from the Known-Answer Section.
uint16_t ancount
Definition: dns_common.h:195
#define osIsdigit(c)
Definition: os_port.h:285
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:69
@ ERROR_MESSAGE_TOO_LONG
Definition: error.h:136
#define MIN(a, b)
Definition: os_port.h:63
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
error_t mdnsResponderFormatIpv4AddrRecord(MdnsResponderContext *context, MdnsMessage *message, const uint8_t *ipv4Addr, bool_t cacheFlush, uint32_t ttl)
Format A resource record.
uint32_t systime_t
System time.
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
error_t mdnsResponderSendProbe(MdnsResponderContext *context)
Send probe packet.
void dnsSdResponderParseNsRecords(NetInterface *interface, const MdnsMessage *query, size_t offset)
Parse the Authority Section.
mDNS message
Definition: mdns_common.h:78
char char_t
Definition: compiler_port.h:48
#define osStrcat(s1, s2)
Definition: os_port.h:219
void dnsSdResponderGenerateAdditionalRecords(NetInterface *interface, MdnsMessage *response, bool_t legacyUnicast)
Additional record generation.
void mdnsResponderChangeState(MdnsResponderContext *context, MdnsState newState, systime_t delay)
Update FSM state.
#define ipv6CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv6.h:123
#define ipv4CompAddr(ipAddr1, ipAddr2)
Definition: ipv4.h:159
void mdnsResponderGenerateAdditionalRecords(MdnsResponderContext *context, MdnsMessage *response, bool_t legacyUnicast)
Generate additional records.
Helper functions for DNS-SD responder.
void mdnsDeleteMessage(MdnsMessage *message)
release a mDNS message
Definition: mdns_common.c:434
@ MDNS_STATE_ANNOUNCING
uint8_t m
Definition: ndp.h:304
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
const UdpHeader * udpHeader
Definition: mdns_common.h:83
#define IPV6_ADDR_LIST_SIZE
Definition: ipv6.h:65
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
DnsResourceRecord * mdnsResponderGetNextTiebreakerRecord(MdnsResponderContext *context, const MdnsMessage *query, size_t offset, DnsResourceRecord *record)
Sort the tiebreaker records in lexicographical order.
Helper functions for mDNS responder.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
DnsQuestion
Definition: dns_common.h:210
#define MDNS_MESSAGE_MAX_SIZE
Definition: mdns_common.h:40
uint8_t s
Definition: igmp_common.h:234
#define ipv4CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv4.h:155
error_t mdnsResponderGenerateIpv6AddrRecords(MdnsResponderContext *context, MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
Generate AAAA resource records.
@ DNS_RR_TYPE_SRV
Server selection.
Definition: dns_common.h:149
error_t mdnsResponderFormatIpv6AddrRecord(MdnsResponderContext *context, MdnsMessage *message, const uint8_t *ipv6Addr, bool_t cacheFlush, uint32_t ttl)
Format AAAA resource record.
error_t mdnsResponderFormatIpv4PtrRecord(MdnsResponderContext *context, MdnsMessage *message, const char_t *reverseName, bool_t cacheFlush, uint32_t ttl)
Format reverse address mapping PTR resource record (IPv4)
uint32_t ttl
Definition: dns_common.h:221
#define MDNS_IPV4_MULTICAST_ADDR
Definition: mdns_common.h:65
error_t mdnsResponderGenerateIpv6PtrRecords(MdnsResponderContext *context, MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
Generate reverse address mapping PTR resource record (IPv6)
DnsResourceRecord * mdnsResponderGetNextHostRecord(MdnsResponderContext *context, DnsResourceRecord *record)
Sort the host records in lexicographical order.
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:224
#define MDNS_DEFAULT_RR_TTL
Definition: mdns_common.h:47
@ DNS_RR_TYPE_AAAA
IPv6 address.
Definition: dns_common.h:147
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
systime_t timestamp
Definition: mdns_common.h:85
void mdnsResponderParseNsRecords(MdnsResponderContext *context, const MdnsMessage *query, size_t offset)
Parse the Authority Section.
#define ntohl(value)
Definition: cpu_endian.h:422
Ipv4PseudoHeader ipv4Data
Definition: ip.h:115
error_t mdnsResponderSendAnnouncement(MdnsResponderContext *context)
Send announcement packet.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define MDNS_QCLASS_QU
Definition: mdns_common.h:60
#define osMemmove(dest, src, length)
Definition: os_port.h:147
#define NET_MAX_HOSTNAME_LEN
Definition: net.h:149
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
error_t mdnsResponderGenerateIpv4PtrRecords(MdnsResponderContext *context, MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
Generate reverse address mapping PTR resource record (IPv4)
systime_t osGetSystemTime(void)
Retrieve system time.
Ipv4Addr destIpAddr
Definition: ipcp.h:80