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;
}
Exemple #2
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;
}
Exemple #3
0
int_t bind(int_t s, const sockaddr *addr, int_t addrlen)
{
   error_t error;
   uint16_t port;
   IpAddr ipAddr;
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Check the length of the address
   if(addrlen < sizeof(sockaddr))
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 address?
   if(addr->sa_family == AF_INET && addrlen >= sizeof(sockaddr_in))
   {
      //Point to the IPv4 address information
      sockaddr_in *sa = (sockaddr_in *) addr;
      //Get port number
      port = ntohs(sa->sin_port);

      //Copy IPv4 address
      if(sa->sin_addr.s_addr == INADDR_ANY)
      {
         ipAddr.length = 0;
         ipAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
      }
      else
      {
         ipAddr.length = sizeof(Ipv4Addr);
         ipAddr.ipv4Addr = sa->sin_addr.s_addr;
      }
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 address?
   if(addr->sa_family == AF_INET6 && addrlen >= sizeof(sockaddr_in6))
   {
      //Point to the IPv6 address information
      sockaddr_in6 *sa = (sockaddr_in6 *) addr;
      //Get port number
      port = ntohs(sa->sin6_port);

      //Copy IPv6 address
      if(ipv6CompAddr(sa->sin6_addr.s6_addr, &in6addr_any))
      {
         ipAddr.length = 0;
         ipAddr.ipv6Addr = IPV6_UNSPECIFIED_ADDR;
      }
      else
      {
         ipAddr.length = sizeof(Ipv6Addr);
         ipv6CopyAddr(&ipAddr.ipv6Addr, sa->sin6_addr.s6_addr);
      }
   }
   else
#endif
   //Invalid address?
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

   //Associate the local address with the socket
   error = socketBind(socket, &ipAddr, port);

   //Any error to report?
   if(error)
   {
      socketError(socket, error);
      return SOCKET_ERROR;
   }

   //Successful processing
   return SOCKET_SUCCESS;
}
Exemple #4
0
int_t getpeername(int_t s, sockaddr *addr, int_t *addrlen)
{
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //The socket has not been bound to an address?
   if(!socket->remoteIpAddr.length)
   {
      socketError(socket, ERROR_NO_BINDING);
      return SOCKET_ERROR;
   }

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 address?
   if(socket->remoteIpAddr.length == sizeof(Ipv4Addr) && *addrlen >= sizeof(sockaddr_in))
   {
      //Point to the IPv4 address information
      sockaddr_in *sa = (sockaddr_in *) addr;

      //Set address family and port number
      sa->sin_family = AF_INET;
      sa->sin_port = htons(socket->remotePort);
      //Copy IPv4 address
      sa->sin_addr.s_addr = socket->remoteIpAddr.ipv4Addr;

      //Return the actual length of the address
      *addrlen = sizeof(sockaddr_in);
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 address?
   if(socket->remoteIpAddr.length == sizeof(Ipv6Addr) && *addrlen >= sizeof(sockaddr_in6))
   {
      //Point to the IPv6 address information
      sockaddr_in6 *sa = (sockaddr_in6 *) addr;

      //Set address family and port number
      sa->sin6_family = AF_INET6;
      sa->sin6_port = htons(socket->remotePort);
      //Copy IPv6 address
      ipv6CopyAddr(sa->sin6_addr.s6_addr, &socket->remoteIpAddr.ipv6Addr);

      //Return the actual length of the address
      *addrlen = sizeof(sockaddr_in6);
   }
   else
#endif
   //Invalid address?
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

   //Successful processing
   return SOCKET_SUCCESS;
}
Exemple #5
0
int_t recvfrom(int_t s, void *data, int_t size,
   int_t flags, sockaddr *addr, int_t *addrlen)
{
   error_t error;
   size_t received;
   uint16_t port;
   IpAddr ipAddr;
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Receive data
   error = socketReceiveFrom(socket, &ipAddr, &port, data, size, &received, flags << 8);

   //Any error to report?
   if(error)
   {
      socketError(socket, error);
      return SOCKET_ERROR;
   }

   //The address is optional
   if(addr != NULL && addrlen != NULL)
   {
#if (IPV4_SUPPORT == ENABLED)
      //IPv4 address?
      if(ipAddr.length == sizeof(Ipv4Addr) && *addrlen >= sizeof(sockaddr_in))
      {
         //Point to the IPv4 address information
         sockaddr_in *sa = (sockaddr_in *) addr;

         //Set address family and port number
         sa->sin_family = AF_INET;
         sa->sin_port = htons(port);
         //Copy IPv4 address
         sa->sin_addr.s_addr = ipAddr.ipv4Addr;

         //Return the actual length of the address
         *addrlen = sizeof(sockaddr_in);
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //IPv6 address?
      if(ipAddr.length == sizeof(Ipv6Addr) && *addrlen >= sizeof(sockaddr_in6))
      {
         //Point to the IPv6 address information
         sockaddr_in6 *sa = (sockaddr_in6 *) addr;

         //Set address family and port number
         sa->sin6_family = AF_INET6;
         sa->sin6_port = htons(port);
         //Copy IPv6 address
         ipv6CopyAddr(sa->sin6_addr.s6_addr, &ipAddr.ipv6Addr);

         //Return the actual length of the address
         *addrlen = sizeof(sockaddr_in6);
      }
      else
#endif
      //Invalid address?
      {
         //Report an error
         socketError(socket, ERROR_INVALID_PARAMETER);
         return SOCKET_ERROR;
      }
   }

   //Return the number of bytes received
   return received;
}
Exemple #6
0
int_t sendto(int_t s, const void *data, int_t length,
   int_t flags, const sockaddr *addr, int_t addrlen)
{
   error_t error;
   size_t written;
   uint16_t port;
   IpAddr ipAddr;
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Check the length of the address
   if(addrlen < sizeof(sockaddr))
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

#if (IPV4_SUPPORT == ENABLED)
   //IPv4 address?
   if(addr->sa_family == AF_INET && addrlen == sizeof(sockaddr_in))
   {
      //Point to the IPv4 address information
      sockaddr_in *sa = (sockaddr_in *) addr;

      //Get port number
      port = ntohs(sa->sin_port);
      //Copy IPv4 address
      ipAddr.length = sizeof(Ipv4Addr);
      ipAddr.ipv4Addr = sa->sin_addr.s_addr;
   }
   else
#endif
#if (IPV6_SUPPORT == ENABLED)
   //IPv6 address?
   if(addr->sa_family == AF_INET6 && addrlen == sizeof(sockaddr_in6))
   {
      //Point to the IPv6 address information
      sockaddr_in6 *sa = (sockaddr_in6 *) addr;

      //Get port number
      port = ntohs(sa->sin6_port);
      //Copy IPv6 address
      ipAddr.length = sizeof(Ipv6Addr);
      ipv6CopyAddr(&ipAddr.ipv6Addr, sa->sin6_addr.s6_addr);
   }
   else
#endif
   //Invalid address?
   {
      //Report an error
      socketError(socket, ERROR_INVALID_PARAMETER);
      return SOCKET_ERROR;
   }

   //Send data
   error = socketSendTo(socket, &ipAddr, port, data, length, &written, flags << 8);

   //Any error to report?
   if(error)
   {
      socketError(socket, error);
      return SOCKET_ERROR;
   }

   //Return the number of bytes sent
   return written;
}
Exemple #7
0
int_t accept(int_t s, sockaddr *addr, int_t *addrlen)
{
   uint16_t port;
   IpAddr ipAddr;
   Socket *socket;
   Socket *newSocket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Permit an incoming connection attempt on a socket
   newSocket = socketAccept(socket, &ipAddr, &port);

   //The address is optional
   if(addr != NULL && addrlen != NULL)
   {
#if (IPV4_SUPPORT == ENABLED)
      //IPv4 address?
      if(ipAddr.length == sizeof(Ipv4Addr) && *addrlen >= sizeof(sockaddr_in))
      {
         //Point to the IPv4 address information
         sockaddr_in *sa = (sockaddr_in *) addr;

         //Set address family and port number
         sa->sin_family = AF_INET;
         sa->sin_port = htons(port);
         //Copy IPv4 address
         sa->sin_addr.s_addr = ipAddr.ipv4Addr;

         //Return the actual length of the address
         *addrlen = sizeof(sockaddr_in);
      }
      else
#endif
#if (IPV6_SUPPORT == ENABLED)
      //IPv6 address?
      if(ipAddr.length == sizeof(Ipv6Addr) && *addrlen >= sizeof(sockaddr_in6))
      {
         //Point to the IPv6 address information
         sockaddr_in6 *sa = (sockaddr_in6 *) addr;

         //Set address family and port number
         sa->sin6_family = AF_INET6;
         sa->sin6_port = htons(port);
         //Copy IPv6 address
         ipv6CopyAddr(sa->sin6_addr.s6_addr, &ipAddr.ipv6Addr);

         //Return the actual length of the address
         *addrlen = sizeof(sockaddr_in6);
      }
      else
#endif
      //Invalid address?
      {
         //Close socket
         socketClose(newSocket);
         //Report an error
         socketError(socket, ERROR_INVALID_PARAMETER);
         return SOCKET_ERROR;
      }
   }

   //Return the descriptor to the new socket
   return newSocket->descriptor;
}
Exemple #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);
}