Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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);
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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);
}