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