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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); }