Ejemplo n.º 1
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);
}
Ejemplo n.º 2
0
void mdnsProcessQuery(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
   const UdpHeader *udpHeader, const DnsHeader *query, size_t queryLen)
{
   error_t error;
   uint_t i;
   size_t pos;
   size_t offset;
   size_t responseLen;
   DnsHeader *response;
   NetBuffer *buffer;

   //Check the state of the mDNS responder
   if(interface->mdnsContext.state != MDNS_STATE_DONE)
      return;

   //Initialize error code
   error = NO_ERROR;

   //This buffer will hold the mDNS response, if any
   buffer = NULL;
   //Point to the first question
   pos = sizeof(DnsHeader);

   //Parse question section
   for(i = 0; i < ntohs(query->qdcount); i++)
   {
      size_t n;
      uint16_t qclass;
      uint16_t qtype;
      DnsQuestion *question;

      //Parse domain name
      n = dnsParseName(query, queryLen, pos, NULL, 0);

      //Invalid name?
      if(!n)
         break;
      //Malformed mDNS message?
      if((n + sizeof(DnsQuestion)) > queryLen)
         break;

      //Point to the corresponding entry
      question = DNS_GET_QUESTION(query, n);
      //Convert the query class to host byte order
      qclass = ntohs(question->qclass);
      //Discard QU flag
      qclass &= ~MDNS_QCLASS_QU;
      //Convert the query type to host byte order
      qtype = ntohs(question->qtype);

      //Check the class of the query
      if(qclass == DNS_RR_CLASS_IN || qclass == DNS_RR_CLASS_ANY)
      {
#if (DNS_SD_SUPPORT == ENABLED)
         //PTR query?
         if(qtype == DNS_RR_TYPE_PTR || qtype == DNS_RR_TYPE_ANY)
         {
            uint_t j;

            //Service type enumeration meta-query received?
            if(mdnsCompareName(query, queryLen, pos, "", "_services._dns-sd._udp", ".local", 0))
            {
               //Any registered services?
               if(interface->numServices > 0 && interface->instanceName != NULL)
               {
                  //Create a mDNS response message only if necessary
                  if(!buffer)
                  {
                     //Allocate the mDNS response message
                     buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen);
                     //Failed to allocate memory?
                     if(!buffer) break;
                  }

                  //Loop through registered services
                  for(j = 0; j < interface->numServices; j++)
                  {
                     //Format PTR resource record
                     error = dnsSdAddPtrResourceRecord(interface,
                        &interface->services[j], TRUE, response, &responseLen);
                     //Any error to report?
                     if(error) break;
                  }

                  //Propagate exception if necessary...
                  if(error) break;
               }
            }
            else
            {
               //Loop through registered services
               for(j = 0; j < interface->numServices; j++)
               {
                  //Compare service name
                  if(mdnsCompareName(query, queryLen, pos, "",
                     interface->services[j].name, ".local", 0))
                  {
                     //The current service name matches a registered service
                     break;
                  }
               }

               //Any matching service name?
               if(j < interface->numServices && interface->instanceName != NULL)
               {
                  //Create a mDNS response message only if necessary
                  if(!buffer)
                  {
                     //Allocate the mDNS response message
                     buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen);
                     //Failed to allocate memory?
                     if(!buffer) break;
                  }

                  //Format PTR resource record
                  error = dnsSdAddPtrResourceRecord(interface,
                     &interface->services[j], FALSE, response, &responseLen);
                  //Any error to report?
                  if(error) break;

                  //Format TXT resource record
                  error = dnsSdAddTxtResourceRecord(interface,
                     &interface->services[j], response, &responseLen);
                  //Any error to report?
                  if(error) break;

                  //Format SRV resource record
                  error = dnsSdAddSrvResourceRecord(interface,
                     &interface->services[j], response, &responseLen);
                  //Any error to report?
                  if(error) break;

                  //Format A resource record
                  error = mdnsAddIpv4ResourceRecord(interface,
                     response, &responseLen, FALSE);
                  //Any error to report?
                  if(error) break;

                  //Format AAAA resource record
                  error = mdnsAddIpv6ResourceRecord(interface,
                     response, &responseLen, FALSE);
                  //Any error to report?
                  if(error) break;
               }
            }
         }
         //SRV or TXT query?
         else if(qtype == DNS_RR_TYPE_SRV || qtype == DNS_RR_TYPE_TXT)
         {
            uint_t j;

            //Loop through registered services
            for(j = 0; j < interface->numServices; j++)
            {
               //Compare service name
               if(mdnsCompareName(query, queryLen, pos, interface->instanceName,
                  interface->services[j].name, ".local", 0))
               {
                  //The current service name matches a registered service
                  break;
               }
            }

            //Any matching service name?
            if(j < interface->numServices && interface->instanceName != NULL)
            {
               //Create a mDNS response message only if necessary
               if(!buffer)
               {
                  //Allocate the mDNS response message
                  buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen);
                  //Failed to allocate memory?
                  if(!buffer) break;
               }

               //Check query type?
               if(qtype == DNS_RR_TYPE_TXT)
               {
                  //Format TXT resource record
                  error = dnsSdAddTxtResourceRecord(interface,
                     &interface->services[j], response, &responseLen);
                  //Any error to report?
                  if(error) break;
               }
               else if(qtype == DNS_RR_TYPE_SRV)
               {
                  //Format SRV resource record
                  error = dnsSdAddSrvResourceRecord(interface,
                     &interface->services[j], response, &responseLen);
                  //Any error to report?
                  if(error) break;

                  //Format A resource record
                  error = mdnsAddIpv4ResourceRecord(interface,
                     response, &responseLen, FALSE);
                  //Any error to report?
                  if(error) break;

                  //Format AAAA resource record
                  error = mdnsAddIpv6ResourceRecord(interface,
                     response, &responseLen, FALSE);
                  //Any error to report?
                  if(error) break;
               }
            }
         }
