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.6
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, 0);
464  //Invalid name?
465  if(n == 0)
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, 0);
503  //Invalid name?
504  if(n == 0)
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,
854  responseOffset, 0);
855  //Invalid name?
856  if(n == 0)
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, 0);
978  //Invalid name?
979  if(n == 0)
980  break;
981 
982  //Point to the associated resource record
983  record2 = DNS_GET_RESOURCE_RECORD(response2->dnsHeader, n);
984  //Point to the resource data
985  n += sizeof(DnsResourceRecord);
986 
987  //Make sure the resource record is valid
988  if(n > response2->length)
989  break;
990 
991  //Point to the end of the resource record
992  n += ntohs(record2->rdlength);
993 
994  //Make sure the resource record is valid
995  if(n > response2->length)
996  break;
997 
998  //Compare resource record names
999  if(!dnsCompareEncodedName(response->dnsHeader, response->length, offset,
1000  response2->dnsHeader, response2->length, offset2, 0))
1001  {
1002  //Compare the contents of the resource records
1003  if(!mdnsCompareRecord(response, record, response2, record2))
1004  {
1005  //If a host is planning to send an answer, and it sees another
1006  //host on the network send a response message containing the same
1007  //answer record, and the TTL in that record is not less than the
1008  //TTL this host would have given, then this host should treat its
1009  //own answer as having been sent, and not also send an identical
1010  //answer itself
1011  if(ntohl(record->ttl) >= ntohl(record2->ttl))
1012  {
1013  //Perform Duplicate Answer Suppression
1014  osMemmove((uint8_t *) response2->dnsHeader + offset2,
1015  (uint8_t *) response2->dnsHeader + n, response2->length - n);
1016 
1017  //Update the length of the mDNS response2 message
1018  response2->length -= (n - offset2);
1019  //Update the number of resource records in the Answer Section
1020  response2->dnsHeader->ancount--;
1021 
1022  //Update the number of shared resource records
1023  if(ntohs(record->rclass) == DNS_RR_TYPE_PTR &&
1024  response2->sharedRecordCount > 0)
1025  {
1026  response2->sharedRecordCount--;
1027  }
1028 
1029  //Keep at the same position
1030  n = offset2;
1031  i--;
1032  }
1033  }
1034  }
1035 
1036  //Point to the next resource record
1037  offset2 = n;
1038  }
1039 
1040  //When multiple responders on the network have the same data, there is no
1041  //need for all of them to respond
1042  if(response2->dnsHeader->ancount == 0)
1043  {
1044  mdnsDeleteMessage(response2);
1045  }
1046  }
1047 
1048  //Check for conflicts
1049  if(!mdnsCompareName(response->dnsHeader, response->length, offset,
1050  context->hostname, "", ".local", 0))
1051  {
1052  //Convert the class to host byte order
1053  rclass = ntohs(record->rclass);
1054  //Discard Cache Flush flag
1056 
1057  //Check the class of the resource record
1058  if(rclass == DNS_RR_CLASS_IN)
1059  {
1060 #if (IPV4_SUPPORT == ENABLED)
1061  //A resource record found?
1062  if(ntohs(record->rtype) == DNS_RR_TYPE_A)
1063  {
1064  //A conflict occurs when a mDNS responder has a unique record for
1065  //which it is currently authoritative, and it receives a mDNS
1066  //response message containing a record with the same name, rrtype
1067  //and rrclass, but inconsistent rdata
1068  conflict = TRUE;
1069 
1070  //Verify the length of the data field
1071  if(ntohs(record->rdlength) == sizeof(Ipv4Addr))
1072  {
1073  //Loop through the list of IPv4 addresses assigned to the interface
1074  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
1075  {
1076  //Valid IPv4 address?
1077  if(context->ipv4AddrList[i].valid)
1078  {
1079  //Check whether the rdata field is consistent
1080  if(ipv4CompAddr(context->ipv4AddrList[i].record.rdata,
1081  record->rdata))
1082  {
1083  conflict = FALSE;
1084  }
1085  }
1086  }
1087  }
1088 
1089  //Check whether the host name is already in use by some other host
1090  if(conflict)
1091  {
1092  context->conflict = TRUE;
1093  }
1094  }
1095 #endif
1096 #if (IPV6_SUPPORT == ENABLED)
1097  //AAAA resource record found?
1098  if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
1099  {
1100  //A conflict occurs when a mDNS responder has a unique record for
1101  //which it is currently authoritative, and it receives a mDNS
1102  //response message containing a record with the same name, rrtype
1103  //and rrclass, but inconsistent rdata
1104  conflict = TRUE;
1105 
1106  //Verify the length of the data field
1107  if(ntohs(record->rdlength) == sizeof(Ipv6Addr))
1108  {
1109  //Loop through the list of IPv6 addresses assigned to the interface
1110  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
1111  {
1112  //Valid IPv6 address?
1113  if(context->ipv6AddrList[i].valid)
1114  {
1115  //Check whether the rdata field is consistent
1116  if(ipv6CompAddr(context->ipv6AddrList[i].record.rdata,
1117  record->rdata))
1118  {
1119  conflict = FALSE;
1120  }
1121  }
1122  }
1123  }
1124 
1125  //Check whether the host name is already in use by some other host
1126  if(conflict)
1127  {
1128  context->conflict = TRUE;
1129  }
1130  }
1131 #endif
1132  }
1133  }
1134 }
1135 
1136 
1137 /**
1138  * @brief Parse the Authority Section
1139  * @param[in] context Pointer to the mDNS responder context
1140  * @param[in] query Incoming mDNS query message
1141  * @param[in] offset Offset to first byte of the Authority Section
1142  **/
1143 
1145  const MdnsMessage *query, size_t offset)
1146 {
1147  int_t res;
1148  DnsResourceRecord *record1;
1149  DnsResourceRecord *record2;
1150 
1151  //Get the first tiebreaker record in lexicographical order
1152  record1 = mdnsResponderGetNextTiebreakerRecord(context, query, offset, NULL);
1153  //Get the first host record in lexicographical order
1154  record2 = mdnsResponderGetNextHostRecord(context, NULL);
1155 
1156  //When a host is probing for a set of records with the same name, or a
1157  //message is received containing multiple tiebreaker records answering
1158  //a given probe question in the Question Section, the host's records
1159  //and the tiebreaker records from the message are each sorted into order
1160  while(1)
1161  {
1162  //The records are compared pairwise
1163  if(record1 == NULL && record2 == NULL)
1164  {
1165  //If both lists run out of records at the same time without any
1166  //difference being found, then this indicates that two devices are
1167  //advertising identical sets of records, as is sometimes done for
1168  //fault tolerance, and there is, in fact, no conflict
1169  break;
1170  }
1171  else if(record1 != NULL && record2 == NULL)
1172  {
1173  //If either list of records runs out of records before any difference
1174  //is found, then the list with records remaining is deemed to have won
1175  //the tiebreak
1176  context->tieBreakLost = TRUE;
1177  break;
1178  }
1179  else if(record1 == NULL && record2 != NULL)
1180  {
1181  //The host has won the tiebreak
1182  break;
1183  }
1184  else
1185  {
1186  //The two records are compared and the lexicographically later data
1187  //wins
1188  res = mdnsCompareRecord(query, record1, NULL, record2);
1189 
1190  //Check comparison result
1191  if(res > 0)
1192  {
1193  //If the host finds that its own data is lexicographically earlier,
1194  //then it defers to the winning host by waiting one second, and
1195  //then begins probing for this record again
1196  context->tieBreakLost = TRUE;
1197  break;
1198  }
1199  else if(res < 0)
1200  {
1201  //If the host finds that its own data is lexicographically later,
1202  //it simply ignores the other host's probe
1203  break;
1204  }
1205  else
1206  {
1207  //When comparing the records, if the first records match perfectly,
1208  //then the second records are compared, and so on
1209  }
1210  }
1211 
1212  //Get the next tiebreaker record in lexicographical order
1213  record1 = mdnsResponderGetNextTiebreakerRecord(context, query, offset,
1214  record1);
1215 
1216  //Get the next host record in lexicographical order
1217  record2 = mdnsResponderGetNextHostRecord(context, record2);
1218  }
1219 }
1220 
1221 
1222 /**
1223  * @brief Generate additional records
1224  * @param[in] context Pointer to the mDNS responder context
1225  * @param[in,out] response mDNS response message
1226  * @param[in] legacyUnicast This flag is set for legacy unicast responses
1227  **/
1228 
1230  MdnsMessage *response, bool_t legacyUnicast)
1231 {
1232 #if (MDNS_ADDITIONAL_RECORDS_SUPPORT == ENABLED)
1233  uint_t i;
1234  uint_t k;
1235  size_t n;
1236  size_t offset;
1237  uint_t ancount;
1238  uint16_t rclass;
1239  uint32_t ttl;
1240  bool_t cacheFlush;
1241  DnsResourceRecord *record;
1242 
1243  //Get the TTL resource record
1244  ttl = context->ttl;
1245 
1246  //Check whether the querier originating the query is a simple resolver
1247  if(legacyUnicast)
1248  {
1249  //The resource record TTL given in a legacy unicast response should
1250  //not be greater than ten seconds, even if the true TTL of the mDNS
1251  //resource record is higher
1253 
1254  //The cache-flush bit must not be set in legacy unicast responses
1255  cacheFlush = FALSE;
1256  }
1257  else
1258  {
1259  //The cache-bit should be set for unique resource records
1260  cacheFlush = TRUE;
1261  }
1262 
1263  //Point to the first question
1264  offset = sizeof(DnsHeader);
1265 
1266  //Skip the question section
1267  for(i = 0; i < response->dnsHeader->qdcount; i++)
1268  {
1269  //Parse domain name
1270  offset = dnsParseName(response->dnsHeader, response->length, offset, 0);
1271  //Invalid name?
1272  if(!offset)
1273  break;
1274 
1275  //Point to the next question
1276  offset += sizeof(DnsQuestion);
1277  //Make sure the mDNS message is valid
1278  if(offset > response->length)
1279  break;
1280  }
1281 
1282  //Save the number of resource records in the Answer Section
1283  ancount = response->dnsHeader->ancount;
1284 
1285  //Compute the total number of resource records
1286  k = response->dnsHeader->ancount + response->dnsHeader->nscount +
1287  response->dnsHeader->arcount;
1288 
1289  //Loop through the resource records
1290  for(i = 0; i < k; i++)
1291  {
1292  //Parse resource record name
1293  n = dnsParseName(response->dnsHeader, response->length, offset, 0);
1294  //Invalid name?
1295  if(n == 0)
1296  break;
1297 
1298  //Point to the associated resource record
1299  record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n);
1300  //Point to the resource data
1301  n += sizeof(DnsResourceRecord);
1302 
1303  //Make sure the resource record is valid
1304  if(n > response->length)
1305  break;
1306  if((n + ntohs(record->rdlength)) > response->length)
1307  break;
1308 
1309  //Convert the record class to host byte order
1310  rclass = ntohs(record->rclass);
1311  //Discard the cache-flush bit
1313 
1314  //Check the class of the resource record
1315  if(rclass == DNS_RR_CLASS_IN)
1316  {
1317  //A record?
1318  if(ntohs(record->rtype) == DNS_RR_TYPE_A)
1319  {
1320  //When a mDNS responder places an IPv4 address record into a
1321  //response message, it should also place any IPv6 address records
1322  //with the same name into the Additional Section
1323  if(context->ipv6AddrCount > 0)
1324  {
1325  //Generate AAAA resource records
1326  mdnsResponderGenerateIpv6AddrRecords(context, response,
1327  cacheFlush, ttl);
1328  }
1329  else
1330  {
1331  //In the event that a device has only IPv4 addresses but no IPv6
1332  //addresses, then the appropriate NSEC record should be placed
1333  //into the Additional Section
1334  mdnsResponderFormatNsecRecord(context, response, cacheFlush,
1335  ttl);
1336  }
1337  }
1338  //AAAA record?
1339  else if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA)
1340  {
1341  //When a mDNS responder places an IPv6 address record into a
1342  //response message, it should also place any IPv4 address records
1343  //with the same name into the Additional Section
1344  if(context->ipv4AddrCount > 0)
1345  {
1346  //Generate A resource records
1347  mdnsResponderGenerateIpv4AddrRecords(context, response,
1348  cacheFlush, ttl);
1349  }
1350  else
1351  {
1352  //In the event that a device has only IPv6 addresses but no IPv4
1353  //addresses, then the appropriate NSEC record should be placed
1354  //into the Additional Section
1355  mdnsResponderFormatNsecRecord(context, response, cacheFlush,
1356  ttl);
1357  }
1358  }
1359  //SRV record?
1360  else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
1361  {
1362  //Generate A resource records
1363  mdnsResponderGenerateIpv4AddrRecords(context, response,
1364  cacheFlush, ttl);
1365 
1366  //Generate AAAA resource records
1367  mdnsResponderGenerateIpv6AddrRecords(context, response,
1368  cacheFlush, ttl);
1369 
1370  //In the event that a device has only IPv4 addresses but no IPv6
1371  //addresses, or vice versa, then the appropriate NSEC record should
1372  //be placed into the additional section, so that queriers can know
1373  //with certainty that the device has no addresses of that kind
1374  if(context->ipv4AddrCount == 0 || context->ipv6AddrCount == 0)
1375  {
1376  //Generate NSEC resource record
1377  mdnsResponderFormatNsecRecord(context, response, cacheFlush,
1378  ttl);
1379  }
1380  }
1381  }
1382 
1383  //Point to the next resource record
1384  offset = n + ntohs(record->rdlength);
1385  }
1386 
1387  //Number of resource records in the Additional Section
1388  response->dnsHeader->arcount += response->dnsHeader->ancount - ancount;
1389  //Number of resource records in the Answer Section
1390  response->dnsHeader->ancount = ancount;
1391 #endif
1392 }
1393 
1394 
1395 /**
1396  * @brief Generate A resource records
1397  * @param[in] context Pointer to the mDNS responder context
1398  * @param[in,out] message Pointer to the mDNS message
1399  * @param[in] cacheFlush Cache-flush bit
1400  * @param[in] ttl Resource record TTL (cache lifetime)
1401  * @return Error code
1402  **/
1403 
1405  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1406 {
1407 #if (IPV4_SUPPORT == ENABLED)
1408  error_t error;
1409  uint_t i;
1410 
1411  //Initialize status code
1412  error = NO_ERROR;
1413 
1414  //Loop through the list of IPv4 addresses assigned to the interface
1415  for(i = 0; i < IPV4_ADDR_LIST_SIZE && !error; i++)
1416  {
1417  //Valid entry?
1418  if(context->ipv4AddrList[i].valid)
1419  {
1420  //Format A resource record
1421  error = mdnsResponderFormatIpv4AddrRecord(context, message,
1422  context->ipv4AddrList[i].record.rdata, cacheFlush, ttl);
1423  }
1424  }
1425 
1426  //Return status code
1427  return error;
1428 #else
1429  //Not implemented
1430  return NO_ERROR;
1431 #endif
1432 }
1433 
1434 
1435 /**
1436  * @brief Generate AAAA resource records
1437  * @param[in] context Pointer to the mDNS responder context
1438  * @param[in,out] message Pointer to the mDNS message
1439  * @param[in] cacheFlush Cache-flush bit
1440  * @param[in] ttl Resource record TTL (cache lifetime)
1441  * @return Error code
1442  **/
1443 
1445  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1446 {
1447 #if (IPV6_SUPPORT == ENABLED)
1448  error_t error;
1449  uint_t i;
1450 
1451  //Initialize status code
1452  error = NO_ERROR;
1453 
1454  //Loop through the list of IPv6 addresses assigned to the interface
1455  for(i = 0; i < IPV6_ADDR_LIST_SIZE && !error; i++)
1456  {
1457  //Valid entry?
1458  if(context->ipv6AddrList[i].valid)
1459  {
1460  //Format AAAA resource record
1461  error = mdnsResponderFormatIpv6AddrRecord(context, message,
1462  context->ipv6AddrList[i].record.rdata, cacheFlush, ttl);
1463  }
1464  }
1465 
1466  //Return status code
1467  return error;
1468 #else
1469  //Not implemented
1470  return NO_ERROR;
1471 #endif
1472 }
1473 
1474 
1475 /**
1476  * @brief Generate reverse address mapping PTR resource record (IPv4)
1477  * @param[in] context Pointer to the mDNS responder context
1478  * @param[in,out] message Pointer to the mDNS message
1479  * @param[in] cacheFlush Cache-flush bit
1480  * @param[in] ttl Resource record TTL (cache lifetime)
1481  * @return Error code
1482  **/
1483 
1485  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1486 {
1487 #if (IPV4_SUPPORT == ENABLED)
1488  error_t error;
1489  uint_t i;
1490 
1491  //Initialize status code
1492  error = NO_ERROR;
1493 
1494  //Loop through the list of IPv4 addresses assigned to the interface
1495  for(i = 0; i < IPV4_ADDR_LIST_SIZE && !error; i++)
1496  {
1497  //Valid entry?
1498  if(context->ipv4AddrList[i].valid)
1499  {
1500  //Format reverse address mapping PTR resource record (IPv4)
1501  error = mdnsResponderFormatIpv4PtrRecord(context, message,
1502  context->ipv4AddrList[i].reverseName, cacheFlush, ttl);
1503  }
1504  }
1505 
1506  //Return status code
1507  return error;
1508 #else
1509  //Not implemented
1510  return NO_ERROR;
1511 #endif
1512 }
1513 
1514 
1515 /**
1516  * @brief Generate reverse address mapping PTR resource record (IPv6)
1517  * @param[in] context Pointer to the mDNS responder context
1518  * @param[in,out] message Pointer to the mDNS message
1519  * @param[in] cacheFlush Cache-flush bit
1520  * @param[in] ttl Resource record TTL (cache lifetime)
1521  * @return Error code
1522  **/
1523 
1525  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1526 {
1527 #if (IPV6_SUPPORT == ENABLED)
1528  error_t error;
1529  uint_t i;
1530 
1531  //Initialize status code
1532  error = NO_ERROR;
1533 
1534  //Loop through the list of IPv6 addresses assigned to the interface
1535  for(i = 0; i < IPV6_ADDR_LIST_SIZE && !error; i++)
1536  {
1537  //Valid entry?
1538  if(context->ipv6AddrList[i].valid)
1539  {
1540  //Format reverse address mapping PTR resource record (IPv6)
1541  error = mdnsResponderFormatIpv6PtrRecord(context, message,
1542  context->ipv6AddrList[i].reverseName, cacheFlush, ttl);
1543  }
1544  }
1545 
1546  //Return status code
1547  return error;
1548 #else
1549  //Not implemented
1550  return NO_ERROR;
1551 #endif
1552 }
1553 
1554 
1555 /**
1556  * @brief Format A resource record
1557  * @param[in] context Pointer to the mDNS responder context
1558  * @param[in,out] message Pointer to the mDNS message
1559  * @param[in] ipv4Addr Pointer to the IPv4 address
1560  * @param[in] cacheFlush Cache-flush bit
1561  * @param[in] ttl Resource record TTL (cache lifetime)
1562  * @return Error code
1563  **/
1564 
1566  MdnsMessage *message, const uint8_t *ipv4Addr, bool_t cacheFlush,
1567  uint32_t ttl)
1568 {
1569  size_t n;
1570  size_t offset;
1571  bool_t duplicate;
1572  DnsResourceRecord *record;
1573 
1574  //Check whether the resource record is already present in the Answer
1575  //Section of the message
1576  duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
1577  "", ".local", DNS_RR_TYPE_A, ipv4Addr, sizeof(Ipv4Addr));
1578 
1579  //The duplicates should be suppressed and the resource record should
1580  //appear only once in the list
1581  if(!duplicate)
1582  {
1583  //Set the position to the end of the buffer
1584  offset = message->length;
1585 
1586  //The first pass calculates the length of the DNS encoded host name
1587  n = mdnsEncodeName(context->hostname, "", ".local", NULL);
1588 
1589  //Check the length of the resulting mDNS message
1590  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1591  return ERROR_MESSAGE_TOO_LONG;
1592 
1593  //The second pass encodes the host name using the DNS name notation
1594  offset += mdnsEncodeName(context->hostname, "", ".local",
1595  (uint8_t *) message->dnsHeader + offset);
1596 
1597  //Consider the length of the resource record itself
1598  n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
1599 
1600  //Check the length of the resulting mDNS message
1601  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1602  return ERROR_MESSAGE_TOO_LONG;
1603 
1604  //Point to the corresponding resource record
1605  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1606 
1607  //Fill in resource record
1608  record->rtype = HTONS(DNS_RR_TYPE_A);
1609  record->rclass = HTONS(DNS_RR_CLASS_IN);
1610  record->ttl = htonl(ttl);
1611  record->rdlength = HTONS(sizeof(Ipv4Addr));
1612 
1613  //Check whether the cache-flush bit should be set
1614  if(cacheFlush)
1615  {
1616  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1617  }
1618 
1619  //Copy IPv4 address
1620  ipv4CopyAddr(record->rdata, ipv4Addr);
1621 
1622  //Number of resource records in the answer section
1623  message->dnsHeader->ancount++;
1624  //Update the length of the mDNS response message
1625  message->length = offset + n;
1626  }
1627 
1628  //Successful processing
1629  return NO_ERROR;
1630 }
1631 
1632 
1633 /**
1634  * @brief Format AAAA resource record
1635  * @param[in] context Pointer to the mDNS responder context
1636  * @param[in,out] message Pointer to the mDNS message
1637  * @param[in] ipv6Addr Pointer to the IPv6 address
1638  * @param[in] cacheFlush Cache-flush bit
1639  * @param[in] ttl Resource record TTL (cache lifetime)
1640  * @return Error code
1641  **/
1642 
1644  MdnsMessage *message, const uint8_t *ipv6Addr, bool_t cacheFlush,
1645  uint32_t ttl)
1646 {
1647  size_t n;
1648  size_t offset;
1649  bool_t duplicate;
1650  DnsResourceRecord *record;
1651 
1652  //Check whether the resource record is already present in the Answer
1653  //Section of the message
1654  duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
1655  "", ".local", DNS_RR_TYPE_AAAA, ipv6Addr, sizeof(Ipv6Addr));
1656 
1657  //The duplicates should be suppressed and the resource record should
1658  //appear only once in the list
1659  if(!duplicate)
1660  {
1661  //Set the position to the end of the buffer
1662  offset = message->length;
1663 
1664  //The first pass calculates the length of the DNS encoded host name
1665  n = mdnsEncodeName(context->hostname, "", ".local", NULL);
1666 
1667  //Check the length of the resulting mDNS message
1668  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1669  return ERROR_MESSAGE_TOO_LONG;
1670 
1671  //The second pass encodes the host name using the DNS name notation
1672  offset += mdnsEncodeName(context->hostname, "", ".local",
1673  (uint8_t *) message->dnsHeader + offset);
1674 
1675  //Consider the length of the resource record itself
1676  n = sizeof(DnsResourceRecord) + sizeof(Ipv6Addr);
1677 
1678  //Check the length of the resulting mDNS message
1679  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1680  return ERROR_MESSAGE_TOO_LONG;
1681 
1682  //Point to the corresponding resource record
1683  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1684 
1685  //Fill in resource record
1686  record->rtype = HTONS(DNS_RR_TYPE_AAAA);
1687  record->rclass = HTONS(DNS_RR_CLASS_IN);
1688  record->ttl = htonl(ttl);
1689  record->rdlength = HTONS(sizeof(Ipv6Addr));
1690 
1691  //Check whether the cache-flush bit should be set
1692  if(cacheFlush)
1693  {
1694  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1695  }
1696 
1697  //Copy IPv6 address
1698  ipv6CopyAddr(record->rdata, ipv6Addr);
1699 
1700  //Number of resource records in the answer section
1701  message->dnsHeader->ancount++;
1702  //Update the length of the mDNS response message
1703  message->length = offset + n;
1704  }
1705 
1706  //Successful processing
1707  return NO_ERROR;
1708 }
1709 
1710 
1711 /**
1712  * @brief Format reverse address mapping PTR resource record (IPv4)
1713  * @param[in] context Pointer to the mDNS responder context
1714  * @param[in,out] message Pointer to the mDNS message
1715  * @param[in] reverseName Domain name for reverse DNS lookup
1716  * @param[in] cacheFlush Cache-flush bit
1717  * @param[in] ttl Resource record TTL (cache lifetime)
1718  * @return Error code
1719  **/
1720 
1722  MdnsMessage *message, const char_t *reverseName, bool_t cacheFlush,
1723  uint32_t ttl)
1724 {
1725  size_t n;
1726  size_t offset;
1727  bool_t duplicate;
1728  DnsResourceRecord *record;
1729 
1730  //Check whether the resource record is already present in the Answer Section
1731  //of the message
1732  duplicate = mdnsCheckDuplicateRecord(message, reverseName, "in-addr", ".arpa",
1733  DNS_RR_TYPE_PTR, NULL, 0);
1734 
1735  //The duplicates should be suppressed and the resource record should appear
1736  //only once in the list
1737  if(!duplicate)
1738  {
1739  //Set the position to the end of the buffer
1740  offset = message->length;
1741 
1742  //The first pass calculates the length of the DNS encoded reverse name
1743  n = mdnsEncodeName(reverseName, "in-addr", ".arpa", NULL);
1744 
1745  //Check the length of the resulting mDNS message
1746  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1747  return ERROR_MESSAGE_TOO_LONG;
1748 
1749  //The second pass encodes the reverse name using the DNS name notation
1750  offset += mdnsEncodeName(reverseName, "in-addr", ".arpa",
1751  (uint8_t *) message->dnsHeader + offset);
1752 
1753  //Consider the length of the resource record itself
1754  n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
1755 
1756  //Check the length of the resulting mDNS message
1757  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1758  return ERROR_MESSAGE_TOO_LONG;
1759 
1760  //Point to the corresponding resource record
1761  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1762 
1763  //Fill in resource record
1764  record->rtype = HTONS(DNS_RR_TYPE_PTR);
1765  record->rclass = HTONS(DNS_RR_CLASS_IN);
1766  record->ttl = htonl(ttl);
1767 
1768  //Check whether the cache-flush bit should be set
1769  if(cacheFlush)
1770  {
1771  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1772  }
1773 
1774  //Advance write index
1775  offset += sizeof(DnsResourceRecord);
1776 
1777  //The first pass calculates the length of the DNS encoded host name
1778  n = mdnsEncodeName("", context->hostname, ".local", NULL);
1779 
1780  //Check the length of the resulting mDNS message
1781  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1782  return ERROR_MESSAGE_TOO_LONG;
1783 
1784  //The second pass encodes the host name using DNS notation
1785  n = mdnsEncodeName("", context->hostname, ".local", record->rdata);
1786 
1787  //Convert length field to network byte order
1788  record->rdlength = htons(n);
1789 
1790  //Number of resource records in the answer section
1791  message->dnsHeader->ancount++;
1792  //Update the length of the mDNS response message
1793  message->length = offset + n;
1794  }
1795 
1796  //Successful processing
1797  return NO_ERROR;
1798 }
1799 
1800 
1801 /**
1802  * @brief Format reverse address mapping PTR resource record (IPv6)
1803  * @param[in] context Pointer to the mDNS responder context
1804  * @param[in,out] message Pointer to the mDNS message
1805  * @param[in] reverseName Domain name for reverse DNS lookup
1806  * @param[in] cacheFlush Cache-flush bit
1807  * @param[in] ttl Resource record TTL (cache lifetime)
1808  * @return Error code
1809  **/
1810 
1812  MdnsMessage *message, const char_t *reverseName, bool_t cacheFlush,
1813  uint32_t ttl)
1814 {
1815  size_t n;
1816  size_t offset;
1817  bool_t duplicate;
1818  DnsResourceRecord *record;
1819 
1820  //Check whether the resource record is already present in the Answer Section
1821  //of the message
1822  duplicate = mdnsCheckDuplicateRecord(message, reverseName, "ip6", ".arpa",
1823  DNS_RR_TYPE_PTR, NULL, 0);
1824 
1825  //The duplicates should be suppressed and the resource record should appear
1826  //only once in the list
1827  if(!duplicate)
1828  {
1829  //Set the position to the end of the buffer
1830  offset = message->length;
1831 
1832  //The first pass calculates the length of the DNS encoded reverse name
1833  n = mdnsEncodeName(reverseName, "ip6", ".arpa", NULL);
1834 
1835  //Check the length of the resulting mDNS message
1836  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1837  return ERROR_MESSAGE_TOO_LONG;
1838 
1839  //The second pass encodes the reverse name using the DNS name notation
1840  offset += mdnsEncodeName(reverseName, "ip6", ".arpa",
1841  (uint8_t *) message->dnsHeader + offset);
1842 
1843  //Consider the length of the resource record itself
1844  n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr);
1845 
1846  //Check the length of the resulting mDNS message
1847  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1848  return ERROR_MESSAGE_TOO_LONG;
1849 
1850  //Point to the corresponding resource record
1851  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1852 
1853  //Fill in resource record
1854  record->rtype = HTONS(DNS_RR_TYPE_PTR);
1855  record->rclass = HTONS(DNS_RR_CLASS_IN);
1856  record->ttl = htonl(ttl);
1857 
1858  //Check whether the cache-flush bit should be set
1859  if(cacheFlush)
1860  {
1861  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1862  }
1863 
1864  //Advance write index
1865  offset += sizeof(DnsResourceRecord);
1866 
1867  //The first pass calculates the length of the DNS encoded host name
1868  n = mdnsEncodeName("", context->hostname, ".local", NULL);
1869 
1870  //Check the length of the resulting mDNS message
1871  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1872  return ERROR_MESSAGE_TOO_LONG;
1873 
1874  //The second pass encodes the host name using DNS notation
1875  n = mdnsEncodeName("", context->hostname, ".local", record->rdata);
1876 
1877  //Convert length field to network byte order
1878  record->rdlength = htons(n);
1879 
1880  //Number of resource records in the answer section
1881  message->dnsHeader->ancount++;
1882  //Update the length of the mDNS response message
1883  message->length = offset + n;
1884  }
1885 
1886  //Successful processing
1887  return NO_ERROR;
1888 }
1889 
1890 
1891 /**
1892  * @brief Format NSEC resource record
1893  * @param[in] context Pointer to the mDNS responder context
1894  * @param[in,out] message Pointer to the mDNS message
1895  * @param[in] cacheFlush Cache-flush bit
1896  * @param[in] ttl Resource record TTL (cache lifetime)
1897  * @return Error code
1898  **/
1899 
1901  MdnsMessage *message, bool_t cacheFlush, uint32_t ttl)
1902 {
1903  size_t n;
1904  size_t offset;
1905  bool_t duplicate;
1906  size_t bitmapLen;
1907  uint8_t bitmap[8];
1908  DnsResourceRecord *record;
1909 
1910  //Check whether the resource record is already present in the Answer
1911  //Section of the message
1912  duplicate = mdnsCheckDuplicateRecord(message, context->hostname,
1913  "", ".local", DNS_RR_TYPE_NSEC, NULL, 0);
1914 
1915  //The duplicates should be suppressed and the resource record should
1916  //appear only once in the list
1917  if(!duplicate)
1918  {
1919  //The bitmap identifies the resource record types that exist
1920  osMemset(bitmap, 0, sizeof(bitmap));
1921 
1922  //Check whether the host has A records
1923  if(context->ipv4AddrCount > 0)
1924  {
1926  }
1927 
1928  //Check whether the host has AAAA records
1929  if(context->ipv6AddrCount > 0)
1930  {
1932  }
1933 
1934  //Compute the length of the bitmap
1935  for(bitmapLen = sizeof(bitmap); bitmapLen > 0; bitmapLen--)
1936  {
1937  //Trailing zero octets in the bitmap must be omitted
1938  if(bitmap[bitmapLen - 1] != 0)
1939  {
1940  break;
1941  }
1942  }
1943 
1944  //Set the position to the end of the buffer
1945  offset = message->length;
1946 
1947  //The first pass calculates the length of the DNS encoded host name
1948  n = mdnsEncodeName(context->hostname, "", ".local", NULL);
1949 
1950  //Check the length of the resulting mDNS message
1951  if((offset + n) > MDNS_MESSAGE_MAX_SIZE)
1952  return ERROR_MESSAGE_TOO_LONG;
1953 
1954  //The second pass encodes the host name using the DNS name notation
1955  offset += mdnsEncodeName(context->hostname, "", ".local",
1956  (uint8_t *) message->dnsHeader + offset);
1957 
1958  //Consider the length of the resource record itself
1959  if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE)
1960  return ERROR_MESSAGE_TOO_LONG;
1961 
1962  //Point to the corresponding resource record
1963  record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset);
1964 
1965  //Fill in resource record
1966  record->rtype = HTONS(DNS_RR_TYPE_NSEC);
1967  record->rclass = HTONS(DNS_RR_CLASS_IN);
1968  record->ttl = htonl(ttl);
1969 
1970  //Check whether the cache-flush bit should be set
1971  if(cacheFlush)
1972  {
1973  record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH);
1974  }
1975 
1976  //Advance write index
1977  offset += sizeof(DnsResourceRecord);
1978 
1979  //Check the length of the resulting mDNS message
1980  if((offset + n + 2 + bitmapLen) > MDNS_MESSAGE_MAX_SIZE)
1981  return ERROR_MESSAGE_TOO_LONG;
1982 
1983  //The Next Domain Name field contains the record's own name
1984  mdnsEncodeName(context->hostname, "", ".local", record->rdata);
1985 
1986  //DNS NSEC record is limited to Window Block number zero
1987  record->rdata[n++] = 0;
1988  //The Bitmap Length is a value in the range 1-32
1989  record->rdata[n++] = bitmapLen;
1990 
1991  //The Bitmap data identifies the resource record types that exist
1992  osMemcpy(record->rdata + n, bitmap, bitmapLen);
1993 
1994  //Convert length field to network byte order
1995  record->rdlength = htons(n + bitmapLen);
1996 
1997  //Number of resource records in the answer section
1998  message->dnsHeader->ancount++;
1999  //Update the length of the DNS message
2000  message->length = offset + n + bitmapLen;
2001  }
2002 
2003  //Successful processing
2004  return NO_ERROR;
2005 }
2006 
2007 
2008 /**
2009  * @brief Sort the host records in lexicographical order
2010  * @param[in] context Pointer to the mDNS responder context
2011  * @param[in] record Pointer to the current record
2012  * @return Pointer to the next record, if any
2013  **/
2014 
2016  DnsResourceRecord *record)
2017 {
2018  uint_t i;
2019  int_t res;
2020  DnsResourceRecord *curRecord;
2021  DnsResourceRecord *nextRecord;
2022 
2023  //Initialize record pointer
2024  nextRecord = NULL;
2025 
2026 #if (IPV4_SUPPORT == ENABLED)
2027  //Loop through the list of IPv4 addresses assigned to the interface
2028  for(i = 0; i < IPV4_ADDR_LIST_SIZE; i++)
2029  {
2030  //Valid IPv4 address?
2031  if(context->ipv4AddrList[i].valid)
2032  {
2033  //Point to the A resource record
2034  curRecord = (DnsResourceRecord *) &context->ipv4AddrList[i].record;
2035 
2036  //Perform lexicographical comparison
2037  if(record != NULL)
2038  {
2039  res = mdnsCompareRecord(NULL, curRecord, NULL, record);
2040  }
2041  else
2042  {
2043  res = 1;
2044  }
2045 
2046  //Check whether the record is lexicographically later
2047  if(res > 0)
2048  {
2049  if(nextRecord == NULL)
2050  {
2051  nextRecord = curRecord;
2052  }
2053  else if(mdnsCompareRecord(NULL, curRecord, NULL, nextRecord) < 0)
2054  {
2055  nextRecord = curRecord;
2056  }
2057  }
2058  }
2059  }
2060 #endif
2061 
2062 #if (IPV6_SUPPORT == ENABLED)
2063  //Loop through the list of IPv6 addresses assigned to the interface
2064  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
2065  {
2066  //Valid IPv6 address?
2067  if(context->ipv6AddrList[i].valid)
2068  {
2069  //Point to the AAAA resource record
2070  curRecord = (DnsResourceRecord *) &context->ipv6AddrList[i].record;
2071 
2072  //Perform lexicographical comparison
2073  if(record != NULL)
2074  {
2075  res = mdnsCompareRecord(NULL, curRecord, NULL, record);
2076  }
2077  else
2078  {
2079  res = 1;
2080  }
2081 
2082  //Check whether the record is lexicographically later
2083  if(res > 0)
2084  {
2085  if(nextRecord == NULL)
2086  {
2087  nextRecord = curRecord;
2088  }
2089  else if(mdnsCompareRecord(NULL, curRecord, NULL, nextRecord) < 0)
2090  {
2091  nextRecord = curRecord;
2092  }
2093  }
2094  }
2095  }
2096 #endif
2097 
2098  //Return the pointer to the next record
2099  return nextRecord;
2100 }
2101 
2102 
2103 /**
2104  * @brief Sort the tiebreaker records in lexicographical order
2105  * @param[in] context Pointer to the mDNS responder context
2106  * @param[in] query Incoming mDNS query message
2107  * @param[in] offset Offset to first byte of the Authority Section
2108  * @param[in] record Pointer to the current record
2109  * @return Pointer to the next record, if any
2110  **/
2111 
2113  const MdnsMessage *query, size_t offset, DnsResourceRecord *record)
2114 {
2115  uint_t i;
2116  size_t n;
2117  int_t res;
2118  DnsResourceRecord *curRecord;
2119  DnsResourceRecord *nextRecord;
2120 
2121  //Initialize record pointer
2122  nextRecord = NULL;
2123 
2124  //Parse Authority Section
2125  for(i = 0; i < ntohs(query->dnsHeader->nscount); i++)
2126  {
2127  //Parse resource record name
2128  n = dnsParseName(query->dnsHeader, query->length, offset, 0);
2129  //Invalid name?
2130  if(n == 0)
2131  break;
2132 
2133  //Point to the associated resource record
2134  curRecord = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n);
2135  //Point to the resource data
2136  n += sizeof(DnsResourceRecord);
2137 
2138  //Make sure the resource record is valid
2139  if(n > query->length)
2140  break;
2141  if((n + ntohs(curRecord->rdlength)) > query->length)
2142  break;
2143 
2144  //Matching host name?
2145  if(!mdnsCompareName(query->dnsHeader, query->length, offset,
2146  context->hostname, "", ".local", 0))
2147  {
2148  //Perform lexicographical comparison
2149  if(record != NULL)
2150  {
2151  res = mdnsCompareRecord(query, curRecord, query, record);
2152  }
2153  else
2154  {
2155  res = 1;
2156  }
2157 
2158  //Check whether the record is lexicographically later
2159  if(res > 0)
2160  {
2161  if(nextRecord == NULL)
2162  {
2163  nextRecord = curRecord;
2164  }
2165  else if(mdnsCompareRecord(query, curRecord, query, nextRecord) < 0)
2166  {
2167  nextRecord = curRecord;
2168  }
2169  }
2170  }
2171 
2172  //Point to the next resource record
2173  offset = n + ntohs(curRecord->rdlength);
2174  }
2175 
2176  //Return the pointer to the next record
2177  return nextRecord;
2178 }
2179 
2180 #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
int bool_t
Definition: compiler_port.h:63
@ DNS_RR_CLASS_ANY
Any class.
Definition: dns_common.h:129
const Ipv6Addr MDNS_IPV6_MULTICAST_ADDR
Definition: mdns_common.c:59
size_t dnsParseName(const DnsHeader *message, size_t length, size_t pos, uint_t level)
Decode a domain name that uses the DNS name encoding.
Definition: dns_common.c:131
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:94
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:68
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:925
error_t dnsSdResponderParseQuestion(NetInterface *interface, const MdnsMessage *query, size_t offset, const DnsQuestion *question, MdnsMessage *response)
Parse a question.
Ipv6Addr
Definition: ipv6.h:282
@ DNS_RR_TYPE_NSEC
NSEC record.
Definition: dns_common.h:155
DnsHeader * dnsHeader
Definition: mdns_common.h:84
uint16_t rclass
Definition: dns_common.h:225
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:136
@ DNS_RR_CLASS_IN
Internet.
Definition: dns_common.h:126
DnsHeader
Definition: dns_common.h:204
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:171
const uint8_t res[]
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:324
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:160
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:147
error_t
Error codes.
Definition: error.h:43
#define DNS_GET_QUESTION(message, offset)
Definition: dns_common.h:65
#define osSprintf(dest,...)
Definition: os_port.h:237
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:66
void mdnsResponderChangeHostname(MdnsResponderContext *context)
Programmatically change the host name.
#define Ipv6PseudoHeader
Definition: ipv6.h:44
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:214
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:139
uint32_t netGenerateRandRange(NetContext *context, uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:989
@ DNS_RR_TYPE_PTR
Domain name pointer.
Definition: dns_common.h:144
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:200
#define osIsdigit(c)
Definition: os_port.h:291
#define Ipv4PseudoHeader
Definition: ipv4.h:40
#define IPV4_ADDR_LIST_SIZE
Definition: ipv4.h:81
@ 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:319
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:812
#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:225
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:132
#define ipv4CompAddr(ipAddr1, ipAddr2)
Definition: ipv4.h:171
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:74
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:215
#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:167
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:152
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:226
#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:141
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:229
#define MDNS_DEFAULT_RR_TTL
Definition: mdns_common.h:47
@ DNS_RR_TYPE_AAAA
IPv6 address.
Definition: dns_common.h:149
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
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:153
#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