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