void dnsFlushCache(NetInterface *interface) { uint_t i; DnsCacheEntry *entry; //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Go through DNS cache for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //Check whether the entry is currently in used if(entry->state != DNS_STATE_NONE) { //Delete DNS entries only for the given network interface if(entry->interface == interface) dnsDeleteEntry(entry); } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); }
DnsCacheEntry *dnsCreateEntry(void) { uint_t i; DnsCacheEntry *entry; DnsCacheEntry *oldestEntry; //Keep track of the oldest entry oldestEntry = &dnsCache[0]; //Loop through DNS cache entries for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //Check whether the entry is currently in used or not if(entry->state == DNS_STATE_NONE) { //Erase contents memset(entry, 0, sizeof(DnsCacheEntry)); //Return a pointer to the DNS entry return entry; } //Keep track of the oldest entry in the table if(timeCompare(entry->timestamp, oldestEntry->timestamp) < 0) oldestEntry = entry; } //The oldest entry is removed whenever the table runs out of space dnsDeleteEntry(oldestEntry); //Erase contents memset(oldestEntry, 0, sizeof(DnsCacheEntry)); //Return a pointer to the DNS entry return oldestEntry; }
void dnsTick(void) { error_t error; uint_t i; systime_t time; DnsCacheEntry *entry; //Get current time time = osGetSystemTime(); //Acquire exclusive access to the DNS cache osAcquireMutex(&dnsCacheMutex); //Go through DNS cache for(i = 0; i < DNS_CACHE_SIZE; i++) { //Point to the current entry entry = &dnsCache[i]; //Name resolution in progress? if(entry->state == DNS_STATE_IN_PROGRESS) { //The request timed out? if(timeCompare(time, entry->timestamp + entry->timeout) >= 0) { //Check whether the maximum number of retransmissions has been exceeded if(entry->retransmitCount > 0) { #if (DNS_CLIENT_SUPPORT == ENABLED) //DNS resolver? if(entry->protocol == HOST_NAME_RESOLVER_DNS) { //Retransmit DNS query error = dnsSendQuery(entry); } else #endif #if (MDNS_CLIENT_SUPPORT == ENABLED) //mDNS resolver? if(entry->protocol == HOST_NAME_RESOLVER_MDNS) { //Retransmit mDNS query error = mdnsSendQuery(entry); } else #endif #if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED) //NetBIOS Name Service resolver? if(entry->protocol == HOST_NAME_RESOLVER_NBNS) { //Retransmit NBNS query error = nbnsSendQuery(entry); } else #endif //Unknown protocol? { error = ERROR_FAILURE; } //Query message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = time; //The timeout value is doubled for each subsequent retransmission entry->timeout = MIN(entry->timeout * 2, entry->maxTimeout); //Decrement retransmission counter entry->retransmitCount--; } else { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); } } #if (DNS_CLIENT_SUPPORT == ENABLED) //DNS resolver? else if(entry->protocol == HOST_NAME_RESOLVER_DNS) { //Select the next DNS server entry->dnsServerNum++; //Initialize retransmission counter entry->retransmitCount = DNS_CLIENT_MAX_RETRIES; //Send DNS query error = dnsSendQuery(entry); //DNS message successfully sent? if(!error) { //Save the time at which the query message was sent entry->timestamp = time; //Set timeout value entry->timeout = DNS_CLIENT_INIT_TIMEOUT; //Decrement retransmission counter entry->retransmitCount--; } else { //The entry should be deleted since name resolution has failed dnsDeleteEntry(entry); } } #endif else { //The maximum number of retransmissions has been exceeded dnsDeleteEntry(entry); } } } //Name successfully resolved? else if(entry->state == DNS_STATE_RESOLVED) { //Check the lifetime of the current DNS cache entry if(timeCompare(time, entry->timestamp + entry->timeout) >= 0) { //Periodically time out DNS cache entries dnsDeleteEntry(entry); } } } //Release exclusive access to the DNS cache osReleaseMutex(&dnsCacheMutex); }
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); }