Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
mdns_common.c
00001 /** 00002 * @file mdns_common.c 00003 * @brief Functions common to mDNS client and mDNS responder 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 * @section Description 00026 * 00027 * Multicast DNS and its companion technology DNS-Based Service Discovery 00028 * were created to provide ease-of-use and autoconfiguration to IP networks. 00029 * Refer to the following RFCs for complete details: 00030 * - RFC 6762: Multicast DNS 00031 * - RFC 6763: DNS-Based Service Discovery 00032 * 00033 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00034 * @version 1.7.6 00035 **/ 00036 00037 //Switch to the appropriate trace level 00038 #define TRACE_LEVEL MDNS_TRACE_LEVEL 00039 00040 //Dependencies 00041 #include <stdlib.h> 00042 #include <string.h> 00043 #include <ctype.h> 00044 #include "core/net.h" 00045 #include "ipv6/ipv6_misc.h" 00046 #include "mdns/mdns_client.h" 00047 #include "mdns/mdns_responder.h" 00048 #include "mdns/mdns_common.h" 00049 #include "dns/dns_debug.h" 00050 #include "debug.h" 00051 00052 //Check TCP/IP stack configuration 00053 #if (MDNS_CLIENT_SUPPORT == ENABLED || MDNS_RESPONDER_SUPPORT == ENABLED) 00054 00055 #if (IPV6_SUPPORT == ENABLED) 00056 00057 //mDNS IPv6 multicast group (ff02::fb) 00058 const Ipv6Addr MDNS_IPV6_MULTICAST_ADDR = 00059 IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00FB); 00060 00061 #endif 00062 00063 00064 /** 00065 * @brief mDNS related initialization 00066 * @param[in] interface Underlying network interface 00067 * @return Error code 00068 **/ 00069 00070 error_t mdnsInit(NetInterface *interface) 00071 { 00072 error_t error; 00073 00074 #if (IPV4_SUPPORT == ENABLED) 00075 //Join the mDNS IPv4 multicast group 00076 error = ipv4JoinMulticastGroup(interface, MDNS_IPV4_MULTICAST_ADDR); 00077 //Any error to report? 00078 if(error) 00079 return error; 00080 #endif 00081 00082 #if (IPV6_SUPPORT == ENABLED) 00083 //Join the mDNS IPv6 multicast group 00084 error = ipv6JoinMulticastGroup(interface, &MDNS_IPV6_MULTICAST_ADDR); 00085 //Any error to report? 00086 if(error) 00087 return error; 00088 #endif 00089 00090 //Callback function to be called when a mDNS message is received 00091 error = udpAttachRxCallback(interface, MDNS_PORT, mdnsProcessMessage, NULL); 00092 //Any error to report? 00093 if(error) 00094 return error; 00095 00096 //Successful initialization 00097 return NO_ERROR; 00098 } 00099 00100 00101 /** 00102 * @brief Process incoming mDNS message 00103 * @param[in] interface Underlying network interface 00104 * @param[in] pseudoHeader UDP pseudo header 00105 * @param[in] udpHeader UDP header 00106 * @param[in] buffer Multi-part buffer containing the incoming mDNS message 00107 * @param[in] offset Offset to the first byte of the mDNS message 00108 * @param[in] params Callback function parameter (not used) 00109 **/ 00110 00111 void mdnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, 00112 const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *params) 00113 { 00114 size_t length; 00115 DnsHeader *dnsHeader; 00116 MdnsMessage message; 00117 00118 //Retrieve the length of the mDNS message 00119 length = netBufferGetLength(buffer) - offset; 00120 00121 //Ensure the mDNS message is valid 00122 if(length < sizeof(DnsHeader)) 00123 return; 00124 if(length > MDNS_MESSAGE_MAX_SIZE) 00125 return; 00126 00127 //Point to the mDNS message header 00128 dnsHeader = netBufferAt(buffer, offset); 00129 //Sanity check 00130 if(dnsHeader == NULL) 00131 return; 00132 00133 //Debug message 00134 TRACE_INFO("mDNS message received (%" PRIuSIZE " bytes)...\r\n", length); 00135 //Dump message 00136 dnsDumpMessage(dnsHeader, length); 00137 00138 //mDNS messages received with an opcode other than zero must be silently ignored 00139 if(dnsHeader->opcode != DNS_OPCODE_QUERY) 00140 return; 00141 //mDNS messages received with non-zero response codes must be silently ignored 00142 if(dnsHeader->rcode != DNS_RCODE_NO_ERROR) 00143 return; 00144 00145 //Save mDNS message 00146 message.buffer = (NetBuffer *) buffer; 00147 message.offset = offset; 00148 message.length = length; 00149 message.pseudoHeader = pseudoHeader; 00150 message.udpHeader = udpHeader; 00151 message.dnsHeader = dnsHeader; 00152 00153 //mDNS query received? 00154 if(!dnsHeader->qr) 00155 { 00156 #if (MDNS_RESPONDER_SUPPORT == ENABLED) 00157 //Process incoming mDNS query message 00158 mdnsResponderProcessQuery(interface, &message); 00159 #endif 00160 } 00161 //mDNS response received? 00162 else 00163 { 00164 //Process incoming mDNS response message 00165 mdnsProcessResponse(interface, &message); 00166 } 00167 } 00168 00169 00170 /** 00171 * @brief Process mDNS response message 00172 * @param[in] interface Underlying network interface 00173 * @param[in] response Incoming mDNS response message 00174 **/ 00175 00176 void mdnsProcessResponse(NetInterface *interface, MdnsMessage *response) 00177 { 00178 uint_t i; 00179 uint_t k; 00180 size_t n; 00181 size_t offset; 00182 DnsResourceRecord *record; 00183 00184 //Source address check (refer to RFC 6762 section 11) 00185 if(!mdnsCheckSourceAddr(interface, response->pseudoHeader)) 00186 return; 00187 00188 //mDNS implementations must silently ignore any mDNS responses they 00189 //receive where the source UDP port is not 5353 00190 if(ntohs(response->udpHeader->srcPort) != MDNS_PORT) 00191 return; 00192 00193 //Point to the question section 00194 offset = sizeof(DnsHeader); 00195 00196 //Any questions in the question section of a received mDNS response 00197 //must be silently ignored 00198 for(i = 0; i < ntohs(response->dnsHeader->qdcount); i++) 00199 { 00200 //Parse domain name 00201 offset = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0); 00202 //Invalid name? 00203 if(!offset) 00204 break; 00205 00206 //Point to the next question 00207 offset += sizeof(DnsQuestion); 00208 //Make sure the mDNS message is valid 00209 if(offset > response->length) 00210 break; 00211 } 00212 00213 //Malformed mDNS message? 00214 if(i != ntohs(response->dnsHeader->qdcount)) 00215 return; 00216 00217 //Compute the total number of resource records 00218 k = ntohs(response->dnsHeader->ancount) + 00219 ntohs(response->dnsHeader->nscount) + 00220 ntohs(response->dnsHeader->arcount); 00221 00222 //Loop through the resource records 00223 for(i = 0; i < k; i++) 00224 { 00225 //Parse resource record name 00226 n = dnsParseName(response->dnsHeader, response->length, offset, NULL, 0); 00227 //Invalid name? 00228 if(!n) 00229 break; 00230 00231 //Point to the associated resource record 00232 record = DNS_GET_RESOURCE_RECORD(response->dnsHeader, n); 00233 //Point to the resource data 00234 n += sizeof(DnsResourceRecord); 00235 00236 //Make sure the resource record is valid 00237 if(n > response->length) 00238 break; 00239 if((n + ntohs(record->rdlength)) > response->length) 00240 break; 00241 00242 #if (MDNS_CLIENT_SUPPORT == ENABLED) 00243 //Parse the resource record 00244 mdnsClientParseAnRecord(interface, response, offset, record); 00245 #endif 00246 00247 #if (MDNS_RESPONDER_SUPPORT == ENABLED) 00248 //Parse the resource record 00249 mdnsResponderParseAnRecord(interface, response, offset, record); 00250 #endif 00251 00252 #if (DNS_SD_SUPPORT == ENABLED) 00253 //Parse the resource record 00254 dnsSdParseAnRecord(interface, response, offset, record); 00255 #endif 00256 00257 //Point to the next resource record 00258 offset = n + ntohs(record->rdlength); 00259 } 00260 } 00261 00262 00263 /** 00264 * @brief Source address check 00265 * @param[in] interface Underlying network interface 00266 * @param[in] pseudoHeader UDP pseudo header 00267 * @return TRUE if the source address is valid, else FALSE 00268 **/ 00269 00270 bool_t mdnsCheckSourceAddr(NetInterface *interface, 00271 const IpPseudoHeader *pseudoHeader) 00272 { 00273 bool_t valid; 00274 00275 #if (IPV4_SUPPORT == ENABLED) 00276 //IPv4 packet received? 00277 if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) 00278 { 00279 //Perform source address check (refer to RFC 6762 section 11) 00280 if(pseudoHeader->ipv4Data.destAddr == MDNS_IPV4_MULTICAST_ADDR) 00281 { 00282 //All responses received with the destination address 224.0.0.251 00283 //are necessarily deemed to have originated on the local link, 00284 //regardless of source IP address 00285 valid = TRUE; 00286 } 00287 else if(ipv4IsLinkLocalAddr(pseudoHeader->ipv4Data.srcAddr) || 00288 ipv4IsLinkLocalAddr(pseudoHeader->ipv4Data.destAddr)) 00289 { 00290 //Packets with a link-local source or destination address 00291 //originate from the local link 00292 valid = TRUE; 00293 } 00294 else if(ipv4IsOnLocalSubnet(interface, pseudoHeader->ipv4Data.srcAddr)) 00295 { 00296 //The source IP address is on the local subnet 00297 valid = TRUE; 00298 } 00299 else 00300 { 00301 //Only accept responses that originate from the local link, and 00302 //silently discard any other response packets 00303 valid = FALSE; 00304 } 00305 } 00306 else 00307 #endif 00308 #if (IPV6_SUPPORT == ENABLED) 00309 //IPv6 packet received? 00310 if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) 00311 { 00312 //Perform source address check (refer to RFC 6762 section 11) 00313 if(ipv6CompAddr(&pseudoHeader->ipv6Data.destAddr, &MDNS_IPV6_MULTICAST_ADDR)) 00314 { 00315 //All responses received with the destination address ff02::fb 00316 //are necessarily deemed to have originated on the local link, 00317 //regardless of source IP address 00318 valid = TRUE; 00319 } 00320 else if(ipv6IsOnLink(interface, &pseudoHeader->ipv6Data.srcAddr)) 00321 { 00322 //The source IP address is on the local link 00323 valid = TRUE; 00324 } 00325 else 00326 { 00327 //Only accept responses that originate from the local link, and 00328 //silently discard any other response packets 00329 valid = FALSE; 00330 } 00331 } 00332 else 00333 #endif 00334 //Invalid packet received? 00335 { 00336 //Discard the response packet 00337 valid = FALSE; 00338 } 00339 00340 //Return flag value 00341 return valid; 00342 } 00343 00344 00345 /** 00346 * @brief Create an empty mDNS message 00347 * @param[in,out] message Newly created mDNS message 00348 * @param[in] queryResponse This flag specifies whether the message is a query or a response 00349 * @return Error code 00350 **/ 00351 00352 error_t mdnsCreateMessage(MdnsMessage *message, bool_t queryResponse) 00353 { 00354 error_t error; 00355 00356 //Allocate a memory buffer to hold the mDNS message 00357 message->buffer = udpAllocBuffer(MDNS_MESSAGE_MAX_SIZE, &message->offset); 00358 00359 //Successful memory allocation? 00360 if(message->buffer != NULL) 00361 { 00362 //Point to the mDNS message header 00363 message->dnsHeader = netBufferAt(message->buffer, message->offset); 00364 00365 //Sanity check 00366 if(message->dnsHeader != NULL) 00367 { 00368 //Format mDNS message header 00369 message->dnsHeader->id = 0; 00370 message->dnsHeader->opcode = DNS_OPCODE_QUERY; 00371 message->dnsHeader->tc = 0; 00372 message->dnsHeader->rd = 0; 00373 message->dnsHeader->ra = 0; 00374 message->dnsHeader->z = 0; 00375 message->dnsHeader->rcode = DNS_RCODE_NO_ERROR; 00376 message->dnsHeader->qdcount = 0; 00377 message->dnsHeader->ancount = 0; 00378 message->dnsHeader->nscount = 0; 00379 message->dnsHeader->arcount = 0; 00380 00381 //Query or response mDNS message? 00382 if(!queryResponse) 00383 { 00384 //In query messages, QR and AA bits must be set to zero 00385 message->dnsHeader->qr = 0; 00386 message->dnsHeader->aa = 0; 00387 } 00388 else 00389 { 00390 //In response messages, QR and AA bits must be set to one 00391 message->dnsHeader->qr = 1; 00392 message->dnsHeader->aa = 1; 00393 } 00394 00395 //Number of shared resource records 00396 message->sharedRecordCount = 0; 00397 //Length of the mDNS message 00398 message->length = sizeof(DnsHeader); 00399 00400 //Successful processing 00401 error = NO_ERROR; 00402 } 00403 else 00404 { 00405 //Clean up side effects 00406 mdnsDeleteMessage(message); 00407 00408 //Report an error 00409 error = ERROR_FAILURE; 00410 } 00411 } 00412 else 00413 { 00414 //Failed to allocate memory 00415 error = ERROR_OUT_OF_RESOURCES; 00416 } 00417 00418 //Return status code 00419 return error; 00420 } 00421 00422 00423 /** 00424 * @brief release a mDNS message 00425 * @param[in] message mDNS message to be released 00426 **/ 00427 00428 void mdnsDeleteMessage(MdnsMessage *message) 00429 { 00430 //Valid mDNS message? 00431 if(message->buffer != NULL) 00432 { 00433 //Free previously allocated memory 00434 netBufferFree(message->buffer); 00435 00436 //The mDNS message is no more valid 00437 message->buffer = NULL; 00438 message->length = 0; 00439 } 00440 } 00441 00442 00443 /** 00444 * @brief Send mDNS message 00445 * @param[in] interface Underlying network interface 00446 * @param[in] message mDNS message to be sent 00447 * @param[in] destIpAddr Destination IP address (optional parameter) 00448 * @param[in] destPort Destination port 00449 * @return Error code 00450 **/ 00451 00452 error_t mdnsSendMessage(NetInterface *interface, const MdnsMessage *message, 00453 const IpAddr *destIpAddr, uint_t destPort) 00454 { 00455 error_t error; 00456 IpAddr ipAddr; 00457 00458 //Make sure the mDNS message is valid 00459 if(message->buffer == NULL) 00460 return ERROR_FAILURE; 00461 00462 //Convert 16-bit values to network byte order 00463 message->dnsHeader->qdcount = htons(message->dnsHeader->qdcount); 00464 message->dnsHeader->nscount = htons(message->dnsHeader->nscount); 00465 message->dnsHeader->ancount = htons(message->dnsHeader->ancount); 00466 message->dnsHeader->arcount = htons(message->dnsHeader->arcount); 00467 00468 //Start of exception handling block 00469 do 00470 { 00471 //Adjust the length of the multi-part buffer 00472 error = netBufferSetLength(message->buffer, message->offset + message->length); 00473 //Any error to report? 00474 if(error) 00475 break; 00476 00477 //Debug message 00478 TRACE_INFO("Sending mDNS message (%" PRIuSIZE " bytes)...\r\n", message->length); 00479 //Dump message 00480 dnsDumpMessage(message->dnsHeader, message->length); 00481 00482 //Check whether the message should be sent to a specific IP address 00483 if(destIpAddr != NULL) 00484 { 00485 //All multicast DNS responses should be sent with an IP TTL set to 255 00486 error = udpSendDatagramEx(interface, MDNS_PORT, destIpAddr, 00487 destPort, message->buffer, message->offset, MDNS_DEFAULT_IP_TTL); 00488 //Any error to report? 00489 if(error) 00490 break; 00491 } 00492 else 00493 { 00494 #if (IPV4_SUPPORT == ENABLED) 00495 //Select the relevant multicast address (224.0.0.251) 00496 ipAddr.length = sizeof(Ipv4Addr); 00497 ipAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; 00498 00499 //All multicast DNS queries should be sent with an IP TTL set to 255 00500 error = udpSendDatagramEx(interface, MDNS_PORT, &ipAddr, 00501 MDNS_PORT, message->buffer, message->offset, MDNS_DEFAULT_IP_TTL); 00502 //Any error to report? 00503 if(error) 00504 break; 00505 #endif 00506 00507 #if (IPV6_SUPPORT == ENABLED) 00508 //Select the relevant multicast address (ff02::fb) 00509 ipAddr.length = sizeof(Ipv6Addr); 00510 ipAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; 00511 00512 //All multicast DNS queries should be sent with an IP TTL set to 255 00513 error = udpSendDatagramEx(interface, MDNS_PORT, &ipAddr, 00514 MDNS_PORT, message->buffer, message->offset, MDNS_DEFAULT_IP_TTL); 00515 //Any error to report? 00516 if(error) 00517 break; 00518 #endif 00519 } 00520 00521 //End of exception handling block 00522 } while(0); 00523 00524 //Return status code 00525 return error; 00526 } 00527 00528 00529 /** 00530 * @brief Encode instance, service and domain names using the DNS name notation 00531 * @param[in] instance Instance name 00532 * @param[in] service Service name 00533 * @param[in] domain Domain name 00534 * @param[out] dest Pointer to the encoded name (optional parameter) 00535 * @return Length of the encoded domain name 00536 **/ 00537 00538 size_t mdnsEncodeName(const char_t *instance, const char_t *service, 00539 const char_t *domain, uint8_t *dest) 00540 { 00541 size_t n; 00542 size_t length; 00543 00544 //Total length of the encoded name 00545 length = 0; 00546 00547 //Any instance name? 00548 if(*instance != '\0') 00549 { 00550 //Encode instance name 00551 n = dnsEncodeName(instance, dest); 00552 00553 //Failed to encode instance name? 00554 if(!n) 00555 return 0; 00556 00557 //Update the length of the encoded name 00558 length += n; 00559 } 00560 00561 //Any service name? 00562 if(*service != '\0') 00563 { 00564 //If an instance name precedes the service name, then 00565 //remove the null label 00566 if(length > 0) 00567 length--; 00568 00569 //Encode service name 00570 if(dest != NULL) 00571 n = dnsEncodeName(service, dest + length); 00572 else 00573 n = dnsEncodeName(service, NULL); 00574 00575 //Failed to encode instance name? 00576 if(!n) 00577 return 0; 00578 00579 //Update the length of the encoded name 00580 length += n; 00581 } 00582 00583 //Skip the separator that may precede the domain name 00584 if(*domain == '.') 00585 domain++; 00586 00587 //Any domain name to encode? 00588 if(*domain != '\0') 00589 { 00590 //If an instance or a service name precedes the domain name, then 00591 //remove the null label 00592 if(length > 0) 00593 length--; 00594 00595 //Encode domain name 00596 if(dest != NULL) 00597 n = dnsEncodeName(domain, dest + length); 00598 else 00599 n = dnsEncodeName(domain, NULL); 00600 00601 //Failed to encode instance name? 00602 if(!n) 00603 return 0; 00604 00605 //Update the length of the encoded name 00606 length += n; 00607 } 00608 00609 //Return the length of the encoded string 00610 return length; 00611 } 00612 00613 00614 /** 00615 * @brief Compare instance, service and domain names 00616 * @param[in] message Pointer to the DNS message 00617 * @param[in] length Length of the DNS message 00618 * @param[in] pos Offset of the encoded name 00619 * @param[in] instance Instance name 00620 * @param[in] service Service name 00621 * @param[in] domain Domain name 00622 * @param[in] level Current level of recursion 00623 * @return The function returns 0 if the domain names match, -1 if the first 00624 * domain name lexicographically precedes the second name, or 1 if the 00625 * second domain name lexicographically precedes the first name 00626 **/ 00627 00628 int_t mdnsCompareName(const DnsHeader *message, size_t length, size_t pos, 00629 const char_t *instance, const char_t *service, const char_t *domain, uint_t level) 00630 { 00631 int_t res; 00632 size_t n; 00633 size_t pointer; 00634 uint8_t *p; 00635 00636 //Check parameters 00637 if(instance == NULL || service == NULL || domain == NULL) 00638 return -2; 00639 00640 //Recursion limit exceeded? 00641 if(level >= DNS_NAME_MAX_RECURSION) 00642 return -2; 00643 00644 //Cast the DNS message to byte array 00645 p = (uint8_t *) message; 00646 00647 //Skip the separator that may precede the domain name 00648 if(*domain == '.') 00649 domain++; 00650 00651 //Parse encoded domain name 00652 while(pos < length) 00653 { 00654 //Retrieve the length of the current label 00655 n = p[pos]; 00656 00657 //End marker found? 00658 if(n == 0) 00659 { 00660 //The domain name which still has remaining data is deemed 00661 //lexicographically later 00662 if(*instance != '\0' || *service != '\0' || *domain != '\0') 00663 return -1; 00664 00665 //The domain names match each other 00666 return 0; 00667 } 00668 //Compression tag found? 00669 if(n >= DNS_COMPRESSION_TAG) 00670 { 00671 //Malformed DNS message? 00672 if((pos + 1) >= length) 00673 return -2; 00674 00675 //Read the most significant byte of the pointer 00676 pointer = (p[pos] & ~DNS_COMPRESSION_TAG) << 8; 00677 //Read the least significant byte of the pointer 00678 pointer |= p[pos + 1]; 00679 00680 //Compare the remaining part 00681 res = mdnsCompareName(message, length, pointer, 00682 instance, service, domain, level + 1); 00683 00684 //Return comparison result 00685 return res; 00686 } 00687 else 00688 { 00689 //Advance data pointer 00690 pos++; 00691 00692 //Malformed DNS message? 00693 if((pos + n) > length) 00694 return -2; 00695 00696 //Compare current label 00697 if(*instance != '\0') 00698 { 00699 //Compare instance name 00700 res = strncasecmp((char_t *) p + pos, instance, n); 00701 //Any mismatch? 00702 if(res) 00703 return res; 00704 00705 //Advance data pointer 00706 instance += n; 00707 00708 //The instance name which still has remaining data is deemed 00709 //lexicographically later 00710 if(*instance != '\0' && *instance != '.') 00711 return -1; 00712 00713 //Skip the separator character, if any 00714 if(*instance == '.') 00715 instance++; 00716 } 00717 else if(*service != '\0') 00718 { 00719 //Compare service name 00720 res = strncasecmp((char_t *) p + pos, service, n); 00721 //Any mismatch? 00722 if(res) 00723 return res; 00724 00725 //Advance data pointer 00726 service += n; 00727 00728 //The service name which still has remaining data is deemed 00729 //lexicographically later 00730 if(*service != '\0' && *service != '.') 00731 return -1; 00732 00733 //Any separator in service name? 00734 if(*service == '.') 00735 service++; 00736 } 00737 else 00738 { 00739 //Compare domain name 00740 res = strncasecmp((char_t *) p + pos, domain, n); 00741 //Any mismatch? 00742 if(res) 00743 return res; 00744 00745 //Advance data pointer 00746 domain += n; 00747 00748 //The domain name which still has remaining data is deemed 00749 //lexicographically later 00750 if(*domain != '\0' && *domain != '.') 00751 return -1; 00752 00753 //Any separator in domain name? 00754 if(*domain == '.') 00755 domain++; 00756 } 00757 00758 //Advance data pointer 00759 pos += n; 00760 } 00761 } 00762 00763 //Malformed DNS message 00764 return -2; 00765 } 00766 00767 00768 /** 00769 * @brief Compare resource records 00770 * @param[in] message1 Pointer to the first mDNS message 00771 * @param[in] offset1 Offset of the first but of the resource record 00772 * @param[in] record1 Pointer the first resource record 00773 * @param[in] message2 Pointer to the second mDNS message 00774 * @param[in] offset2 Offset of the first but of the resource record 00775 * @param[in] record2 Pointer the second resource record 00776 * @return The function returns 0 if the resource records match, -1 if the first 00777 * resource record lexicographically precedes the second one, or 1 if the 00778 * second resource record lexicographically precedes the first one 00779 **/ 00780 00781 int_t mdnsCompareRecord(const MdnsMessage *message1, size_t offset1, 00782 const DnsResourceRecord *record1, const MdnsMessage *message2, 00783 size_t offset2, const DnsResourceRecord *record2) 00784 { 00785 int_t res; 00786 size_t n1; 00787 size_t n2; 00788 uint16_t value1; 00789 uint16_t value2; 00790 00791 //Convert the record class to host byte order 00792 value1 = ntohs(record1->rclass); 00793 value2 = ntohs(record2->rclass); 00794 00795 //Discard cache-flush bit 00796 value1 &= ~MDNS_RCLASS_CACHE_FLUSH; 00797 value2 &= ~MDNS_RCLASS_CACHE_FLUSH; 00798 00799 //The determination of lexicographically later record is performed by 00800 //first comparing the record class (excluding the cache-flush bit) 00801 if(value1 < value2) 00802 return -1; 00803 else if(value1 > value2) 00804 return 1; 00805 00806 //Convert the record type to host byte order 00807 value1 = ntohs(record1->rtype); 00808 value2 = ntohs(record2->rtype); 00809 00810 //Then compare the record type 00811 if(value1 < value2) 00812 return -1; 00813 else if(value1 > value2) 00814 return 1; 00815 00816 //If the rrtype and rrclass both match, then the rdata is compared 00817 if(value1 == DNS_RR_TYPE_NS || value1 == DNS_RR_TYPE_SOA || 00818 value1 == DNS_RR_TYPE_CNAME || value1 == DNS_RR_TYPE_PTR) 00819 { 00820 //Compute the offset of the first byte of the rdata 00821 n1 = record1->rdata - (uint8_t *) message1->dnsHeader; 00822 n2 = record2->rdata - (uint8_t *) message2->dnsHeader; 00823 00824 //The names must be uncompressed before comparison 00825 res = dnsCompareEncodedName(message1->dnsHeader, message1->length, 00826 n1, message2->dnsHeader, message2->length, n2, 0); 00827 } 00828 else 00829 { 00830 //Retrieve the length of the rdata fields 00831 n1 = htons(record1->rdlength); 00832 n2 = htons(record2->rdlength); 00833 00834 //The bytes of the raw uncompressed rdata are compared in turn, interpreting 00835 //the bytes as eight-bit unsigned values, until a byte is found whose value 00836 //is greater than that of its counterpart (in which case, the rdata whose 00837 //byte has the greater value is deemed lexicographically later) or one of the 00838 //resource records runs out of rdata (in which case, the resource record which 00839 //still has remaining data first is deemed lexicographically later) 00840 if(n1 < n2) 00841 { 00842 //Raw comparison of the binary content of the rdata 00843 res = memcmp(record1->rdata, record2->rdata, n1); 00844 00845 //Check comparison result 00846 if(!res) 00847 { 00848 //The first resource records runs out of rdata 00849 res = -1; 00850 } 00851 } 00852 else if(n1 > n2) 00853 { 00854 //Raw comparison of the binary content of the rdata 00855 res = memcmp(record1->rdata, record2->rdata, n2); 00856 00857 //Check comparison result 00858 if(!res) 00859 { 00860 //The second resource records runs out of rdata 00861 res = 1; 00862 } 00863 } 00864 else 00865 { 00866 //Raw comparison of the binary content of the rdata 00867 res = memcmp(record1->rdata, record2->rdata, n1); 00868 } 00869 } 00870 00871 //Return comparison result 00872 return res; 00873 } 00874 00875 00876 /** 00877 * @brief Check for duplicate resource records 00878 * @param[in] message Pointer to the mDNS message 00879 * @param[in] instance Instance name 00880 * @param[in] service Service name 00881 * @param[in] domain Domain name 00882 * @param[in] rtype Resource record type 00883 * @return The function returns TRUE is the specified resource record is a 00884 * duplicate. Otherwise FALSE is returned 00885 **/ 00886 00887 bool_t mdnsCheckDuplicateRecord(const MdnsMessage *message, const char_t *instance, 00888 const char_t *service, const char_t *domain, uint16_t rtype) 00889 { 00890 uint_t i; 00891 uint_t k; 00892 size_t n; 00893 size_t offset; 00894 uint16_t rclass; 00895 bool_t duplicate; 00896 DnsResourceRecord *record; 00897 00898 //Clear flag 00899 duplicate = FALSE; 00900 00901 //Point to the first question 00902 offset = sizeof(DnsHeader); 00903 00904 //Parse the Question Section 00905 for(i = 0; i < message->dnsHeader->qdcount; i++) 00906 { 00907 //Parse domain name 00908 offset = dnsParseName(message->dnsHeader, message->length, offset, NULL, 0); 00909 //Invalid name? 00910 if(!offset) 00911 break; 00912 00913 //Point to the next question 00914 offset += sizeof(DnsQuestion); 00915 //Make sure the mDNS message is valid 00916 if(offset > message->length) 00917 break; 00918 } 00919 00920 //Successful processing? 00921 if(i == message->dnsHeader->qdcount) 00922 { 00923 //Compute the total number of resource records 00924 k = message->dnsHeader->ancount + message->dnsHeader->nscount + 00925 message->dnsHeader->arcount; 00926 00927 //Loop through the resource records 00928 for(i = 0; i < k; i++) 00929 { 00930 //Parse resource record name 00931 n = dnsParseName(message->dnsHeader, message->length, offset, NULL, 0); 00932 //Invalid name? 00933 if(!n) 00934 break; 00935 00936 //Point to the associated resource record 00937 record = DNS_GET_RESOURCE_RECORD(message->dnsHeader, n); 00938 //Point to the resource data 00939 n += sizeof(DnsResourceRecord); 00940 00941 //Make sure the resource record is valid 00942 if(n > message->length) 00943 break; 00944 if((n + ntohs(record->rdlength)) > message->length) 00945 break; 00946 00947 //Convert the record class to host byte order 00948 rclass = ntohs(record->rclass); 00949 //Discard cache-flush bit 00950 rclass &= ~MDNS_RCLASS_CACHE_FLUSH; 00951 00952 //Check the class and the type of the resource record 00953 if(rclass == DNS_RR_CLASS_IN && ntohs(record->rtype) == rtype) 00954 { 00955 //Compare resource record name 00956 if(!mdnsCompareName(message->dnsHeader, message->length, 00957 offset, instance, service, domain, 0)) 00958 { 00959 //The resource record is already present in the Answer Section 00960 duplicate = TRUE; 00961 //We are done 00962 break; 00963 } 00964 } 00965 00966 //Point to the next resource record 00967 offset = n + ntohs(record->rdlength); 00968 } 00969 } 00970 00971 //The function returns TRUE is the specified resource record is a duplicate 00972 return duplicate; 00973 } 00974 00975 #endif 00976
Generated on Tue Jul 12 2022 17:10:14 by
1.7.2