#endif
#if (IPV4_SUPPORT == ENABLED)
         //A query?
#if (DNS_SD_SUPPORT == ENABLED)
         if(qtype == DNS_RR_TYPE_A)
#else
         if(qtype == DNS_RR_TYPE_A || qtype == DNS_RR_TYPE_ANY)
#endif
         {
            //Compare domain name
            if(mdnsCompareName(query, queryLen, pos, interface->hostname, "", ".local", 0))
            {
               //Create a mDNS response message only if necessary
               if(!buffer)
               {
                  //Allocate the mDNS response message
                  buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen);
                  //Failed to allocate memory?
                  if(!buffer) break;
               }

               //Format A resource record
               error = mdnsAddIpv4ResourceRecord(interface, response, &responseLen, FALSE);
               //Any error to report?
               if(error) break;
            }
         }
#endif
#if (IPV6_SUPPORT == ENABLED)
         //AAAA query?
#if (DNS_SD_SUPPORT == ENABLED)
         if(qtype == DNS_RR_TYPE_AAAA)
#else
         if(qtype == DNS_RR_TYPE_AAAA || qtype == DNS_RR_TYPE_ANY)
#endif
         {
            //Compare domain name
            if(mdnsCompareName(query, queryLen, pos, interface->hostname, "", ".local", 0))
            {
               //Create a mDNS response message only if necessary
               if(!buffer)
               {
                  //Allocate the mDNS response message
                  buffer = mdnsCreateResponse(query->id, &offset, &response, &responseLen);
                  //Failed to allocate memory?
                  if(!buffer) break;
               }

               //Format AAAA resource record
               error = mdnsAddIpv6ResourceRecord(interface, response, &responseLen, FALSE);
               //Any error to report?
               if(error) break;
            }
         }
#endif
      }

      //Point to the next question
      pos = n + sizeof(DnsQuestion);
   }

   //Any response to send?
   if(buffer != NULL)
   {
      //Check status code
      if(!error)
      {
         //Send mDNS response message
         mdnsSendResponse(interface, pseudoHeader, udpHeader,
            buffer, offset, responseLen);
      }

      //Free previously allocated memory
      netBufferFree(buffer);
   }
}