error_t mdnsAddIpv4ResourceRecord(NetInterface *interface,
   DnsHeader *message, size_t *length, bool_t flush)
{
#if (IPV4_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(Ipv4Addr);

   //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_A);
   resourceRecord->ttl = HTONL(MDNS_DEFAULT_RESOURCE_RECORD_TTL);
   resourceRecord->rdlength = HTONS(sizeof(Ipv4Addr));

   //Copy IPv4 address
   ipv4CopyAddr(resourceRecord->rdata, &interface->ipv4Config.addr);

   //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 dhcpDumpIpv4Addr(const DhcpOption *option)
{
   Ipv4Addr ipAddr;

   //Check option length
   if(option->length != sizeof(Ipv4Addr))
      return ERROR_INVALID_OPTION;

   //Retrieve IPv4 address
   ipv4CopyAddr(&ipAddr, option->value);
   //Dump option contents
   TRACE_DEBUG("    %s\r\n", ipv4AddrToString(ipAddr, NULL));

   //No error to report
   return NO_ERROR;
}
Exemple #3
0
int_t gethostbyname(const char_t *name, hostent *info)
{
   error_t error;
   IpAddr ipAddr;

   //Check input parameters
   if(!name || !info)
      return ERROR_INVALID_PARAMETER;

   //Resolve host address
   error = getHostByName(NULL, name, &ipAddr, 1, NULL, 0);
   //Address resolution failed?
   if(error) return error;

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 address?
   if(ipAddr.length == sizeof(Ipv4Addr))
   {
      //Set address family
      info->h_addrtype = AF_INET;
      //Copy IPv4 address
      info->h_length = sizeof(Ipv4Addr);
      ipv4CopyAddr(info->h_addr, &ipAddr.ipv4Addr);
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 address?
   if(ipAddr.length == sizeof(Ipv6Addr))
   {
      //Set address family
      info->h_addrtype = AF_INET6;
      //Copy IPv6 address
      info->h_length = sizeof(Ipv6Addr);
      ipv6CopyAddr(info->h_addr, &ipAddr.ipv6Addr);
   }
   else
#endif
   //Invalid address?
   {
      //Report an error
      return ERROR_FAILURE;
   }

   //Successful processing
   return NO_ERROR;
}
error_t dhcpDumpIpv4AddrList(const DhcpOption *option)
{
   size_t i;
   Ipv4Addr ipAddr;

   //Check option length
   if((option->length % sizeof(Ipv4Addr)) != 0)
      return ERROR_INVALID_OPTION;

   //Parse the list of IPv4 addresses
   for(i = 0; i < option->length; i += sizeof(Ipv4Addr))
   {
      //Retrieve the current IPv4 address
      ipv4CopyAddr(&ipAddr, option->value + i);
      //Display current address
      TRACE_DEBUG("    %s\r\n", ipv4AddrToString(ipAddr, NULL));
   }

   //No error to report
   return NO_ERROR;
}
Exemple #5
0
error_t ipcpDumpOptions(const PppOption *option, size_t length)
{
#if (IPV4_SUPPORT == ENABLED)
   Ipv4Addr ipAddr;
#endif

   //Parse options
   while(length > 0)
   {
      //Malformed IPCP packet?
      if(length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;

      //Check option length
      if(option->length < sizeof(PppOption))
         return ERROR_INVALID_LENGTH;
      if(option->length > length)
         return ERROR_INVALID_LENGTH;

      //Display the name of the current option
      if(option->type < arraysize(ipcpOptionLabel))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", ipcpOptionLabel[option->type], option->length);
      else if(option->type >= 128 && option->type < (128 + arraysize(ipcpOptionLabel2)))
         TRACE_DEBUG("  %s option (%" PRIu8 " bytes)\r\n", ipcpOptionLabel2[option->type - 128], option->length);
      else
         TRACE_DEBUG("  Option %" PRIu8 " (%" PRIu8 " bytes)\r\n", option->type, option->length);

      //Check option code
      switch(option->type)
      {
#if (IPV4_SUPPORT == ENABLED)
      //IP address?
      case IPCP_OPTION_IP_ADDRESS:
      case IPCP_OPTION_PRIMARY_DNS:
      case IPCP_OPTION_PRIMARY_NBNS:
      case IPCP_OPTION_SECONDARY_DNS:
      case IPCP_OPTION_SECONDARY_NBNS:
         //Check length field
         if(option->length != (sizeof(PppOption) + sizeof(Ipv4Addr)))
            return ERROR_INVALID_OPTION;
         //Retrieve IPv4 address
         ipv4CopyAddr(&ipAddr, option->data);
         //Dump option contents
         TRACE_DEBUG("    %s\r\n", ipv4AddrToString(ipAddr, NULL));
         break;
#endif
      //Raw data?
      default:
         //Dump option contents
         TRACE_DEBUG_ARRAY("    ", option->data, option->length - sizeof(PppOption));
         break;
      }

      //Remaining bytes to process
      length -= option->length;
      //Jump to the next option
      option = (PppOption *) ((uint8_t *) option + option->length);
   }

   //No error to report
   return NO_ERROR;
}
Exemple #6
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;
}
Exemple #7
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);
}