void nbnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *params) { size_t length; NbnsHeader *message; //Make sure the NBNS message was received from an IPv4 peer if(pseudoHeader->length != sizeof(Ipv4PseudoHeader)) return; //Retrieve the length of the NBNS message length = netBufferGetLength(buffer) - offset; //Ensure the NBNS message is valid if(length < sizeof(NbnsHeader)) return; if(length > DNS_MESSAGE_MAX_SIZE) return; //Point to the NBNS message header message = netBufferAt(buffer, offset); //Sanity check if(message == NULL) return; //Debug message TRACE_INFO("NBNS message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage((DnsHeader *) message, length); //NBNS messages received with an opcode other than zero must be silently ignored if(message->opcode != DNS_OPCODE_QUERY) return; //NBNS messages received with non-zero response codes must be silently ignored if(message->rcode != DNS_RCODE_NO_ERROR) return; //NBNS query received? if(!message->qr) { #if (NBNS_RESPONDER_SUPPORT == ENABLED) //Process incoming NBNS query message nbnsProcessQuery(interface, &pseudoHeader->ipv4Data, udpHeader, message, length); #endif } //NBNS response received? else { #if (NBNS_CLIENT_SUPPORT == ENABLED) //Process incoming NBNS response message nbnsProcessResponse(interface, &pseudoHeader->ipv4Data, udpHeader, message, length); #endif } }
void mdnsProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const ChunkedBuffer *buffer, size_t offset, void *params) { size_t length; DnsHeader *message; //Retrieve the length of the mDNS message length = chunkedBufferGetLength(buffer) - offset; //Ensure the mDNS message is valid if(length < sizeof(DnsHeader)) return; if(length > DNS_MESSAGE_MAX_SIZE) return; //Point to the mDNS message header message = chunkedBufferAt(buffer, offset); //Sanity check if(!message) return; //Debug message TRACE_INFO("mDNS message received (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); //mDNS messages received with an opcode other than zero must be silently ignored if(message->opcode != DNS_OPCODE_QUERY) return; //mDNS messages received with non-zero response codes must be silently ignored if(message->rcode != DNS_RCODE_NO_ERROR) return; #if (MDNS_RESPONDER_SUPPORT == ENABLED) //mDNS query received? if(!message->qr) { //Process incoming mDNS query message mdnsProcessQuery(interface, pseudoHeader, udpHeader, message, length); } #endif #if (MDNS_CLIENT_SUPPORT == ENABLED) //mDNS response received? if(message->qr) { //Process incoming mDNS response message mdnsProcessResponse(interface, pseudoHeader, udpHeader, message, length); } #endif }
error_t nbnsSendQuery(DnsCacheEntry *entry) { error_t error; size_t length; size_t offset; NetBuffer *buffer; NbnsHeader *message; DnsQuestion *dnsQuestion; IpAddr destIpAddr; //Allocate a memory buffer to hold the NBNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the NBNS header message = netBufferAt(buffer, offset); //Format NBNS query message message->id = htons(entry->id); message->qr = 0; message->opcode = DNS_OPCODE_QUERY; message->aa = 0; message->tc = 0; message->rd = 0; message->ra = 0; message->z = 0; message->b = 1; message->rcode = DNS_RCODE_NO_ERROR; //The NBNS query contains one question message->qdcount = HTONS(1); message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the NBNS query message length = sizeof(DnsHeader); //Encode the NetBIOS name length += nbnsEncodeName(entry->name, message->questions); //Point to the corresponding question structure dnsQuestion = DNS_GET_QUESTION(message, length); //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_NB); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); //Update the length of the NBNS query message length += sizeof(DnsQuestion); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage((DnsHeader *) message, length); //The destination address is the broadcast address destIpAddr.length = sizeof(Ipv4Addr); ipv4GetBroadcastAddr(entry->interface, &destIpAddr.ipv4Addr); //A request packet is always sent to the well known port 137 error = udpSendDatagramEx(entry->interface, NBNS_PORT, &destIpAddr, NBNS_PORT, buffer, offset, IPV4_DEFAULT_TTL); //Free previously allocated memory netBufferFree(buffer); //Return status code return error; }
error_t nbnsSendResponse(NetInterface *interface, const IpAddr *destIpAddr, uint16_t destPort, uint16_t id) { error_t error; size_t length; size_t offset; ChunkedBuffer *buffer; NbnsHeader *message; NbnsAddrEntry *addrEntry; DnsResourceRecord *resourceRecord; //Allocate a memory buffer to hold the NBNS response message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the NBNS header message = chunkedBufferAt(buffer, offset); //Take the identifier from the query message message->id = id; //Format NBNS response header message->qr = 1; message->opcode = DNS_OPCODE_QUERY; message->aa = 1; message->tc = 0; message->rd = 1; message->ra = 1; message->z = 0; message->b = 0; message->rcode = DNS_RCODE_NO_ERROR; //The NBNS response contains 1 answer resource record message->qdcount = 0; message->ancount = HTONS(1); message->nscount = 0; message->arcount = 0; //NBNS response message length length = sizeof(DnsHeader); //Encode the host name using the NBNS name notation length += nbnsEncodeName(interface->hostname, (uint8_t *) message + length); //Point to the corresponding resource record resourceRecord = DNS_GET_RESOURCE_RECORD(message, length); //Fill in resource record resourceRecord->rtype = HTONS(DNS_RR_TYPE_NB); resourceRecord->rclass = HTONS(DNS_RR_CLASS_IN); resourceRecord->ttl = HTONL(NBNS_DEFAULT_RESOURCE_RECORD_TTL); resourceRecord->rdlength = HTONS(sizeof(NbnsAddrEntry)); //Point to the address entry array addrEntry = (NbnsAddrEntry *) resourceRecord->rdata; //Fill in address entry addrEntry->flags = HTONS(NBNS_G_UNIQUE | NBNS_ONT_BNODE); addrEntry->addr = interface->ipv4Config.addr; //Update the length of the NBNS response message length += sizeof(DnsResourceRecord) + sizeof(NbnsAddrEntry); //Adjust the length of the multi-part buffer chunkedBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending NBNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage((DnsHeader *) message, length); //A response packet is always sent to the source UDP port and //source IP address of the request packet error = udpSendDatagramEx(interface, NBNS_PORT, destIpAddr, destPort, buffer, offset, IPV4_DEFAULT_TTL); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return 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); }
error_t dnsSendQuery(DnsCacheEntry *entry) { error_t error; size_t length; size_t offset; ChunkedBuffer *buffer; DnsHeader *message; DnsQuestion *dnsQuestion; IpAddr destIpAddr; #if (IPV4_SUPPORT == ENABLED) //An IPv4 address is expected? if(entry->type == HOST_TYPE_IPV4) { //Select the relevant DNS server destIpAddr.length = sizeof(Ipv4Addr); ipv4GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv4Addr); //Make sure the IP address is valid if(destIpAddr.ipv4Addr == IPV4_UNSPECIFIED_ADDR) return ERROR_NO_DNS_SERVER; } else #endif #if (IPV6_SUPPORT == ENABLED) //An IPv6 address is expected? if(entry->type == HOST_TYPE_IPV6) { //Select the relevant DNS server destIpAddr.length = sizeof(Ipv6Addr); ipv6GetDnsServer(entry->interface, entry->dnsServerNum, &destIpAddr.ipv6Addr); //Make sure the IP address is valid if(ipv6CompAddr(&destIpAddr.ipv6Addr, &IPV6_UNSPECIFIED_ADDR)) return ERROR_NO_DNS_SERVER; } else #endif //Invalid host type? { //Report an error return ERROR_INVALID_PARAMETER; } //Allocate a memory buffer to hold the DNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the DNS header message = chunkedBufferAt(buffer, offset); //Format DNS query message message->id = htons(entry->id); message->qr = 0; message->opcode = DNS_OPCODE_QUERY; message->aa = 0; message->tc = 0; message->rd = 1; message->ra = 0; message->z = 0; message->rcode = DNS_RCODE_NO_ERROR; //The DNS query contains one question message->qdcount = HTONS(1); message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the DNS query message length = sizeof(DnsHeader); //Encode the host name using the DNS name notation length += dnsEncodeName(entry->name, message->questions); //Point to the corresponding question structure dnsQuestion = DNS_GET_QUESTION(message, length); #if (IPV4_SUPPORT == ENABLED) //An IPv4 address is expected? if(entry->type == HOST_TYPE_IPV4) { //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_A); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); } #endif #if (IPV6_SUPPORT == ENABLED) //An IPv6 address is expected? if(entry->type == HOST_TYPE_IPV6) { //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_AAAA); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); } #endif //Update the length of the DNS query message length += sizeof(DnsQuestion); //Adjust the length of the multi-part buffer chunkedBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending DNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); //Send DNS query message error = udpSendDatagramEx(entry->interface, entry->port, &destIpAddr, DNS_PORT, buffer, offset, 0); //Free previously allocated memory chunkedBufferFree(buffer); //Return status code return error; }
error_t mdnsSendResponse(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, NetBuffer *buffer, size_t offset, size_t length) { uint16_t destPort; IpAddr destIpAddr; DnsHeader *response; #if (IPV4_SUPPORT == ENABLED) //Check whether the mDNS query was received from an IPv4 peer if(pseudoHeader->length == sizeof(Ipv4PseudoHeader)) { //If the source UDP port in a received Multicast DNS query is not port 5353, //this indicates that the querier originating the query is a simple resolver if(udpHeader->srcPort != HTONS(MDNS_PORT)) { //the mDNS responder must send a UDP response directly back to the querier, //via unicast, to the query packet's source IP address and port destIpAddr.length = sizeof(Ipv4Addr); destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr; } else { //Use mDNS IPv4 multicast address destIpAddr.length = sizeof(Ipv4Addr); destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; } } #endif #if (IPV6_SUPPORT == ENABLED) //Check whether the mDNS query was received from an IPv6 peer if(pseudoHeader->length == sizeof(Ipv6PseudoHeader)) { //If the source UDP port in a received Multicast DNS query is not port 5353, //this indicates that the querier originating the query is a simple resolver if(udpHeader->srcPort != HTONS(MDNS_PORT)) { //the mDNS responder must send a UDP response directly back to the querier, //via unicast, to the query packet's source IP address and port destIpAddr.length = sizeof(Ipv6Addr); destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr; } else { //Use mDNS IPv6 multicast address destIpAddr.length = sizeof(Ipv6Addr); destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; } } #endif //Destination port destPort = ntohs(udpHeader->srcPort); //Point to the mDNS response header response = netBufferAt(buffer, offset); //Convert 16-bit value to network byte order response->ancount = htons(response->ancount); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending mDNS message (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(response, length); //All multicast DNS responses should be sent with an IP TTL set to 255 return udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, destPort, buffer, offset, MDNS_DEFAULT_IP_TTL); }
error_t mdnsSendAnnouncement(NetInterface *interface) { error_t error; size_t length; size_t offset; NetBuffer *buffer; DnsHeader *message; IpAddr destIpAddr; //Initialize error code error = NO_ERROR; //Allocate a memory buffer to hold the mDNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the mDNS header message = netBufferAt(buffer, offset); //Format mDNS query message message->id = 0; message->qr = 1; message->opcode = DNS_OPCODE_QUERY; message->aa = 1; message->tc = 0; message->rd = 0; message->ra = 0; message->z = 0; message->rcode = DNS_RCODE_NO_ERROR; //Multicast DNS responses must not contain any questions message->qdcount = 0; message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the mDNS query message length = sizeof(DnsHeader); //Start of exception handling block do { //Format A resource record error = mdnsAddIpv4ResourceRecord(interface, message, &length, TRUE); //Any error to report? if(error) break; //Format AAAA resource record error = mdnsAddIpv6ResourceRecord(interface, message, &length, TRUE); //Any error to report? if(error) break; //Convert 16-bit value to network byte order message->ancount = htons(message->ancount); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending mDNS announcement (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); #if (IPV4_SUPPORT == ENABLED) //Select the relevant multicast address (224.0.0.251) destIpAddr.length = sizeof(Ipv4Addr); destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); //Any error to report? if(error)break; #endif #if (IPV6_SUPPORT == ENABLED) //Select the relevant multicast address (ff02::fb) destIpAddr.length = sizeof(Ipv6Addr); destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); //Any error to report? if(error)break; #endif //End of exception handling block } while(0); //Free previously allocated memory netBufferFree(buffer); //Return status code return error; }
error_t mdnsSendProbe(NetInterface *interface) { error_t error; size_t length; size_t offset; NetBuffer *buffer; DnsHeader *message; DnsQuestion *dnsQuestion; IpAddr destIpAddr; //Initialize error code error = NO_ERROR; //Allocate a memory buffer to hold the mDNS query message buffer = udpAllocBuffer(DNS_MESSAGE_MAX_SIZE, &offset); //Failed to allocate buffer? if(!buffer) return ERROR_OUT_OF_MEMORY; //Point to the mDNS header message = netBufferAt(buffer, offset); //Format mDNS query message message->id = 0; message->qr = 0; message->opcode = DNS_OPCODE_QUERY; message->aa = 0; message->tc = 0; message->rd = 0; message->ra = 0; message->z = 0; message->rcode = DNS_RCODE_NO_ERROR; //The mDNS query contains one question message->qdcount = HTONS(1); message->ancount = 0; message->nscount = 0; message->arcount = 0; //Length of the mDNS query message length = sizeof(DnsHeader); //Encode the host name using the DNS name notation length += mdnsEncodeName(interface->hostname, "", ".local", (uint8_t *) message + length); //Point to the corresponding question structure dnsQuestion = DNS_GET_QUESTION(message, length); //Fill in question structure dnsQuestion->qtype = HTONS(DNS_RR_TYPE_ANY); dnsQuestion->qclass = HTONS(DNS_RR_CLASS_IN); //Update the length of the mDNS query message length += sizeof(DnsQuestion); //Adjust the length of the multi-part buffer netBufferSetLength(buffer, offset + length); //Debug message TRACE_INFO("Sending mDNS probe (%" PRIuSIZE " bytes)...\r\n", length); //Dump message dnsDumpMessage(message, length); #if (IPV4_SUPPORT == ENABLED) //Check status code if(!error) { //Select the relevant multicast address (224.0.0.251) destIpAddr.length = sizeof(Ipv4Addr); destIpAddr.ipv4Addr = MDNS_IPV4_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); } #endif #if (IPV6_SUPPORT == ENABLED) //Check status code if(!error) { //Select the relevant multicast address (ff02::fb) destIpAddr.length = sizeof(Ipv6Addr); destIpAddr.ipv6Addr = MDNS_IPV6_MULTICAST_ADDR; //All multicast DNS queries should be sent with an IP TTL set to 255 error = udpSendDatagramEx(interface, MDNS_PORT, &destIpAddr, MDNS_PORT, buffer, offset, MDNS_DEFAULT_IP_TTL); } #endif //Free previously allocated memory netBufferFree(buffer); //Return status code return error; }