Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
mdns_responder.c
Go to the documentation of this file.
00001 /** 00002 * @file mdns_responder.c 00003 * @brief mDNS responder (Multicast DNS) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL MDNS_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <stdlib.h> 00034 #include <ctype.h> 00035 #include "core/net.h" 00036 #include "mdns/mdns_responder.h" 00037 #include "mdns/mdns_common.h" 00038 #include "dns/dns_debug.h" 00039 #include "dns_sd/dns_sd.h" 00040 #include "str.h" 00041 #include "debug.h" 00042 00043 //Check TCP/IP stack configuration 00044 #if (MDNS_RESPONDER_SUPPORT == ENABLED) 00045 00046 //Tick counter to handle periodic operations 00047 systime_t mdnsResponderTickCounter; 00048 00049 00050 /** 00051 * @brief Initialize settings with default values 00052 * @param[out] settings Structure that contains mDNS responder settings 00053 **/ 00054 00055 void mdnsResponderGetDefaultSettings(MdnsResponderSettings *settings) 00056 { 00057 //Use default interface 00058 settings->interface = netGetDefaultInterface(); 00059 00060 //Number of announcement packets 00061 settings->numAnnouncements = MDNS_ANNOUNCE_NUM; 00062 //TTL resource record 00063 settings->ttl = MDNS_DEFAULT_RR_TTL; 00064 //FSM state change event 00065 settings->stateChangeEvent = NULL; 00066 } 00067 00068 00069 /** 00070 * @brief mDNS responder initialization 00071 * @param[in] context Pointer to the mDNS responder context 00072 * @param[in] settings mDNS responder specific settings 00073 * @return Error code 00074 **/ 00075 00076 error_t mdnsResponderInit(MdnsResponderContext *context, 00077 const MdnsResponderSettings *settings) 00078 { 00079 NetInterface *interface; 00080 00081 //Debug message 00082 TRACE_INFO("Initializing mDNS responder...\r\n"); 00083 00084 //Ensure the parameters are valid 00085 if(context == NULL || settings == NULL) 00086 return ERROR_INVALID_PARAMETER; 00087 00088 //Invalid network interface? 00089 if(settings->interface == NULL) 00090 return ERROR_INVALID_PARAMETER; 00091 00092 //Point to the underlying network interface 00093 interface = settings->interface; 00094 00095 //Clear the mDNS responder context 00096 memset(context, 0, sizeof(MdnsResponderContext)); 00097 //Save user settings 00098 context->settings = *settings; 00099 00100 //mDNS responder is currently suspended 00101 context->running = FALSE; 00102 //Initialize state machine 00103 context->state = MDNS_STATE_INIT; 00104 00105 //Attach the mDNS responder context to the network interface 00106 interface->mdnsResponderContext = context; 00107 00108 //Successful initialization 00109 return NO_ERROR; 00110 } 00111 00112 00113 /** 00114 * @brief Start mDNS responder 00115 * @param[in] context Pointer to the mDNS responder context 00116 * @return Error code 00117 **/ 00118 00119 error_t mdnsResponderStart(MdnsResponderContext *context) 00120 { 00121 //Check parameter 00122 if(context == NULL) 00123 return ERROR_INVALID_PARAMETER; 00124 00125 //Debug message 00126 TRACE_INFO("Starting mDNS responder...\r\n"); 00127 00128 //Get exclusive access 00129 osAcquireMutex(&netMutex); 00130 00131 //Start mDNS responder 00132 context->running = TRUE; 00133 //Initialize state machine 00134 context->state = MDNS_STATE_INIT; 00135 00136 //Release exclusive access 00137 osReleaseMutex(&netMutex); 00138 00139 //Successful processing 00140 return NO_ERROR; 00141 } 00142 00143 00144 /** 00145 * @brief Stop mDNS responder 00146 * @param[in] context Pointer to the mDNS responder context 00147 * @return Error code 00148 **/ 00149 00150 error_t mdnsResponderStop(MdnsResponderContext *context) 00151 { 00152 //Check parameter 00153 if(context == NULL) 00154 return ERROR_INVALID_PARAMETER; 00155 00156 //Debug message 00157 TRACE_INFO("Stopping mDNS responder...\r\n"); 00158 00159 //Get exclusive access 00160 osAcquireMutex(&netMutex); 00161 00162 //Suspend mDNS responder 00163 context->running = FALSE; 00164 //Reinitialize state machine 00165 context->state = MDNS_STATE_INIT; 00166 00167 //Release exclusive access 00168 osReleaseMutex(&netMutex); 00169 00170 //Successful processing 00171 return NO_ERROR; 00172 } 00173 00174 00175 /** 00176 * @brief Retrieve current state 00177 * @param[in] context Pointer to the mDNS responder context 00178 * @return Current mDNS responder state 00179 **/ 00180 00181 MdnsState mdnsResponderGetState(MdnsResponderContext *context) 00182 { 00183 MdnsState state; 00184 00185 //Get exclusive access 00186 osAcquireMutex(&netMutex); 00187 //Get current state 00188 state = context->state; 00189 //Release exclusive access 00190 osReleaseMutex(&netMutex); 00191 00192 //Return current state 00193 return state; 00194 } 00195 00196 00197 /** 00198 * @brief Set hostname 00199 * @param[in] context Pointer to the mDNS responder context 00200 * @param[in] hostname NULL-terminated string that contains the hostname 00201 * @return Error code 00202 **/ 00203 00204 error_t mdnsResponderSetHostname(MdnsResponderContext *context, 00205 const char_t *hostname) 00206 { 00207 NetInterface *interface; 00208 00209 //Check parameters 00210 if(context == NULL || hostname == NULL) 00211 return ERROR_INVALID_PARAMETER; 00212 00213 //Get exclusive access 00214 osAcquireMutex(&netMutex); 00215 00216 //Point to the underlying network interface 00217 interface = context->settings.interface; 00218 00219 //Check whether a hostname is already assigned 00220 if(context->hostname[0] != '\0') 00221 { 00222 //Check whether the link is up 00223 if(interface->linkState) 00224 { 00225 //Send a goodbye packet 00226 mdnsResponderSendGoodbye(context); 00227 } 00228 } 00229 00230 //Set hostname 00231 strSafeCopy(context->hostname, hostname, 00232 MDNS_RESPONDER_MAX_HOSTNAME_LEN); 00233 00234 //Restart probing process (hostname) 00235 mdnsResponderStartProbing(interface->mdnsResponderContext); 00236 00237 #if (DNS_SD_SUPPORT == ENABLED) 00238 //Restart probing process (service instance name) 00239 dnsSdStartProbing(interface->dnsSdContext); 00240 #endif 00241 00242 //Release exclusive access 00243 osReleaseMutex(&netMutex); 00244 00245 //Successful processing 00246 return NO_ERROR; 00247 } 00248 00249 00250 /** 00251 * @brief Generate domain name for reverse DNS lookup (IPv4) 00252 * @param[in] context Pointer to the mDNS responder context 00253 * @return Error code 00254 **/ 00255 00256 error_t mdnsResponderSetIpv4ReverseName(MdnsResponderContext *context) 00257 { 00258 #if (IPV4_SUPPORT == ENABLED) 00259 uint8_t *addr; 00260 NetInterface *interface; 00261 00262 //Check whether the mDNS responder has been properly instantiated 00263 if(context == NULL) 00264 return ERROR_INVALID_PARAMETER; 00265 00266 //Point to the underlying network interface 00267 interface = context->settings.interface; 00268 00269 //Check whether the host address is valid 00270 if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID) 00271 { 00272 //Cast the IPv4 address as byte array 00273 addr = (uint8_t *) &interface->ipv4Context.addr; 00274 00275 //Generate the domain name for reverse DNS lookup 00276 sprintf(context->ipv4ReverseName, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8, 00277 addr[3], addr[2], addr[1], addr[0]); 00278 } 00279 else 00280 { 00281 //The host address is not valid 00282 context->ipv4ReverseName[0] = '\0'; 00283 } 00284 #endif 00285 00286 //Successful processing 00287 return NO_ERROR; 00288 } 00289 00290 00291 /** 00292 * @brief Generate domain name for reverse DNS lookup (IPv6) 00293 * @param[in] context Pointer to the mDNS responder context 00294 * @return Error code 00295 **/ 00296 00297 error_t mdnsResponderSetIpv6ReverseName(MdnsResponderContext *context) 00298 { 00299 #if (IPV6_SUPPORT == ENABLED) 00300 uint_t i; 00301 uint_t m; 00302 uint_t n; 00303 char_t *p; 00304 uint8_t *addr; 00305 NetInterface *interface; 00306 00307 //Check whether the mDNS responder has been properly instantiated 00308 if(context == NULL) 00309 return ERROR_INVALID_PARAMETER; 00310 00311 //Point to the underlying network interface 00312 interface = context->settings.interface; 00313 00314 //Point to the buffer where to format the reverse name 00315 p = context->ipv6ReverseName; 00316 00317 //Check whether the link-local address is valid 00318 if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED) 00319 { 00320 //Cast the IPv4 address as byte array 00321 addr = interface->ipv6Context.addrList[0].addr.b; 00322 00323 //Generate the domain name for reverse DNS lookup 00324 for(i = 0; i < 32; i++) 00325 { 00326 //Calculate the shift count 00327 n = (31 - i) / 2; 00328 m = (i % 2) * 4; 00329 00330 //Format the current digit 00331 p += sprintf(p, "%" PRIx8, (addr[n] >> m) & 0x0F); 00332 00333 //Add a delimiter character 00334 if(i != 31) 00335 p += sprintf(p, "."); 00336 } 00337 } 00338 else 00339 { 00340 //The link-local address is not valid 00341 p[0] = '\0'; 00342 } 00343 #endif 00344 00345 //Successful processing 00346 return NO_ERROR; 00347 } 00348 00349 00350 /** 00351 * @brief Restart probing process 00352 * @param[in] context Pointer to the mDNS responder context 00353 * @return Error code 00354 **/ 00355 00356 error_t mdnsResponderStartProbing(MdnsResponderContext *context) 00357 { 00358 //Check whether the mDNS responder has been properly instantiated 00359 if(context == NULL) 00360 return ERROR_INVALID_PARAMETER; 00361 00362 //Generate domain names for reverse DNS lookup 00363 mdnsResponderSetIpv4ReverseName(context); 00364 mdnsResponderSetIpv6ReverseName(context); 00365 00366 //Force mDNS responder to start probing again 00367 context->state = MDNS_STATE_INIT; 00368 00369 //Successful processing 00370 return NO_ERROR; 00371 } 00372 00373 00374 /** 00375 * @brief mDNS responder timer handler 00376 * 00377 * This routine must be periodically called by the TCP/IP stack to 00378 * manage mDNS operation 00379 * 00380 * @param[in] context Pointer to the mDNS responder context 00381 **/ 00382 00383 void mdnsResponderTick(MdnsResponderContext *context) 00384 { 00385 bool_t valid; 00386 systime_t time; 00387 systime_t delay; 00388 NetInterface *interface; 00389 IpAddr destIpAddr; 00390 00391 //Make sure the mDNS responder has been properly instantiated 00392 if(context == NULL) 00393 return; 00394 00395 //Point to the underlying network interface 00396 interface = context->settings.interface; 00397 00398 //Get current time 00399 time = osGetSystemTime(); 00400 00401 //Check current state 00402 if(context->state == MDNS_STATE_INIT) 00403 { 00404 //Check whether a hostname has been assigned 00405 if(context->hostname[0] != '\0') 00406 { 00407 //Make sure that the link is up 00408 if(interface->linkState) 00409 { 00410 //Clear flag 00411 valid = FALSE; 00412 00413 #if (IPV4_SUPPORT == ENABLED) 00414 //Check whether the IPv4 host address is valid 00415 if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID) 00416 valid = TRUE; 00417 #endif 00418 00419 #if (IPV6_SUPPORT == ENABLED) 00420 //Check whether the IPv6 link-local address is valid 00421 if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED) 00422 valid = TRUE; 00423 #endif 00424 //Any valid IP address assigned to the network interface? 00425 if(valid) 00426 { 00427 //Wait until both IPv4 and IPv6 addresses are valid 00428 mdnsResponderChangeState(context, MDNS_STATE_WAITING, 0); 00429 } 00430 } 00431 } 00432 } 00433 else if(context->state == MDNS_STATE_WAITING) 00434 { 00435 //Set flag 00436 valid = TRUE; 00437 00438 //Check current time 00439 if(timeCompare(time, context->timestamp + MDNS_MAX_WAITING_DELAY) < 0) 00440 { 00441 #if (IPV4_SUPPORT == ENABLED) 00442 //Check whether the IPv4 host address is valid 00443 if(interface->ipv4Context.addrState != IPV4_ADDR_STATE_VALID) 00444 valid = FALSE; 00445 #endif 00446 00447 #if (IPV6_SUPPORT == ENABLED) 00448 //Check whether the IPv6 link-local address is valid 00449 if(ipv6GetLinkLocalAddrState(interface) != IPV6_ADDR_STATE_PREFERRED) 00450 valid = FALSE; 00451 #endif 00452 } 00453 00454 //Start probing? 00455 if(valid) 00456 { 00457 //Initial random delay 00458 delay = netGetRandRange(MDNS_RAND_DELAY_MIN, MDNS_RAND_DELAY_MAX); 00459 //Perform probing 00460 mdnsResponderChangeState(context, MDNS_STATE_PROBING, delay); 00461 } 00462 } 00463 else if(context->state == MDNS_STATE_PROBING) 00464 { 00465 //Probing failed? 00466 if(context->conflict && context->retransmitCount > 0) 00467 { 00468 //Programmatically change the host name 00469 mdnsResponderChangeHostname(context); 00470 //Probe again, and repeat as necessary until a unique name is found 00471 mdnsResponderChangeState(context, MDNS_STATE_PROBING, 0); 00472 } 00473 //Tie-break lost? 00474 else if(context->tieBreakLost && context->retransmitCount > 0) 00475 { 00476 //The host defers to the winning host by waiting one second, and 00477 //then begins probing for this record again 00478 mdnsResponderChangeState(context, MDNS_STATE_PROBING, MDNS_PROBE_DEFER); 00479 } 00480 else 00481 { 00482 //Check current time 00483 if(timeCompare(time, context->timestamp + context->timeout) >= 0) 00484 { 00485 //Probing is on-going? 00486 if(context->retransmitCount < MDNS_PROBE_NUM) 00487 { 00488 //First probe? 00489 if(context->retransmitCount == 0) 00490 { 00491 //Apparently conflicting mDNS responses received before the 00492 //first probe packet is sent must be silently ignored 00493 context->conflict = FALSE; 00494 context->tieBreakLost = FALSE; 00495 } 00496 00497 //Send probe packet 00498 mdnsResponderSendProbe(context); 00499 00500 //Save the time at which the packet was sent 00501 context->timestamp = time; 00502 //Time interval between subsequent probe packets 00503 context->timeout = MDNS_PROBE_DELAY; 00504 //Increment retransmission counter 00505 context->retransmitCount++; 00506 } 00507 //Probing is complete? 00508 else 00509 { 00510 //The mDNS responder must send unsolicited mDNS responses 00511 //containing all of its newly registered resource records 00512 if(context->settings.numAnnouncements > 0) 00513 mdnsResponderChangeState(context, MDNS_STATE_ANNOUNCING, 0); 00514 else 00515 mdnsResponderChangeState(context, MDNS_STATE_IDLE, 0); 00516 } 00517 } 00518 } 00519 } 00520 else if(context->state == MDNS_STATE_ANNOUNCING) 00521 { 00522 //Whenever a mDNS responder receives any mDNS response (solicited or 00523 //otherwise) containing a conflicting resource record, the conflict 00524 //must be resolved 00525 if(context->conflict) 00526 { 00527 //Probe again, and repeat as necessary until a unique name is found 00528 mdnsResponderChangeState(context, MDNS_STATE_PROBING, 0); 00529 } 00530 else 00531 { 00532 //Check current time 00533 if(timeCompare(time, context->timestamp + context->timeout) >= 0) 00534 { 00535 //Send announcement packet 00536 mdnsResponderSendAnnouncement(context); 00537 00538 //Save the time at which the packet was sent 00539 context->timestamp = time; 00540 //Increment retransmission counter 00541 context->retransmitCount++; 00542 00543 //First announcement packet? 00544 if(context->retransmitCount == 1) 00545 { 00546 //The mDNS responder must send at least two unsolicited 00547 //responses, one second apart 00548 context->timeout = MDNS_ANNOUNCE_DELAY; 00549 } 00550 else 00551 { 00552 //To provide increased robustness against packet loss, a mDNS 00553 //responder may send up to eight unsolicited responses, provided 00554 //that the interval between unsolicited responses increases by 00555 //at least a factor of two with every response sent 00556 context->timeout *= 2; 00557 } 00558 00559 //Last announcement packet? 00560 if(context->retransmitCount >= context->settings.numAnnouncements) 00561 { 00562 //A mDNS responder must not send regular periodic announcements 00563 mdnsResponderChangeState(context, MDNS_STATE_IDLE, 0); 00564 } 00565 } 00566 } 00567 } 00568 else if(context->state == MDNS_STATE_IDLE) 00569 { 00570 //Whenever a mDNS responder receives any mDNS response (solicited or 00571 //otherwise) containing a conflicting resource record, the conflict 00572 //must be resolved 00573 if(context->conflict) 00574 { 00575 //Probe again, and repeat as necessary until a unique name is found 00576 mdnsResponderChangeState(context, MDNS_STATE_PROBING, 0); 00577 } 00578 } 00579 00580 #if (IPV4_SUPPORT == ENABLED) 00581 //Any response message pending to be sent? 00582 if(context->ipv4Response.buffer != NULL) 00583 { 00584 //Check whether the time delay has elapsed 00585 if(timeCompare(time, context->ipv4Response.timestamp + 00586 context->ipv4Response.timeout) >= 0) 00587 { 00588 #if (DNS_SD_SUPPORT == ENABLED) 00589 //Additional record generation (DNS-SD) 00590 dnsSdGenerateAdditionalRecords(interface, 00591 &context->ipv4Response, FALSE); 00592 #endif 00593 //Additional record generation (mDNS) 00594 mdnsResponderGenerateAdditionalRecords(interface, 00595 &context->ipv4Response, FALSE); 00596 00597 //Use mDNS IPv4 multicast address 00598 destIpAddr.length = sizeof(Ipv4Addr); 00599 destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; 00600 00601 //Send mDNS response message 00602 mdnsSendMessage(interface, &context->ipv4Response, 00603 &destIpAddr, MDNS_PORT); 00604 00605 //Free previously allocated memory 00606 mdnsDeleteMessage(&context->ipv4Response); 00607 } 00608 } 00609 #endif 00610 00611 #if (IPV6_SUPPORT == ENABLED) 00612 //Any response message pending to be sent? 00613 if(context->ipv6Response.buffer != NULL) 00614 { 00615 //Check whether the time delay has elapsed 00616 if(timeCompare(time, context->ipv6Response.timestamp + 00617 context->ipv6Response.timeout) >= 0) 00618 { 00619 #if (DNS_SD_SUPPORT == ENABLED) 00620 //Additional record generation (DNS-SD) 00621 dnsSdGenerateAdditionalRecords(interface, 00622 &context->ipv6Response, FALSE); 00623 #endif 00624 //Additional record generation (mDNS) 00625 mdnsResponderGenerateAdditionalRecords(interface, 00626 &context->ipv6Response, FALSE); 00627 00628 //Use mDNS IPv6 multicast address 00629 destIpAddr.length = sizeof(Ipv6Addr); 00630 destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; 00631 00632 //Send mDNS response message 00633 mdnsSendMessage(interface, &context->ipv6Response, 00634 &destIpAddr, MDNS_PORT); 00635 00636 //Free previously allocated memory 00637 mdnsDeleteMessage(&context->ipv6Response); 00638 } 00639 } 00640 #endif 00641 } 00642 00643 00644 /** 00645 * @brief Callback function for link change event 00646 * @param[in] context Pointer to the mDNS responder context 00647 **/ 00648 00649 void mdnsResponderLinkChangeEvent(MdnsResponderContext *context) 00650 { 00651 //Make sure the mDNS responder has been properly instantiated 00652 if(context == NULL) 00653 return; 00654 00655 #if (IPV4_SUPPORT == ENABLED) 00656 //Free any response message pending to be sent 00657 mdnsDeleteMessage(&context->ipv4Response); 00658 #endif 00659 00660 #if (IPV6_SUPPORT == ENABLED) 00661 //Free any response message pending to be sent 00662 mdnsDeleteMessage(&context->ipv6Response); 00663 #endif 00664 00665 //Whenever a mDNS responder receives an indication of a link 00666 //change event, it must perform probing and announcing 00667 mdnsResponderChangeState(context, MDNS_STATE_INIT, 0); 00668 } 00669 00670 00671 /** 00672 * @brief Update FSM state 00673 * @param[in] context Pointer to the mDNS responder context 00674 * @param[in] newState New state to switch to 00675 * @param[in] delay Initial delay 00676 **/ 00677 00678 void mdnsResponderChangeState(MdnsResponderContext *context, 00679 MdnsState newState, systime_t delay) 00680 { 00681 NetInterface *interface; 00682 00683 //Point to the underlying network interface 00684 interface = context->settings.interface; 00685 00686 //Set time stamp 00687 context->timestamp = osGetSystemTime(); 00688 //Set initial delay 00689 context->timeout = delay; 00690 //Reset retransmission counter 00691 context->retransmitCount = 0; 00692 //Switch to the new state 00693 context->state = newState; 00694 00695 //Any registered callback? 00696 if(context->settings.stateChangeEvent != NULL) 00697 { 00698 //Release exclusive access 00699 osReleaseMutex(&netMutex); 00700 //Invoke user callback function 00701 context->settings.stateChangeEvent(context, interface, newState); 00702 //Get exclusive access 00703 osAcquireMutex(&netMutex); 00704 } 00705 } 00706 00707 00708 /** 00709 * @brief Programmatically change the host name 00710 * @param[in] context Pointer to the mDNS responder context 00711 **/ 00712 00713 void mdnsResponderChangeHostname(MdnsResponderContext *context) 00714 { 00715 size_t i; 00716 size_t m; 00717 size_t n; 00718 uint32_t index; 00719 char_t s[16]; 00720 00721 //Retrieve the length of the string 00722 n = strlen(context->hostname); 00723 00724 //Parse the string backwards 00725 for(i = n; i > 0; i--) 00726 { 00727 //Check whether the current character is a digit 00728 if(!isdigit((uint8_t) context->hostname[i - 1])) 00729 break; 00730 } 00731 00732 //Any number following the host name? 00733 if(context->hostname[i] != '\0') 00734 { 00735 //Retrieve the number at the end of the name 00736 index = atoi(context->hostname + i); 00737 //Increment the value 00738 index++; 00739 00740 //Strip the digits 00741 context->hostname[i] = '\0'; 00742 } 00743 else 00744 { 00745 //Append the digit "2" to the name 00746 index = 2; 00747 } 00748 00749 //Convert the number to a string of characters 00750 m = sprintf(s, "%" PRIu32, index); 00751 00752 //Sanity check 00753 if((i + m) <= NET_MAX_HOSTNAME_LEN) 00754 { 00755 //Add padding if necessary 00756 while((i + m) < n) 00757 context->hostname[i++] = '0'; 00758 00759 //Properly terminate the string 00760 context->hostname[i] = '\0'; 00761 //Programmatically change the host name 00762 strcat(context->hostname, s); 00763 } 00764 } 00765 00766 00767 /** 00768 * @brief Send probe packet 00769 * @param[in] context Pointer to the mDNS responder context 00770 * @return Error code 00771 **/ 00772 00773 error_t mdnsResponderSendProbe(MdnsResponderContext *context) 00774 { 00775 error_t error; 00776 NetInterface *interface; 00777 DnsQuestion *dnsQuestion; 00778 MdnsMessage message; 00779 00780 //Point to the underlying network interface 00781 interface = context->settings.interface; 00782 00783 //Create an empty mDNS query message 00784 error = mdnsCreateMessage(&message, FALSE); 00785 //Any error to report? 00786 if(error) 00787 return error; 00788 00789 //Start of exception handling block 00790 do 00791 { 00792 //Encode the host name using the DNS name notation 00793 message.length += mdnsEncodeName(context->hostname, "", 00794 ".local", message.dnsHeader->questions); 00795 00796 //Point to the corresponding question structure 00797 dnsQuestion = DNS_GET_QUESTION(message.dnsHeader, message.length); 00798 00799 //The probes should be sent as QU questions with the unicast-response 00800 //bit set, to allow a defending host to respond immediately via unicast 00801 dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY); 00802 dnsQuestion->qclass = HTONS(MDNS_QCLASS_QU | DNS_RR_CLASS_IN); 00803 00804 //Update the length of the mDNS query message 00805 message.length += sizeof(DnsQuestion); 00806 00807 //Format A resource record 00808 error = mdnsResponderAddIpv4AddrRecord(interface, 00809 &message, FALSE, MDNS_DEFAULT_RR_TTL); 00810 //Any error to report? 00811 if(error) 00812 break; 00813 00814 //Format AAAA resource record 00815 error = mdnsResponderAddIpv6AddrRecord(interface, 00816 &message, FALSE, MDNS_DEFAULT_RR_TTL); 00817 //Any error to report? 00818 if(error) 00819 break; 00820 00821 //Number of questions in the Question Section 00822 message.dnsHeader->qdcount = 1; 00823 //Number of resource records in the Authority Section 00824 message.dnsHeader->nscount = message.dnsHeader->ancount; 00825 //Number of resource records in the Answer Section 00826 message.dnsHeader->ancount = 0; 00827 00828 //Send mDNS message 00829 error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT); 00830 00831 //End of exception handling block 00832 } while(0); 00833 00834 //Free previously allocated memory 00835 mdnsDeleteMessage(&message); 00836 00837 //Return status code 00838 return error; 00839 } 00840 00841 00842 /** 00843 * @brief Send announcement packet 00844 * @param[in] context Pointer to the mDNS responder context 00845 * @return Error code 00846 **/ 00847 00848 error_t mdnsResponderSendAnnouncement(MdnsResponderContext *context) 00849 { 00850 error_t error; 00851 NetInterface *interface; 00852 MdnsMessage message; 00853 00854 //Point to the underlying network interface 00855 interface = context->settings.interface; 00856 00857 //Create an empty mDNS response message 00858 error = mdnsCreateMessage(&message, TRUE); 00859 //Any error to report? 00860 if(error) 00861 return error; 00862 00863 //Start of exception handling block 00864 do 00865 { 00866 //Format A resource record 00867 error = mdnsResponderAddIpv4AddrRecord(interface, 00868 &message, TRUE, MDNS_DEFAULT_RR_TTL); 00869 //Any error to report? 00870 if(error) 00871 break; 00872 00873 //Format reverse address mapping PTR record (IPv4) 00874 error = mdnsResponderAddIpv4ReversePtrRecord(interface, 00875 &message, TRUE, MDNS_DEFAULT_RR_TTL); 00876 //Any error to report? 00877 if(error) 00878 break; 00879 00880 //Format AAAA resource record 00881 error = mdnsResponderAddIpv6AddrRecord(interface, 00882 &message, TRUE, MDNS_DEFAULT_RR_TTL); 00883 //Any error to report? 00884 if(error) 00885 break; 00886 00887 //Format reverse address mapping PTR record (IPv6) 00888 error = mdnsResponderAddIpv6ReversePtrRecord(interface, 00889 &message, TRUE, MDNS_DEFAULT_RR_TTL); 00890 //Any error to report? 00891 if(error) 00892 break; 00893 00894 //Send mDNS message 00895 error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT); 00896 00897 //End of exception handling block 00898 } while(0); 00899 00900 //Free previously allocated memory 00901 mdnsDeleteMessage(&message); 00902 00903 //Return status code 00904 return error; 00905 } 00906 00907 00908 /** 00909 * @brief Send goodbye packet 00910 * @param[in] context Pointer to the mDNS responder context 00911 * @return Error code 00912 **/ 00913 00914 error_t mdnsResponderSendGoodbye(MdnsResponderContext *context) 00915 { 00916 error_t error; 00917 NetInterface *interface; 00918 MdnsMessage message; 00919 00920 //Point to the underlying network interface 00921 interface = context->settings.interface; 00922 00923 //Create an empty mDNS response message 00924 error = mdnsCreateMessage(&message, TRUE); 00925 //Any error to report? 00926 if(error) 00927 return error; 00928 00929 //Start of exception handling block 00930 do 00931 { 00932 //Format A resource record 00933 error = mdnsResponderAddIpv4AddrRecord(interface, &message, TRUE, 0); 00934 //Any error to report? 00935 if(error) 00936 break; 00937 00938 //Format reverse address mapping PTR record (IPv4) 00939 error = mdnsResponderAddIpv4ReversePtrRecord(interface, &message, TRUE, 0); 00940 //Any error to report? 00941 if(error) 00942 break; 00943 00944 //Format AAAA resource record 00945 error = mdnsResponderAddIpv6AddrRecord(interface, &message, TRUE, 0); 00946 //Any error to report? 00947 if(error) 00948 break; 00949 00950 //Format reverse address mapping PTR record (IPv6) 00951 error = mdnsResponderAddIpv6ReversePtrRecord(interface, &message, TRUE, 0); 00952 //Any error to report? 00953 if(error) 00954 break; 00955 00956 //Send mDNS message 00957 error = mdnsSendMessage(interface, &message, NULL, MDNS_PORT); 00958 00959 //End of exception handling block 00960 } while(0); 00961 00962 //Free previously allocated memory 00963 mdnsDeleteMessage(&message); 00964 00965 //Return status code 00966 return error; 00967 } 00968 00969 00970 /** 00971 * @brief Process mDNS query message 00972 * @param[in] interface Underlying network interface 00973 * @param[in] query Incoming mDNS query message 00974 **/ 00975 00976 void mdnsResponderProcessQuery(NetInterface *interface, MdnsMessage *query) 00977 { 00978 error_t error; 00979 uint_t i; 00980 size_t n; 00981 size_t offset; 00982 DnsQuestion *question; 00983 DnsResourceRecord *record; 00984 MdnsResponderContext *context; 00985 MdnsMessage *response; 00986 uint16_t destPort; 00987 IpAddr destIpAddr; 00988 00989 //Point to the mDNS responder context 00990 context = interface->mdnsResponderContext; 00991 //Make sure the mDNS responder has been properly instantiated 00992 if(context == NULL) 00993 return; 00994 00995 #if (IPV4_SUPPORT == ENABLED) 00996 //IPv4 query received? 00997 if(query->pseudoHeader->length == sizeof(Ipv4PseudoHeader)) 00998 { 00999 //If the source UDP port in a received Multicast DNS query is not port 5353, 01000 //this indicates that the querier originating the query is a simple resolver 01001 if(ntohs(query->udpHeader->srcPort) != MDNS_PORT) 01002 { 01003 //The mDNS responder must send a UDP response directly back to the querier, 01004 //via unicast, to the query packet's source IP address and port 01005 destIpAddr.length = sizeof(Ipv4Addr); 01006 destIpAddr.ipv4Addr = query->pseudoHeader->ipv4Data.srcAddr; 01007 } 01008 else 01009 { 01010 //Use mDNS IPv4 multicast address 01011 destIpAddr.length = sizeof(Ipv4Addr); 01012 destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; 01013 } 01014 01015 //Point to the mDNS response message 01016 response = &context->ipv4Response; 01017 } 01018 else 01019 #endif 01020 #if (IPV6_SUPPORT == ENABLED) 01021 //IPv6 query received? 01022 if(query->pseudoHeader->length == sizeof(Ipv6PseudoHeader)) 01023 { 01024 //If the source UDP port in a received Multicast DNS query is not port 5353, 01025 //this indicates that the querier originating the query is a simple resolver 01026 if(ntohs(query->udpHeader->srcPort) != MDNS_PORT) 01027 { 01028 //The mDNS responder must send a UDP response directly back to the querier, 01029 //via unicast, to the query packet's source IP address and port 01030 destIpAddr.length = sizeof(Ipv6Addr); 01031 destIpAddr.ipv6Addr = query->pseudoHeader->ipv6Data.srcAddr; 01032 } 01033 else 01034 { 01035 //Use mDNS IPv6 multicast address 01036 destIpAddr.length = sizeof(Ipv6Addr); 01037 destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; 01038 } 01039 01040 //Point to the mDNS response message 01041 response = &context->ipv6Response; 01042 } 01043 else 01044 #endif 01045 //Invalid query received? 01046 { 01047 //Discard the mDNS query message 01048 return; 01049 } 01050 01051 //When possible, a responder should, for the sake of network 01052 //efficiency, aggregate as many responses as possible into a 01053 //single mDNS response message 01054 if(response->buffer == NULL) 01055 { 01056 //Create an empty mDNS response message 01057 error = mdnsCreateMessage(response, TRUE); 01058 //Any error to report? 01059 if(error) 01060 return; 01061 } 01062 01063 //Take the identifier from the query message 01064 response->dnsHeader->id = query->dnsHeader->id; 01065 01066 //Point to the first question 01067 offset = sizeof(DnsHeader); 01068 01069 //Start of exception handling block 01070 do 01071 { 01072 //Parse the Question Section 01073 for(i = 0; i < ntohs(query->dnsHeader->qdcount); i++) 01074 { 01075 //Parse resource record name 01076 n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0); 01077 //Invalid name? 01078 if(!n) 01079 break; 01080 //Malformed mDNS message? 01081 if((n + sizeof(DnsQuestion)) > query->length) 01082 break; 01083 01084 //Point to the corresponding entry 01085 question = DNS_GET_QUESTION(query->dnsHeader, n); 01086 01087 //Parse question 01088 error = mdnsResponderParseQuestion(interface, query, 01089 offset, question, response); 01090 //Any error to report? 01091 if(error) 01092 break; 01093 01094 #if (DNS_SD_SUPPORT == ENABLED) 01095 //Parse resource record 01096 error = dnsSdParseQuestion(interface, query, offset, 01097 question, response); 01098 //Any error to report? 01099 if(error) 01100 break; 01101 #endif 01102 //Point to the next question 01103 offset = n + sizeof(DnsQuestion); 01104 } 01105 01106 //Any error while parsing the Question Section? 01107 if(i != ntohs(query->dnsHeader->qdcount)) 01108 break; 01109 01110 //Parse the Known-Answer Section 01111 for(i = 0; i < ntohs(query->dnsHeader->ancount); i++) 01112 { 01113 //Parse resource record name 01114 n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0); 01115 //Invalid name? 01116 if(!n) 01117 break; 01118 01119 //Point to the associated resource record 01120 record = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n); 01121 //Point to the resource data 01122 n += sizeof(DnsResourceRecord); 01123 01124 //Make sure the resource record is valid 01125 if(n > query->length) 01126 break; 01127 if((n + ntohs(record->rdlength)) > query->length) 01128 break; 01129 01130 //Parse resource record 01131 mdnsResponderParseKnownAnRecord(interface, query, offset, 01132 record, response); 01133 01134 //Point to the next resource record 01135 offset = n + ntohs(record->rdlength); 01136 } 01137 01138 //Any error while parsing the Answer Section? 01139 if(i != ntohs(query->dnsHeader->ancount)) 01140 break; 01141 01142 //Parse Authority Section 01143 for(i = 0; i < ntohs(query->dnsHeader->nscount); i++) 01144 { 01145 //Parse resource record name 01146 n = dnsParseName(query->dnsHeader, query->length, offset, NULL, 0); 01147 //Invalid name? 01148 if(!n) 01149 break; 01150 01151 //Point to the associated resource record 01152 record = DNS_GET_RESOURCE_RECORD(query->dnsHeader, n); 01153 //Point to the resource data 01154 n += sizeof(DnsResourceRecord); 01155 01156 //Make sure the resource record is valid 01157 if(n > query->length) 01158 break; 01159 if((n + ntohs(record->rdlength)) > query->length) 01160 break; 01161 01162 //Check for host name conflict 01163 mdnsResponderParseNsRecord(interface, query, offset, record); 01164 01165 #if (DNS_SD_SUPPORT == ENABLED) 01166 //Check for service instance name conflict 01167 dnsSdParseNsRecord(interface, query, offset, record); 01168 #endif 01169 //Point to the next resource record 01170 offset = n + ntohs(record->rdlength); 01171 } 01172 01173 //Any error while parsing the Authority Section? 01174 if(i != ntohs(query->dnsHeader->nscount)) 01175 break; 01176 01177 //End of exception handling block 01178 } while(0); 01179 01180 //Should a mDNS message be send in response to the query? 01181 if(response->dnsHeader->ancount > 0) 01182 { 01183 //If the source UDP port in a received Multicast DNS query is not port 5353, 01184 //this indicates that the querier originating the query is a simple resolver 01185 if(ntohs(query->udpHeader->srcPort) != MDNS_PORT) 01186 { 01187 #if (DNS_SD_SUPPORT == ENABLED) 01188 //Additional record generation (DNS-SD) 01189 dnsSdGenerateAdditionalRecords(interface, response, TRUE); 01190 #endif 01191 //Additional record generation (mDNS) 01192 mdnsResponderGenerateAdditionalRecords(interface, response, TRUE); 01193 01194 //Destination port 01195 destPort = ntohs(query->udpHeader->srcPort); 01196 01197 //Send mDNS response message 01198 mdnsSendMessage(interface, response, &destIpAddr, destPort); 01199 //Free previously allocated memory 01200 mdnsDeleteMessage(response); 01201 } 01202 else 01203 { 01204 //Check whether the answer should be delayed 01205 if(query->dnsHeader->tc) 01206 { 01207 //In the case where the query has the TC (truncated) bit set, indicating 01208 //that subsequent Known-Answer packets will follow, responders should 01209 //delay their responses by a random amount of time selected with uniform 01210 //random distribution in the range 400-500 ms 01211 response->timeout = netGetRandRange(400, 500); 01212 01213 //Save current time 01214 response->timestamp = osGetSystemTime(); 01215 } 01216 else if(response->sharedRecordCount > 0) 01217 { 01218 //In any case where there may be multiple responses, such as queries 01219 //where the answer is a member of a shared resource record set, each 01220 //responder should delay its response by a random amount of time 01221 //selected with uniform random distribution in the range 20-120 ms 01222 response->timeout = netGetRandRange(20, 120); 01223 01224 //Save current time 01225 response->timestamp = osGetSystemTime(); 01226 } 01227 else 01228 { 01229 #if (DNS_SD_SUPPORT == ENABLED) 01230 //Additional record generation (refer to RFC 6763 section 12) 01231 dnsSdGenerateAdditionalRecords(interface, response, FALSE); 01232 #endif 01233 //Additional record generation (mDNS) 01234 mdnsResponderGenerateAdditionalRecords(interface, response, FALSE); 01235 01236 //Send mDNS response message 01237 mdnsSendMessage(interface, response, &destIpAddr, MDNS_PORT); 01238 //Free previously allocated memory 01239 mdnsDeleteMessage(response); 01240 } 01241 } 01242 } 01243 else 01244 { 01245 //Free mDNS response message 01246 mdnsDeleteMessage(response); 01247 } 01248 } 01249 01250 01251 /** 01252 * @brief Parse a question 01253 * @param[in] interface Underlying network interface 01254 * @param[in] query Incoming mDNS query message 01255 * @param[in] offset Offset to first byte of the question 01256 * @param[in] question Pointer to the question 01257 * @param[in,out] response mDNS response message 01258 * @return Error code 01259 **/ 01260 01261 error_t mdnsResponderParseQuestion(NetInterface *interface, const MdnsMessage *query, 01262 size_t offset, const DnsQuestion *question, MdnsMessage *response) 01263 { 01264 error_t error; 01265 uint16_t qclass; 01266 uint16_t qtype; 01267 uint32_t ttl; 01268 bool_t cacheFlush; 01269 MdnsResponderContext *context; 01270 01271 //Point to the mDNS responder context 01272 context = interface->mdnsResponderContext; 01273 01274 //Check the state of the mDNS responder 01275 if(context->state != MDNS_STATE_ANNOUNCING && 01276 context->state != MDNS_STATE_IDLE) 01277 { 01278 //Do not respond to mDNS queries during probing 01279 return NO_ERROR; 01280 } 01281 01282 //Convert the query class to host byte order 01283 qclass = ntohs(question->qclass); 01284 //Discard QU flag 01285 qclass &= ~MDNS_QCLASS_QU; 01286 01287 //Convert the query type to host byte order 01288 qtype = ntohs(question->qtype); 01289 01290 //Get the TTL resource record 01291 ttl = context->settings.ttl; 01292 01293 //Check whether the querier originating the query is a simple resolver 01294 if(ntohs(query->udpHeader->srcPort) != MDNS_PORT) 01295 { 01296 //The resource record TTL given in a legacy unicast response should 01297 //not be greater than ten seconds, even if the true TTL of the mDNS 01298 //resource record is higher 01299 ttl = MIN(ttl, MDNS_LEGACY_UNICAST_RR_TTL); 01300 01301 //The cache-flush bit must not be set in legacy unicast responses 01302 cacheFlush = FALSE; 01303 } 01304 else 01305 { 01306 //The cache-bit should be set for unique resource records 01307 cacheFlush = TRUE; 01308 } 01309 01310 //Check the class of the query 01311 if(qclass == DNS_RR_CLASS_IN || qclass == DNS_RR_CLASS_ANY) 01312 { 01313 //Compare domain name 01314 if(!mdnsCompareName(query->dnsHeader, query->length, 01315 offset, context->hostname, "", ".local", 0)) 01316 { 01317 #if (IPV4_SUPPORT == ENABLED) 01318 //A query? 01319 if(qtype == DNS_RR_TYPE_A) 01320 { 01321 //Format A resource record 01322 error = mdnsResponderAddIpv4AddrRecord(interface, 01323 response, cacheFlush, ttl); 01324 //Any error to report? 01325 if(error) 01326 return error; 01327 } 01328 else 01329 #endif 01330 #if (IPV6_SUPPORT == ENABLED) 01331 //AAAA query? 01332 if(qtype == DNS_RR_TYPE_AAAA) 01333 { 01334 //Format AAAA resource record 01335 error = mdnsResponderAddIpv6AddrRecord(interface, 01336 response, cacheFlush, ttl); 01337 //Any error to report? 01338 if(error) 01339 return error; 01340 } 01341 else 01342 #endif 01343 //ANY query? 01344 if(qtype == DNS_RR_TYPE_ANY) 01345 { 01346 //Format A resource record 01347 error = mdnsResponderAddIpv4AddrRecord(interface, 01348 response, cacheFlush, ttl); 01349 //Any error to report? 01350 if(error) 01351 return error; 01352 01353 //Format AAAA resource record 01354 error = mdnsResponderAddIpv6AddrRecord(interface, 01355 response, cacheFlush, ttl); 01356 //Any error to report? 01357 if(error) 01358 return error; 01359 01360 //Format NSEC resource record 01361 error = mdnsResponderAddNsecRecord(interface, 01362 response, cacheFlush, ttl); 01363 //Any error to report? 01364 if(error) 01365 return error; 01366 } 01367 else 01368 { 01369 //Format NSEC resource record 01370 error = mdnsResponderAddNsecRecord(interface, 01371 response, cacheFlush, ttl); 01372 //Any error to report? 01373 if(error) 01374 return error; 01375 } 01376 } 01377 01378 #if (IPV4_SUPPORT == ENABLED) 01379 //Reverse DNS lookup? 01380 if(!mdnsCompareName(query->dnsHeader, query->length, 01381 offset, context->ipv4ReverseName, "in-addr", ".arpa", 0)) 01382 { 01383 //PTR query? 01384 if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY) 01385 { 01386 //Format reverse address mapping PTR record (IPv4) 01387 error = mdnsResponderAddIpv4ReversePtrRecord(interface, 01388 response, cacheFlush, ttl); 01389 //Any error to report? 01390 if(error) 01391 return error; 01392 } 01393 } 01394 #endif 01395 #if (IPV6_SUPPORT == ENABLED) 01396 //Reverse DNS lookup? 01397 if(!mdnsCompareName(query->dnsHeader, query->length, 01398 offset, context->ipv6ReverseName, "ip6", ".arpa", 0)) 01399 { 01400 //PTR query? 01401 if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY) 01402 { 01403 //Format reverse address mapping PTR record (IPv6) 01404 error = mdnsResponderAddIpv6ReversePtrRecord(interface, 01405 response, cacheFlush, ttl); 01406 //Any error to report? 01407 if(error) 01408 return error; 01409 } 01410 } 01411 #endif 01412 } 01413 01414 //Successful processing 01415 return NO_ERROR; 01416 } 01417 01418 01419 /** 01420 * @brief Parse a resource record from the Known-Answer Section 01421 * @param[in] interface Underlying network interface 01422 * @param[in] query Incoming mDNS query message 01423 * @param[in] queryOffset Offset to first byte of the resource record 01424 * @param[in] queryRecord Pointer to the resource record 01425 * @param[in,out] response mDNS response message 01426 **/ 01427 01428 void mdnsResponderParseKnownAnRecord(NetInterface *interface, const MdnsMessage *query, 01429 size_t queryOffset, const DnsResourceRecord *queryRecord, MdnsMessage *response) 01430 { 01431 size_t i; 01432 size_t n; 01433 size_t responseOffset; 01434 DnsResourceRecord *responseRecord; 01435 01436 //mDNS responses must not contain any questions in the Question Section 01437 if(response->dnsHeader->qdcount == 0) 01438 { 01439 //Point to the first resource record 01440 responseOffset = sizeof(DnsHeader); 01441 01442 //Parse the Answer Section of the response 01443 for(i = 0; i < response->dnsHeader->ancount; i++) 01444 { 01445 //Parse resource record name 01446 n = dnsParseName(response->dnsHeader, response->length, responseOffset, NULL, 0); 01447 //Invalid name? 01448 if(!n) 01449 break; 01450 01451 //Point to the associated resource record 01452 responseRecord = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n); 01453 //Point to the resource data 01454 n += sizeof(DnsResourceRecord); 01455 01456 //Make sure the resource record is valid 01457 if(n > response->length) 01458 break; 01459 01460 //Point to the end of the resource record 01461 n += ntohs(responseRecord->rdlength); 01462 01463 //Make sure the resource record is valid 01464 if(n > response->length) 01465 break; 01466 01467 //Compare resource record names 01468 if(!dnsCompareEncodedName(query->dnsHeader, query->length, queryOffset, 01469 response->dnsHeader, response->length, responseOffset, 0)) 01470 { 01471 //Compare the contents of the resource records 01472 if(!mdnsCompareRecord(query, queryOffset, queryRecord, 01473 response, responseOffset, responseRecord)) 01474 { 01475 //A mDNS responder must not answer a mDNS query if the answer 01476 //it would give is already included in the Answer Section with 01477 //an RR TTL at least half the correct value 01478 if(ntohl(queryRecord->ttl) >= (ntohl(responseRecord->ttl) / 2)) 01479 { 01480 //Perform Known-Answer Suppression 01481 memmove((uint8_t *) response->dnsHeader + responseOffset, 01482 (uint8_t *) response->dnsHeader + n, response->length - n); 01483 01484 //Update the length of the mDNS response message 01485 response->length -= (n - responseOffset); 01486 //Update the number of resource records in the Answer Section 01487 response->dnsHeader->ancount--; 01488 01489 //Keep at the same position 01490 n = responseOffset; 01491 i--; 01492 } 01493 } 01494 } 01495 01496 //Point to the next resource record 01497 responseOffset = n; 01498 } 01499 } 01500 } 01501 01502 01503 /** 01504 * @brief Parse a resource record from the Authority Section 01505 * @param[in] interface Underlying network interface 01506 * @param[in] query Incoming mDNS query message 01507 * @param[in] offset Offset to first byte of the resource record 01508 * @param[in] record Pointer to the resource record 01509 **/ 01510 01511 void mdnsResponderParseNsRecord(NetInterface *interface, 01512 const MdnsMessage *query, size_t offset, const DnsResourceRecord *record) 01513 { 01514 bool_t tieBreakLost; 01515 uint16_t rclass; 01516 MdnsResponderContext *context; 01517 01518 //Point to the mDNS responder context 01519 context = interface->mdnsResponderContext; 01520 01521 //When a host that is probing for a record sees another host issue a query 01522 //for the same record, it consults the Authority Section of that query. 01523 //If it finds any resource record there which answers the query, then it 01524 //compares the data of that resource record with its own tentative data 01525 if(!mdnsCompareName(query->dnsHeader, query->length, 01526 offset, context->hostname, "", ".local", 0)) 01527 { 01528 //Convert the class to host byte order 01529 rclass = ntohs(record->rclass); 01530 //Discard Cache Flush flag 01531 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 01532 01533 //Check the class of the resource record 01534 if(rclass == DNS_RR_CLASS_IN) 01535 { 01536 #if (IPV4_SUPPORT == ENABLED) 01537 //A resource record found? 01538 if(ntohs(record->rtype) == DNS_RR_TYPE_A) 01539 { 01540 //Apply tie-breaking rules 01541 tieBreakLost = TRUE; 01542 01543 //Verify the length of the data field 01544 if(ntohs(record->rdlength) == sizeof(Ipv4Addr)) 01545 { 01546 //Valid host address? 01547 if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID) 01548 { 01549 //The two records are compared and the lexicographically 01550 //later data wins 01551 if(memcmp(&interface->ipv4Context.addr, record->rdata, 01552 sizeof(Ipv4Addr)) >= 0) 01553 { 01554 tieBreakLost = FALSE; 01555 } 01556 } 01557 } 01558 01559 //Check whether the host has lost the tie-break 01560 if(tieBreakLost) 01561 context->tieBreakLost = TRUE; 01562 } 01563 #endif 01564 #if (IPV6_SUPPORT == ENABLED) 01565 //AAAA resource record found? 01566 if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA) 01567 { 01568 //Apply tie-breaking rules 01569 tieBreakLost = TRUE; 01570 01571 //Verify the length of the data field 01572 if(ntohs(record->rdlength) == sizeof(Ipv6Addr)) 01573 { 01574 uint_t i; 01575 Ipv6AddrEntry *entry; 01576 01577 //Loop through the list of IPv6 addresses assigned to the interface 01578 for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++) 01579 { 01580 //Point to the current entry 01581 entry = &interface->ipv6Context.addrList[i]; 01582 01583 //Valid IPv6 address 01584 if(entry->state != IPV6_ADDR_STATE_INVALID) 01585 { 01586 //The two records are compared and the lexicographically 01587 //later data wins 01588 if(memcmp(&interface->ipv6Context.addrList[i].addr, 01589 record->rdata, sizeof(Ipv6Addr)) >= 0) 01590 { 01591 tieBreakLost = FALSE; 01592 } 01593 } 01594 } 01595 } 01596 01597 //Check whether the host has lost the tie-break 01598 if(tieBreakLost) 01599 context->tieBreakLost = TRUE; 01600 } 01601 #endif 01602 } 01603 } 01604 } 01605 01606 01607 /** 01608 * @brief Parse a resource record from the Answer Section 01609 * @param[in] interface Underlying network interface 01610 * @param[in] response Incoming mDNS response message 01611 * @param[in] offset Offset to first byte of the resource record to be checked 01612 * @param[in] record Pointer to the resource record 01613 **/ 01614 01615 void mdnsResponderParseAnRecord(NetInterface *interface, 01616 const MdnsMessage *response, size_t offset, const DnsResourceRecord *record) 01617 { 01618 bool_t conflict; 01619 uint16_t rclass; 01620 MdnsResponderContext *context; 01621 01622 //Point to the mDNS responder context 01623 context = interface->mdnsResponderContext; 01624 01625 //Check for conflicts 01626 if(!mdnsCompareName(response->dnsHeader, response->length, 01627 offset, context->hostname, "", ".local", 0)) 01628 { 01629 //Convert the class to host byte order 01630 rclass = ntohs(record->rclass); 01631 //Discard Cache Flush flag 01632 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 01633 01634 //Check the class of the resource record 01635 if(rclass == DNS_RR_CLASS_IN) 01636 { 01637 #if (IPV4_SUPPORT == ENABLED) 01638 //A resource record found? 01639 if(ntohs(record->rtype) == DNS_RR_TYPE_A) 01640 { 01641 //A conflict occurs when a mDNS responder has a unique record for 01642 //which it is currently authoritative, and it receives a mDNS 01643 //response message containing a record with the same name, rrtype 01644 //and rrclass, but inconsistent rdata 01645 conflict = TRUE; 01646 01647 //Verify the length of the data field 01648 if(ntohs(record->rdlength) == sizeof(Ipv4Addr)) 01649 { 01650 //Valid host address? 01651 if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID) 01652 { 01653 //Check whether the rdata field is consistent 01654 if(ipv4CompAddr(&interface->ipv4Context.addr, record->rdata)) 01655 context->conflict = FALSE; 01656 } 01657 } 01658 01659 //Check whether the hostname is already in use by some other host 01660 if(conflict) 01661 context->conflict = TRUE; 01662 } 01663 #endif 01664 #if (IPV6_SUPPORT == ENABLED) 01665 //AAAA resource record found? 01666 if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA) 01667 { 01668 //A conflict occurs when a mDNS responder has a unique record for 01669 //which it is currently authoritative, and it receives a mDNS 01670 //response message containing a record with the same name, rrtype 01671 //and rrclass, but inconsistent rdata 01672 conflict = TRUE; 01673 01674 //Verify the length of the data field 01675 if(ntohs(record->rdlength) == sizeof(Ipv6Addr)) 01676 { 01677 uint_t i; 01678 Ipv6AddrEntry *entry; 01679 01680 //Loop through the list of IPv6 addresses assigned to the interface 01681 for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++) 01682 { 01683 //Point to the current entry 01684 entry = &interface->ipv6Context.addrList[i]; 01685 01686 //Valid IPv6 address 01687 if(entry->state != IPV6_ADDR_STATE_INVALID) 01688 { 01689 //Check whether the rdata field is consistent 01690 if(ipv6CompAddr(&interface->ipv6Context.addrList[i].addr, record->rdata)) 01691 conflict = FALSE; 01692 } 01693 } 01694 } 01695 01696 //Check whether the hostname is already in use by some other host 01697 if(conflict) 01698 context->conflict = TRUE; 01699 } 01700 #endif 01701 } 01702 } 01703 } 01704 01705 01706 /** 01707 * @brief Additional record generation 01708 * @param[in] interface Underlying network interface 01709 * @param[in,out] response mDNS response message 01710 * @param[in] legacyUnicast This flag is set for legacy unicast responses 01711 **/ 01712 01713 void mdnsResponderGenerateAdditionalRecords(NetInterface *interface, 01714 MdnsMessage *response, bool_t legacyUnicast) 01715 { 01716 error_t error; 01717 uint_t i; 01718 uint_t k; 01719 size_t n; 01720 size_t offset; 01721 uint_t ancount; 01722 uint16_t rclass; 01723 uint32_t ttl; 01724 bool_t cacheFlush; 01725 MdnsResponderContext *context; 01726 DnsResourceRecord *record; 01727 01728 //Point to the mDNS responder context 01729 context = interface->mdnsResponderContext; 01730 01731 //mDNS responses must not contain any questions in the Question Section 01732 if(response->dnsHeader->qdcount != 0) 01733 return; 01734 01735 //Get the TTL resource record 01736 ttl = context->settings.ttl; 01737 01738 //Check whether the querier originating the query is a simple resolver 01739 if(legacyUnicast) 01740 { 01741 //The resource record TTL given in a legacy unicast response should 01742 //not be greater than ten seconds, even if the true TTL of the mDNS 01743 //resource record is higher 01744 ttl = MIN(ttl, MDNS_LEGACY_UNICAST_RR_TTL); 01745 01746 //The cache-flush bit must not be set in legacy unicast responses 01747 cacheFlush = FALSE; 01748 } 01749 else 01750 { 01751 //The cache-bit should be set for unique resource records 01752 cacheFlush = TRUE; 01753 } 01754 01755 //Point to the first resource record 01756 offset = sizeof(DnsHeader); 01757 01758 //Save the number of resource records in the Answer Section 01759 ancount = response->dnsHeader->ancount; 01760 01761 //Compute the total number of resource records 01762 k = response->dnsHeader->ancount + response->dnsHeader->nscount + 01763 response->dnsHeader->arcount; 01764 01765 //Loop through the resource records 01766 for(i = 0; i < k; i++) 01767 { 01768 //Parse resource record name 01769 n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0); 01770 //Invalid name? 01771 if(!n) 01772 break; 01773 01774 //Point to the associated resource record 01775 record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n); 01776 //Point to the resource data 01777 n += sizeof(DnsResourceRecord); 01778 01779 //Make sure the resource record is valid 01780 if(n > response->length) 01781 break; 01782 if((n + ntohs(record->rdlength)) > response->length) 01783 break; 01784 01785 //Convert the record class to host byte order 01786 rclass = ntohs(record->rclass); 01787 //Discard the cache-flush bit 01788 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 01789 01790 //Check the class of the resource record 01791 if(rclass == DNS_RR_CLASS_IN) 01792 { 01793 //A record? 01794 if(ntohs(record->rtype) == DNS_RR_TYPE_A) 01795 { 01796 #if (IPV6_SUPPORT == ENABLED) 01797 //When a mDNS responder places an IPv4 address record into a 01798 //response message, it should also place any IPv6 address records 01799 //with the same name into the Additional Section 01800 error = mdnsResponderAddIpv6AddrRecord(interface, 01801 response, cacheFlush, ttl); 01802 #else 01803 //In the event that a device has only IPv4 addresses but no IPv6 01804 //addresses, then the appropriate NSEC record should be placed 01805 //into the Additional Section 01806 error = mdnsResponderAddNsecRecord(interface, 01807 response, cacheFlush, ttl); 01808 #endif 01809 //Any error to report? 01810 if(error) 01811 return; 01812 } 01813 //AAAA record? 01814 else if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA) 01815 { 01816 #if (IPV4_SUPPORT == ENABLED) 01817 //When a mDNS responder places an IPv6 address record into a 01818 //response message, it should also place any IPv4 address records 01819 //with the same name into the Additional Section 01820 error = mdnsResponderAddIpv4AddrRecord(interface, 01821 response, cacheFlush, ttl); 01822 #else 01823 //In the event that a device has only IPv6 addresses but no IPv4 01824 //addresses, then the appropriate NSEC record should be placed 01825 //into the Additional Section 01826 error = mdnsResponderAddNsecRecord(interface, 01827 response, cacheFlush, ttl); 01828 #endif 01829 //Any error to report? 01830 if(error) 01831 return; 01832 } 01833 //SRV record? 01834 else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV) 01835 { 01836 //Format A resource record 01837 error = mdnsResponderAddIpv4AddrRecord(interface, 01838 response, cacheFlush, ttl); 01839 //Any error to report? 01840 if(error) 01841 return; 01842 01843 //Format AAAA resource record 01844 error = mdnsResponderAddIpv6AddrRecord(interface, 01845 response, cacheFlush, ttl); 01846 //Any error to report? 01847 if(error) 01848 return; 01849 01850 #if (IPV4_SUPPORT == DISABLED || IPV6_SUPPORT == DISABLED) 01851 //In the event that a device has only IPv4 addresses but no IPv6 01852 //addresses, or vice versa, then the appropriate NSEC record should 01853 //be placed into the additional section, so that queriers can know 01854 //with certainty that the device has no addresses of that kind 01855 error = mdnsResponderAddNsecRecord(interface, 01856 response, cacheFlush, ttl); 01857 //Any error to report? 01858 if(error) 01859 return; 01860 #endif 01861 } 01862 } 01863 01864 //Point to the next resource record 01865 offset = n + ntohs(record->rdlength); 01866 } 01867 01868 //Number of resource records in the Additional Section 01869 response->dnsHeader->arcount += response->dnsHeader->ancount - ancount; 01870 //Number of resource records in the Answer Section 01871 response->dnsHeader->ancount = ancount; 01872 } 01873 01874 01875 /** 01876 * @brief Add A record to a mDNS message 01877 * @param[in] interface Underlying network interface 01878 * @param[in,out] message Pointer to the mDNS message 01879 * @param[in] cacheFlush Cache-flush bit 01880 * @param[in] ttl Resource record TTL (cache lifetime) 01881 * @return Error code 01882 **/ 01883 01884 error_t mdnsResponderAddIpv4AddrRecord(NetInterface *interface, 01885 MdnsMessage *message, bool_t cacheFlush, uint32_t ttl) 01886 { 01887 #if (IPV4_SUPPORT == ENABLED) 01888 size_t n; 01889 size_t offset; 01890 bool_t duplicate; 01891 MdnsResponderContext *context; 01892 DnsResourceRecord *record; 01893 01894 //Point to the mDNS responder context 01895 context = interface->mdnsResponderContext; 01896 01897 //Valid IPv4 host address? 01898 if(interface->ipv4Context.addrState == IPV4_ADDR_STATE_VALID) 01899 { 01900 //Check whether the resource record is already present in the Answer 01901 //Section of the message 01902 duplicate = mdnsCheckDuplicateRecord(message, context->hostname, 01903 "", ".local", DNS_RR_TYPE_A); 01904 01905 //The duplicates should be suppressed and the resource record should 01906 //appear only once in the list 01907 if(!duplicate) 01908 { 01909 //Set the position to the end of the buffer 01910 offset = message->length; 01911 01912 //The first pass calculates the length of the DNS encoded host name 01913 n = mdnsEncodeName(context->hostname, "", ".local", NULL); 01914 01915 //Check the length of the resulting mDNS message 01916 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01917 return ERROR_MESSAGE_TOO_LONG; 01918 01919 //The second pass encodes the host name using the DNS name notation 01920 offset += mdnsEncodeName(context->hostname, "", ".local", 01921 (uint8_t *) message->dnsHeader + offset); 01922 01923 //Consider the length of the resource record itself 01924 n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr); 01925 01926 //Check the length of the resulting mDNS message 01927 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 01928 return ERROR_MESSAGE_TOO_LONG; 01929 01930 //Point to the corresponding resource record 01931 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 01932 01933 //Fill in resource record 01934 record->rtype = HTONS(DNS_RR_TYPE_A); 01935 record->rclass = HTONS(DNS_RR_CLASS_IN); 01936 record->ttl = htonl(ttl); 01937 record->rdlength = HTONS(sizeof(Ipv4Addr)); 01938 01939 //Check whether the cache-flush bit should be set 01940 if(cacheFlush) 01941 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 01942 01943 //Copy IPv4 address 01944 ipv4CopyAddr(record->rdata, &interface->ipv4Context.addr); 01945 01946 //Number of resource records in the answer section 01947 message->dnsHeader->ancount++; 01948 //Update the length of the mDNS response message 01949 message->length = offset + n; 01950 } 01951 } 01952 #endif 01953 01954 //Successful processing 01955 return NO_ERROR; 01956 } 01957 01958 01959 /** 01960 * @brief Add AAAA record to a mDNS message 01961 * @param[in] interface Underlying network interface 01962 * @param[in,out] message Pointer to the mDNS message 01963 * @param[in] cacheFlush Cache-flush bit 01964 * @param[in] ttl Resource record TTL (cache lifetime) 01965 * @return Error code 01966 **/ 01967 01968 error_t mdnsResponderAddIpv6AddrRecord(NetInterface *interface, 01969 MdnsMessage *message, bool_t cacheFlush, uint32_t ttl) 01970 { 01971 #if (IPV6_SUPPORT == ENABLED) 01972 size_t n; 01973 size_t offset; 01974 bool_t duplicate; 01975 MdnsResponderContext *context; 01976 DnsResourceRecord *record; 01977 01978 //Point to the mDNS responder context 01979 context = interface->mdnsResponderContext; 01980 01981 //Valid IPv6 link-local address? 01982 if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED) 01983 { 01984 //Check whether the resource record is already present in the Answer 01985 //Section of the message 01986 duplicate = mdnsCheckDuplicateRecord(message, context->hostname, 01987 "", ".local", DNS_RR_TYPE_AAAA); 01988 01989 //The duplicates should be suppressed and the resource record should 01990 //appear only once in the list 01991 if(!duplicate) 01992 { 01993 //Set the position to the end of the buffer 01994 offset = message->length; 01995 01996 //The first pass calculates the length of the DNS encoded host name 01997 n = mdnsEncodeName(context->hostname, "", ".local", NULL); 01998 01999 //Check the length of the resulting mDNS message 02000 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02001 return ERROR_MESSAGE_TOO_LONG; 02002 02003 //The second pass encodes the host name using the DNS name notation 02004 offset += mdnsEncodeName(context->hostname, "", ".local", 02005 (uint8_t *) message->dnsHeader + offset); 02006 02007 //Consider the length of the resource record itself 02008 n = sizeof(DnsResourceRecord) + sizeof(Ipv6Addr); 02009 02010 //Check the length of the resulting mDNS message 02011 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02012 return ERROR_MESSAGE_TOO_LONG; 02013 02014 //Point to the corresponding resource record 02015 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 02016 02017 //Fill in resource record 02018 record->rtype = HTONS(DNS_RR_TYPE_AAAA); 02019 record->rclass = HTONS(DNS_RR_CLASS_IN); 02020 record->ttl = htonl(ttl); 02021 record->rdlength = HTONS(sizeof(Ipv6Addr)); 02022 02023 //Check whether the cache-flush bit should be set 02024 if(cacheFlush) 02025 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 02026 02027 //Copy IPv6 address 02028 ipv6CopyAddr(record->rdata, &interface->ipv6Context.addrList[0].addr); 02029 02030 //Number of resource records in the answer section 02031 message->dnsHeader->ancount++; 02032 //Update the length of the mDNS response message 02033 message->length = offset + n; 02034 } 02035 } 02036 #endif 02037 02038 //Successful processing 02039 return NO_ERROR; 02040 } 02041 02042 02043 /** 02044 * @brief Add reverse address mapping PTR record (IPv4) 02045 * @param[in] interface Underlying network interface 02046 * @param[in,out] message Pointer to the mDNS message 02047 * @param[in] cacheFlush Cache-flush bit 02048 * @param[in] ttl Resource record TTL (cache lifetime) 02049 * @return Error code 02050 **/ 02051 02052 error_t mdnsResponderAddIpv4ReversePtrRecord(NetInterface *interface, 02053 MdnsMessage *message, bool_t cacheFlush, uint32_t ttl) 02054 { 02055 #if (IPV4_SUPPORT == ENABLED) 02056 size_t n; 02057 size_t offset; 02058 bool_t duplicate; 02059 MdnsResponderContext *context; 02060 DnsResourceRecord *record; 02061 02062 //Point to the mDNS responder context 02063 context = interface->mdnsResponderContext; 02064 02065 //Valid reverse name? 02066 if(context->ipv4ReverseName[0] != '\0') 02067 { 02068 //Check whether the resource record is already present in the Answer 02069 //Section of the message 02070 duplicate = mdnsCheckDuplicateRecord(message, context->ipv4ReverseName, 02071 "in-addr", ".arpa", DNS_RR_TYPE_PTR); 02072 02073 //The duplicates should be suppressed and the resource record should 02074 //appear only once in the list 02075 if(!duplicate) 02076 { 02077 //Set the position to the end of the buffer 02078 offset = message->length; 02079 02080 //The first pass calculates the length of the DNS encoded reverse name 02081 n = mdnsEncodeName(context->ipv4ReverseName, "in-addr", ".arpa", NULL); 02082 02083 //Check the length of the resulting mDNS message 02084 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02085 return ERROR_MESSAGE_TOO_LONG; 02086 02087 //The second pass encodes the reverse name using the DNS name notation 02088 offset += mdnsEncodeName(context->ipv4ReverseName, "in-addr", ".arpa", 02089 (uint8_t *) message->dnsHeader + offset); 02090 02091 //Consider the length of the resource record itself 02092 n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr); 02093 02094 //Check the length of the resulting mDNS message 02095 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02096 return ERROR_MESSAGE_TOO_LONG; 02097 02098 //Point to the corresponding resource record 02099 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 02100 02101 //Fill in resource record 02102 record->rtype = HTONS(DNS_RR_TYPE_PTR); 02103 record->rclass = HTONS(DNS_RR_CLASS_IN); 02104 record->ttl = htonl(ttl); 02105 02106 //Check whether the cache-flush bit should be set 02107 if(cacheFlush) 02108 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 02109 02110 //Advance write index 02111 offset += sizeof(DnsResourceRecord); 02112 02113 //The first pass calculates the length of the DNS encoded host name 02114 n = mdnsEncodeName("", context->hostname, ".local", NULL); 02115 02116 //Check the length of the resulting mDNS message 02117 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02118 return ERROR_MESSAGE_TOO_LONG; 02119 02120 //The second pass encodes the host name using DNS notation 02121 n = mdnsEncodeName("", context->hostname, ".local", record->rdata); 02122 02123 //Convert length field to network byte order 02124 record->rdlength = htons(n); 02125 02126 //Number of resource records in the answer section 02127 message->dnsHeader->ancount++; 02128 //Update the length of the mDNS response message 02129 message->length = offset + n; 02130 } 02131 } 02132 #endif 02133 02134 //Successful processing 02135 return NO_ERROR; 02136 } 02137 02138 02139 /** 02140 * @brief Add reverse address mapping PTR record (IPv6) 02141 * @param[in] interface Underlying network interface 02142 * @param[in,out] message Pointer to the mDNS message 02143 * @param[in] cacheFlush Cache-flush bit 02144 * @param[in] ttl Resource record TTL (cache lifetime) 02145 * @return Error code 02146 **/ 02147 02148 error_t mdnsResponderAddIpv6ReversePtrRecord(NetInterface *interface, 02149 MdnsMessage *message, bool_t cacheFlush, uint32_t ttl) 02150 { 02151 #if (IPV6_SUPPORT == ENABLED) 02152 size_t n; 02153 size_t offset; 02154 bool_t duplicate; 02155 MdnsResponderContext *context; 02156 DnsResourceRecord *record; 02157 02158 //Point to the mDNS responder context 02159 context = interface->mdnsResponderContext; 02160 02161 //Valid reverse name? 02162 if(context->ipv6ReverseName[0] != '\0') 02163 { 02164 //Check whether the resource record is already present in the Answer 02165 //Section of the message 02166 duplicate = mdnsCheckDuplicateRecord(message, context->ipv6ReverseName, 02167 "ip6", ".arpa", DNS_RR_TYPE_PTR); 02168 02169 //The duplicates should be suppressed and the resource record should 02170 //appear only once in the list 02171 if(!duplicate) 02172 { 02173 //Set the position to the end of the buffer 02174 offset = message->length; 02175 02176 //The first pass calculates the length of the DNS encoded reverse name 02177 n = mdnsEncodeName(context->ipv6ReverseName, "ip6", ".arpa", NULL); 02178 02179 //Check the length of the resulting mDNS message 02180 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02181 return ERROR_MESSAGE_TOO_LONG; 02182 02183 //The second pass encodes the reverse name using the DNS name notation 02184 offset += mdnsEncodeName(context->ipv6ReverseName, "ip6", ".arpa", 02185 (uint8_t *) message->dnsHeader + offset); 02186 02187 //Consider the length of the resource record itself 02188 n = sizeof(DnsResourceRecord) + sizeof(Ipv4Addr); 02189 02190 //Check the length of the resulting mDNS message 02191 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02192 return ERROR_MESSAGE_TOO_LONG; 02193 02194 //Point to the corresponding resource record 02195 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 02196 02197 //Fill in resource record 02198 record->rtype = HTONS(DNS_RR_TYPE_PTR); 02199 record->rclass = HTONS(DNS_RR_CLASS_IN); 02200 record->ttl = htonl(ttl); 02201 02202 //Check whether the cache-flush bit should be set 02203 if(cacheFlush) 02204 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 02205 02206 //Advance write index 02207 offset += sizeof(DnsResourceRecord); 02208 02209 //The first pass calculates the length of the DNS encoded host name 02210 n = mdnsEncodeName("", context->hostname, ".local", NULL); 02211 02212 //Check the length of the resulting mDNS message 02213 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02214 return ERROR_MESSAGE_TOO_LONG; 02215 02216 //The second pass encodes the host name using DNS notation 02217 n = mdnsEncodeName("", context->hostname, ".local", record->rdata); 02218 02219 //Convert length field to network byte order 02220 record->rdlength = htons(n); 02221 02222 //Number of resource records in the answer section 02223 message->dnsHeader->ancount++; 02224 //Update the length of the mDNS response message 02225 message->length = offset + n; 02226 } 02227 } 02228 #endif 02229 02230 //Successful processing 02231 return NO_ERROR; 02232 } 02233 02234 02235 /** 02236 * @brief Add NSEC record to a mDNS message 02237 * @param[in] interface Underlying network interface 02238 * @param[in,out] message Pointer to the mDNS message 02239 * @param[in] cacheFlush Cache-flush bit 02240 * @param[in] ttl Resource record TTL (cache lifetime) 02241 * @return Error code 02242 **/ 02243 02244 error_t mdnsResponderAddNsecRecord(NetInterface *interface, 02245 MdnsMessage *message, bool_t cacheFlush, uint32_t ttl) 02246 { 02247 size_t n; 02248 size_t offset; 02249 bool_t duplicate; 02250 size_t bitmapLength; 02251 uint8_t bitmap[8]; 02252 MdnsResponderContext *context; 02253 DnsResourceRecord *record; 02254 02255 //Point to the mDNS responder context 02256 context = interface->mdnsResponderContext; 02257 02258 //Check whether the resource record is already present in the Answer 02259 //Section of the message 02260 duplicate = mdnsCheckDuplicateRecord(message, context->hostname, 02261 "", ".local", DNS_RR_TYPE_NSEC); 02262 02263 //The duplicates should be suppressed and the resource record should 02264 //appear only once in the list 02265 if(!duplicate) 02266 { 02267 //The bitmap identifies the resource record types that exist 02268 memset(bitmap, 0, sizeof(bitmap)); 02269 02270 #if (IPV4_SUPPORT == ENABLED) 02271 //A resource record is supported 02272 DNS_SET_NSEC_BITMAP(bitmap, DNS_RR_TYPE_A); 02273 #endif 02274 02275 #if (IPV6_SUPPORT == ENABLED) 02276 //A resource record is supported 02277 DNS_SET_NSEC_BITMAP(bitmap, DNS_RR_TYPE_AAAA); 02278 #endif 02279 02280 //Compute the length of the bitmap 02281 for(bitmapLength = sizeof(bitmap); bitmapLength > 0; bitmapLength--) 02282 { 02283 //Trailing zero octets in the bitmap must be omitted... 02284 if(bitmap[bitmapLength - 1] != 0x00) 02285 break; 02286 } 02287 02288 //Set the position to the end of the buffer 02289 offset = message->length; 02290 02291 //The first pass calculates the length of the DNS encoded host name 02292 n = mdnsEncodeName(context->hostname, "", ".local", NULL); 02293 02294 //Check the length of the resulting mDNS message 02295 if((offset + n) > MDNS_MESSAGE_MAX_SIZE) 02296 return ERROR_MESSAGE_TOO_LONG; 02297 02298 //The second pass encodes the host name using the DNS name notation 02299 offset += mdnsEncodeName(context->hostname, "", ".local", 02300 (uint8_t *) message->dnsHeader + offset); 02301 02302 //Consider the length of the resource record itself 02303 if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) 02304 return ERROR_MESSAGE_TOO_LONG; 02305 02306 //Point to the corresponding resource record 02307 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, offset); 02308 02309 //Fill in resource record 02310 record->rtype = HTONS(DNS_RR_TYPE_NSEC); 02311 record->rclass = HTONS(DNS_RR_CLASS_IN); 02312 record->ttl = htonl(ttl); 02313 02314 //Check whether the cache-flush bit should be set 02315 if(cacheFlush) 02316 record->rclass |= HTONS(MDNS_RCLASS_CACHE_FLUSH); 02317 02318 //Advance write index 02319 offset += sizeof(DnsResourceRecord); 02320 02321 //Check the length of the resulting mDNS message 02322 if((offset + n + 2 + bitmapLength) > MDNS_MESSAGE_MAX_SIZE) 02323 return ERROR_MESSAGE_TOO_LONG; 02324 02325 //The Next Domain Name field contains the record's own name 02326 mdnsEncodeName(context->hostname, "", ".local", record->rdata); 02327 02328 //DNS NSEC record is limited to Window Block number zero 02329 record->rdata[n++] = 0; 02330 //The Bitmap Length is a value in the range 1-32 02331 record->rdata[n++] = bitmapLength; 02332 02333 //The Bitmap data identifies the resource record types that exist 02334 memcpy(record->rdata + n, bitmap, bitmapLength); 02335 02336 //Convert length field to network byte order 02337 record->rdlength = htons(n + bitmapLength); 02338 02339 //Number of resource records in the answer section 02340 message->dnsHeader->ancount++; 02341 //Update the length of the DNS message 02342 message->length = offset + n + bitmapLength; 02343 } 02344 02345 //Successful processing 02346 return NO_ERROR; 02347 } 02348 02349 #endif 02350
Generated on Tue Jul 12 2022 17:10:14 by
