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