error_t mdnsAddIpv6ResourceRecord(NetInterface *interface, DnsHeader *message, size_t *length, bool_t flush) { #if (IPV6_SUPPORT == ENABLED) size_t n; size_t offset; DnsResourceRecord *resourceRecord; //Set the position to the end of the buffer offset = *length; //The first pass calculates the length of the DNS encoded host name n = mdnsEncodeName(interface->hostname, "", ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the host name using the DNS name notation offset += mdnsEncodeName(interface->hostname, "", ".local", (uint8_t *) message + offset); //Consider the length of the resource record itself n = sizeof(DnsResourceRecord) + sizeof(Ipv6Addr); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //Point to the corresponding resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, offset); //Check whether the cache-fluch bit should be set if(flush) resourceRecord->rclass = HTONS(MDNS_RCLASS_CACHE_FLUSH | DNS_RR_CLASS_IN); else resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN); //Fill in resource record resourceRecord->rtype = HTONS(DNS_RR_TYPE_AAAA); resourceRecord->ttl = HTONL(MDNS_DEFAULT_RESOURCE_RECORD_TTL); resourceRecord->rdlength = HTONS(sizeof(Ipv6Addr)); //Copy IPv6 address ipv6CopyAddr(resourceRecord->rdata, &interface->ipv6Config.linkLocalAddr); //Number of resource records in the answer section message->ancount++; //Update the length of the mDNS response message *length = offset + n; #endif //Successful processing return NO_ERROR; }
error_t dnsSdAddTxtResourceRecord(NetInterface *interface, const DnsSdService *service, DnsHeader *message, size_t *length) { size_t i; size_t j; size_t k; size_t n; size_t offset; DnsResourceRecord *resourceRecord; //Set the position to the end of the buffer offset = *length; //The first pass calculates the length of the DNS encoded instance name n = mdnsEncodeName(interface->instanceName, service->name, ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the instance name using DNS notation offset += mdnsEncodeName(interface->instanceName, service->name, ".local", (uint8_t *) message + offset); //Consider the length of the resource record itself if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //Point to the corresponding resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, offset); //Fill in resource record resourceRecord->rtype = HTONS(DNS_RR_TYPE_TXT); resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN); resourceRecord->ttl = HTONL(DNS_SD_DEFAULT_RESOURCE_RECORD_TTL); resourceRecord->rdlength = 0; //Advance write index offset += sizeof(DnsResourceRecord); //Point to the beginning of the information string i = 0; j = 0; //Point to the beginning of the resulting TXT record data k = 0; //Format TXT record while(1) { //End of text data? if(service->info[i] == '\0' || service->info[i] == ';') { //Calculate the length of the text data n = MIN(i - j, 255); //Check the length of the resulting mDNS message if((offset + resourceRecord->rdlength + n + 1) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //Write length field resourceRecord->rdata[k] = n; //Write text data memcpy(resourceRecord->rdata + k + 1, service->info + j, n); //Jump to the next text data j = i + 1; //Advance write index k += n + 1; //Update the length of the TXT record resourceRecord->rdlength += n + 1; //End of string detected? if(service->info[i] == '\0') break; } //Advance read index i++; } //Empty TXT record? if(!resourceRecord->rdlength) { //Sanity check if((offset + 1) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //An empty TXT record shall contain a single zero byte resourceRecord->rdata[0] = 0; resourceRecord->rdlength = 1; } //Get the length of the TXT record n = resourceRecord->rdlength; //Convert length field to network byte order resourceRecord->rdlength = htons(n); //Number of resource records in the answer section message->ancount++; //Update the length of the DNS message *length = offset + n; //Successful processing return NO_ERROR; }
error_t dnsSdAddSrvResourceRecord(NetInterface *interface, const DnsSdService *service, DnsHeader *message, size_t *length) { size_t n; size_t offset; DnsSrvResourceRecord *resourceRecord; //Set the position to the end of the buffer offset = *length; //The first pass calculates the length of the DNS encoded instance name n = mdnsEncodeName(interface->instanceName, service->name, ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the instance name using DNS notation offset += mdnsEncodeName(interface->instanceName, service->name, ".local", (uint8_t *) message + offset); //Consider the length of the resource record itself if((offset + sizeof(DnsSrvResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //Point to the corresponding resource record resourceRecord = (DnsSrvResourceRecord *) DNS_GET_RESOURCE_RECORD(message, offset); //Fill in resource record resourceRecord->rtype = HTONS(DNS_RR_TYPE_SRV); resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN); resourceRecord->ttl = HTONL(DNS_SD_DEFAULT_RESOURCE_RECORD_TTL); resourceRecord->priority = htons(service->priority); resourceRecord->weight = htons(service->weight); resourceRecord->port = htons(service->port); //Advance write index offset += sizeof(DnsSrvResourceRecord); //The first pass calculates the length of the DNS encoded target name n = mdnsEncodeName("", interface->hostname, ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the target name using DNS notation n = mdnsEncodeName("", interface->hostname, ".local", resourceRecord->target); //Calculate data length resourceRecord->rdlength = htons(sizeof(DnsSrvResourceRecord) - sizeof(DnsResourceRecord) + n); //Number of resource records in the answer section message->ancount++; //Update the length of the DNS message *length = offset + n; //Successful processing return NO_ERROR; }
error_t dnsSdAddPtrResourceRecord(NetInterface *interface, const DnsSdService *service, bool_t serviceTypeEnum, DnsHeader *message, size_t *length) { size_t n; size_t offset; DnsResourceRecord *resourceRecord; //Set the position to the end of the buffer offset = *length; //Check whether the PTR record is sent in response to a //service type enumeration meta-query if(serviceTypeEnum) { //The first pass calculates the length of the DNS encoded service name n = mdnsEncodeName("", "_services._dns-sd._udp", ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the service name using the DNS name notation offset += mdnsEncodeName("", "_services._dns-sd._udp", ".local", (uint8_t *) message + offset); } else { //The first pass calculates the length of the DNS encoded service name n = mdnsEncodeName("", service->name, ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //Encode the service name using the DNS name notation offset += mdnsEncodeName("", service->name, ".local", (uint8_t *) message + offset); } //Consider the length of the resource record itself if((offset + sizeof(DnsResourceRecord)) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //Point to the corresponding resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, offset); //Fill in resource record resourceRecord->rtype = HTONS(DNS_RR_TYPE_PTR); resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN); resourceRecord->ttl = HTONL(DNS_SD_DEFAULT_RESOURCE_RECORD_TTL); //Advance write index offset += sizeof(DnsResourceRecord); //Check whether the PTR record is sent in response to a //service type enumeration meta-query if(serviceTypeEnum) { //The first pass calculates the length of the DNS encoded service name n = mdnsEncodeName("", service->name, ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the service name using DNS notation n = mdnsEncodeName("", service->name, ".local", resourceRecord->rdata); } else { //The first pass calculates the length of the DNS encoded instance name n = mdnsEncodeName(interface->instanceName, service->name, ".local", NULL); //Check the length of the resulting mDNS message if((offset + n) > MDNS_MESSAGE_MAX_SIZE) return ERROR_MESSAGE_TOO_LONG; //The second pass encodes the instance name using DNS notation n = mdnsEncodeName(interface->instanceName, service->name, ".local", resourceRecord->rdata); } //Convert length field to network byte order resourceRecord->rdlength = htons(n); //Number of resource records in the answer section message->ancount++; //Update the length of the DNS message *length = offset + n; //Successful processing return NO_ERROR; }
void nbnsProcessResponse(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NbnsHeader *message, size_t length) { uint_t i; size_t pos; DnsCacheEntry *entry; DnsResourceRecord *resourceRecord; NbnsAddrEntry *addrEntry; //The NBNS response shall contain one answer if(ntohs(message->qdcount) != 0 && ntohs(message->ancount) != 1) return; //Parse NetBIOS name pos = nbnsParseName(message, length, sizeof(DnsHeader), NULL); //Invalid name? if(!pos) return; //Point to the associated resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, pos); //Point to the resource data pos += sizeof(DnsResourceRecord); //Make sure the resource record is valid if(pos > length) return; if((pos + ntohs(resourceRecord->rdlength)) > length) return; //Check the class and the type of the resource record if(ntohs(resourceRecord->rclass) != DNS_RR_CLASS_IN) return; if(ntohs(resourceRecord->rtype) != DNS_RR_TYPE_NB) return; //Verify the length of the data field if(ntohs(resourceRecord->rdlength) < sizeof(NbnsAddrEntry)) return; //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Loop through DNS cache entries for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //NBNS name resolution in progress? if(entry->state == DNS_STATE_IN_PROGRESS && entry->protocol == HOST_NAME_RESOLVER_NBNS && entry->type == HOST_TYPE_IPV4) { //Compare identifiers if(entry->id == ntohs(message->id)) { //Compare NetBIOS names if(nbnsCompareName(message, length, sizeof(DnsHeader), entry->name)) { //Point to the address entry array addrEntry = (NbnsAddrEntry *) resourceRecord->rdata; //Copy the IPv4 address entry->ipAddr.length = sizeof(Ipv4Addr); entry->ipAddr.ipv4Addr = addrEntry->addr; //Save current time entry->timestamp = osGetSystemTime(); //Save TTL value entry->timeout = ntohl(resourceRecord->ttl) * 1000; //Limit the lifetime of the NBNS cache entries entry->timeout = MIN(entry->timeout, NBNS_MAX_LIFETIME); //Host name successfully resolved entry->state = DNS_STATE_RESOLVED; } } } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); }
error_t nbnsSendResponse(NetInterface *interface, const IpAddr *destIpAddr, uint16_t destPort, uint16_t id) { error_t error; size_t length; size_t offset; ChunkedBuffer *buffer; NbnsHeader *message; NbnsAddrEntry *addrEntry; DnsResourceRecord *resourceRecord; //Allocate a memory buffer to hold the NBNS response message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the NBNS header message = chunkedBufferAt(buffer, offset); //Take the identifier from the query message message->id = id; //Format NBNS response header message->qr = 1; message->opcode = DNS_OPCODE_QUERY; message->aa = 1; message->tc = 0; message->rd = 1; message->ra = 1; message->z = 0; message->b = 0; message->rcode = DNS_RCODE_NO_ERROR; //The NBNS response contains 1 answer resource record message->qdcount = 0; message->ancount = HTONS(1); message->nscount = 0; message->arcount = 0; //NBNS response message length length = sizeof(DnsHeader); //Encode the host name using the NBNS name notation length += nbnsEncodeName(interface->hostname, (uint8_t *) message + length); //Point to the corresponding resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, length); //Fill in resource record resourceRecord->rtype = HTONS(DNS_RR_TYPE_NB); resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN); resourceRecord->ttl = HTONL(NBNS_DEFAULT_RESOURCE_RECORD_TTL); resourceRecord->rdlength = HTONS(sizeof(NbnsAddrEntry)); //Point to the address entry array addrEntry = (NbnsAddrEntry *) resourceRecord->rdata; //Fill in address entry addrEntry->flags = HTONS(NBNS_G_UNIQUE | NBNS_ONT_BNODE); addrEntry->addr = interface->ipv4Config.addr; //Update the length of the NBNS response message length += sizeof(DnsResourceRecord) + sizeof(NbnsAddrEntry); //Adjust the length of the multi-part buffer chunkedBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage((DnsHeader *) message, length); //A response packet is always sent to the source UDP port and //source IP address of the request packet error = udpSendDatagramEx(interface, NBNS_PORT, destIpAddr, destPort, buffer, offset, IPV4_DEFAULT_TTL); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t dnsParseResponse(DnsHeader *dnsMessage, size_t length, uint16_t identifier, IpAddr *ipAddr) { char_t *name; uint_t i; size_t pos; Ipv4Addr ipv4Addr; DnsQuestion *dnsQuestion; DnsResourceRecord *dnsResourceRecord; //Clear host address memset(ipAddr, 0, sizeof(IpAddr)); //Ensure the DNS header is valid if(length < sizeof(DnsHeader)) return ERROR_INVALID_HEADER; //Compare identifier against expected one if(dnsMessage->identifier != identifier) return ERROR_WRONG_IDENTIFIER; //Check message type if(!(dnsMessage->flags & DNS_FLAG_QR)) return ERROR_INVALID_HEADER; //Make sure recursion is available if(!(dnsMessage->flags & DNS_FLAG_RA)) return ERROR_INVALID_HEADER; //Check return code if(dnsMessage->flags & DNS_RCODE_MASK) return ERROR_FAILURE; //Debug message TRACE_DEBUG("DNS response message received (%u bytes)...\r\n", length); //Allocate memory buffer to hold the decoded name name = memPoolAlloc(DNS_NAME_MAX_SIZE); //Failed to allocate memory if(!name) return ERROR_OUT_OF_MEMORY; //Debug message TRACE_DEBUG("%u questions found...\r\n", ntohs(dnsMessage->questionCount)); //Point to the first question pos = sizeof(DnsHeader); //Parse questions for(i = 0; i < ntohs(dnsMessage->questionCount); i++) { //Decode domain name pos = dnsDecodeName(dnsMessage, length, pos, name); //Name decoding failed? if(!pos) { //Free previously allocated memory osMemFree(name); //Report an error return ERROR_INVALID_NAME; } //Point to the associated resource record dnsQuestion = DNS_GET_RESOURCE_RECORD(dnsMessage, pos); //Debug message TRACE_DEBUG(" name = %s\r\n", name); TRACE_DEBUG(" queryType = %u\r\n", ntohs(dnsQuestion->queryType)); TRACE_DEBUG(" queryClass = %u\r\n", ntohs(dnsQuestion->queryClass)); //Point to the next question pos += sizeof(DnsQuestion); } //Debug message TRACE_INFO("%u answer RRs found...\r\n", ntohs(dnsMessage->answerRecordCount)); //Parse answer resource records for(i = 0; i < ntohs(dnsMessage->answerRecordCount); i++) { //Decode domain name pos = dnsDecodeName(dnsMessage, length, pos, name); //Name decoding failed? if(!pos) { //Free previously allocated memory osMemFree(name); //Report an error return ERROR_INVALID_NAME; } //Point to the associated resource record dnsResourceRecord = DNS_GET_RESOURCE_RECORD(dnsMessage, pos); //Debug message TRACE_DEBUG(" name = %s\r\n", name); TRACE_DEBUG(" type = %u\r\n", ntohs(dnsResourceRecord->type)); TRACE_DEBUG(" class = %u\r\n", ntohs(dnsResourceRecord->class)); TRACE_DEBUG(" ttl = %u\r\n", ntohl(dnsResourceRecord->timeToLive)); TRACE_DEBUG(" dataLength = %u\r\n", ntohs(dnsResourceRecord->dataLength)); //Check the type of the resource record switch(ntohs(dnsResourceRecord->type)) { //IPv4 address record found? case DNS_RR_TYPE_A: //Verify the length of the data field if(ntohs(dnsResourceRecord->dataLength) != sizeof(Ipv4Addr)) break; //Copy the IP address ipv4CopyAddr(&ipv4Addr, dnsResourceRecord->data); //Save the first IP address found in resource records if(!ipAddr->length) { ipAddr->length = sizeof(Ipv4Addr); ipAddr->ipv4Addr = ipv4Addr; } //Debug message TRACE_DEBUG(" data = %s\r\n", ipv4AddrToString(ipv4Addr, NULL)); break; //IPv6 address record found? /*case DNS_RR_TYPE_AAAA: //Verify the length of the data field if(ntohs(dnsResourceRecord->dataLength) != sizeof(Ipv6Addr)) break; //Copy the IP address //ipv4CopyAddr(&ipv4Addr, dnsResourceRecord->data); //Save the first IP address found in resource records if(!ipAddr->length) { ipAddr->length = sizeof(Ipv6Addr); ipv6CopyAddr(&ipAddr->ipv6Addr, dnsResourceRecord->data); } //Debug message //TRACE_DEBUG(" data = %s\r\n", ipv4AddrToString(ipv4Addr, NULL)); break;*/ //Name server record found? case DNS_RR_TYPE_NS: //Canonical name record found? case DNS_RR_TYPE_CNAME: //Pointer record? case DNS_RR_TYPE_PTR: //Decode the canonical name dnsDecodeName(dnsMessage, length, pos + sizeof(DnsResourceRecord), name); //Debug message TRACE_DEBUG(" data = %s\r\n", name); break; //Unknown record default: break; } //Point to the next resource record pos += sizeof(DnsResourceRecord) + ntohs(dnsResourceRecord->dataLength); } //Debug message TRACE_INFO("%u authority RRs found...\r\n", ntohs(dnsMessage->authorityRecordCount)); TRACE_INFO("%u additional RRs found...\r\n", ntohs(dnsMessage->additionalRecordCount)); //Free previously allocated memory osMemFree(name); //DNS response successfully decoded return NO_ERROR; }
void dnsProcessResponse(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const ChunkedBuffer *buffer, size_t offset, void *params) { uint_t i; uint_t j; size_t n; size_t pos; size_t length; DnsHeader *message; DnsQuestion *question; DnsResourceRecord *resourceRecord; DnsCacheEntry *entry; //Retrieve the length of the DNS message length = chunkedBufferGetLength(buffer) - offset; //Ensure the DNS message is valid if(length < sizeof(DnsHeader)) return; if(length > DNS_MESSAGE_MAX_SIZE) return; //Point to the DNS message header message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("DNS message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); //Acquire exclusive access to the DNS cache osMutexAcquire(dnsCacheMutex); //Loop through DNS cache entries for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //DNS name resolution in progress? if(entry->state == DNS_STATE_IN_PROGRESS && entry->protocol == HOST_NAME_RESOLVER_DNS) { //Check destination port number if(entry->port == ntohs(udpHeader->destPort)) { //Compare identifier against expected one if(ntohs(message->id) != entry->id) break; //Check message type if(!message->qr) break; //The DNS message shall contain one question if(ntohs(message->qdcount) != 1) break; //Point to the first question pos = sizeof(DnsHeader); //Parse domain name n = dnsParseName(message, length, pos, NULL, 0); //Invalid name? if(!n) break; //Malformed mDNS message? if((n + sizeof(DnsQuestion)) > length) break; //Compare domain name if(!dnsCompareName(message, length, pos, entry->name, 0)) break; //Point to the corresponding entry question = DNS_GET_QUESTION(message, n); //Check the class of the query if(ntohs(question->qclass) != DNS_RR_CLASS_IN) break; //Check the type of the query if(entry->type == HOST_TYPE_IPV4 && ntohs(question->qtype) != DNS_RR_TYPE_A) break; if(entry->type == HOST_TYPE_IPV6 && ntohs(question->qtype) != DNS_RR_TYPE_AAAA) break; //Make sure recursion is available if(!message->ra) { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); //Exit immediately break; } //Check return code if(message->rcode != DNS_RCODE_NO_ERROR) { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); //Exit immediately break; } //Point to the first answer pos = n + sizeof(DnsQuestion); //Parse answer resource records for(j = 0; j < ntohs(message->ancount); j++) { //Parse domain name pos = dnsParseName(message, length, pos, NULL, 0); //Invalid name? if(!pos) break; //Point to the associated resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, pos); //Point to the resource data pos += sizeof(DnsResourceRecord); //Make sure the resource record is valid if(pos >= length) break; if((pos + ntohs(resourceRecord->rdlength)) > length) break; #if (IPV4_SUPPORT == ENABLED) //IPv4 address expected? if(entry->type == HOST_TYPE_IPV4) { //A resource record found? if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_A) { //Verify the length of the data field if(ntohs(resourceRecord->rdlength) == sizeof(Ipv4Addr)) { //Copy the IPv4 address entry->ipAddr.length = sizeof(Ipv4Addr); ipv4CopyAddr(&entry->ipAddr.ipv4Addr, resourceRecord->rdata); //Save current time entry->timestamp = osGetTickCount(); //Save TTL value entry->timeout = ntohl(resourceRecord->ttl) * 1000; //Limit the lifetime of the DNS cache entries entry->timeout = min(entry->timeout, DNS_MAX_LIFETIME); //Unregister UDP callback function udpDetachRxCallback(interface, entry->port); //Host name successfully resolved entry->state = DNS_STATE_RESOLVED; //Exit immediately break; } } } #endif #if (IPV6_SUPPORT == ENABLED) //IPv6 address expected? if(entry->type == HOST_TYPE_IPV6) { //AAAA resource record found? if(ntohs(resourceRecord->rtype) == DNS_RR_TYPE_AAAA) { //Verify the length of the data field if(ntohs(resourceRecord->rdlength) == sizeof(Ipv6Addr)) { //Copy the IPv6 address entry->ipAddr.length = sizeof(Ipv6Addr); ipv6CopyAddr(&entry->ipAddr.ipv6Addr, resourceRecord->rdata); //Save current time entry->timestamp = osGetTickCount(); //Save TTL value entry->timeout = ntohl(resourceRecord->ttl) * 1000; //Limit the lifetime of the DNS cache entries entry->timeout = min(entry->timeout, DNS_MAX_LIFETIME); //Unregister UDP callback function udpDetachRxCallback(interface, entry->port); //Host name successfully resolved entry->state = DNS_STATE_RESOLVED; //Exit immediately break; } } } #endif //Point to the next resource record pos += ntohs(resourceRecord->rdlength); } //We are done break; } } } //Release exclusive access to the DNS cache osMutexRelease(dnsCacheMutex); }