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