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