Tiny DNS Resolver
Dependencies: EthernetNetIf mbed
TinyResolver.cpp
- Committer:
- okini3939
- Date:
- 2011-07-21
- Revision:
- 0:477d4e2f281a
File content as of revision 0:477d4e2f281a:
/* * mbed Tiny DNS Resolver * Copyright (c) 2011 Hiroshi Suga * Released under the MIT License: http://mbed.org/license/mit */ /** @file * @brief Tiny DNS Resolver */ #include "mbed.h" #include "EthernetNetIf.h" #include "UDPSocket.h" #include "TinyResolver.h" // host to network short #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) ) #define ntohs( x ) htons(x) // host to network long #define htonl( x ) ( (( (x) << 24 ) & 0xFF000000) \ | (( (x) << 8 ) & 0x00FF0000) \ | (( (x) >> 8 ) & 0x0000FF00) \ | (( (x) >> 24 ) & 0x000000FF) ) #define ntohl( x ) htonl(x) extern EthernetNetIf eth; static UDPSocket *dns; static volatile unsigned long dnsaddr; static volatile unsigned long id; int createDnsRequest (char *name, char *buf) { struct DnsHeader *dnsHeader; struct DnsQuestionEnd *dnsEnd; int len, num; id ++; dnsHeader = (struct DnsHeader*)buf; dnsHeader->id = htons(id); dnsHeader->flags = htons(0x100); dnsHeader->questions = htons(1); dnsHeader->answers = 0; dnsHeader->authorities = 0; dnsHeader->additional = 0; len = sizeof(struct DnsHeader); while ((num = (int)strchr(name, '.')) != NULL) { num = num - (int)name; buf[len] = num; len ++; strncpy(&buf[len], name, num); name = name + num + 1; len = len + num; } if ((num = strlen(name)) != NULL) { buf[len] = num; len ++; strncpy(&buf[len], name, num); len = len + num; } buf[len] = 0; len ++; dnsEnd = (struct DnsQuestionEnd *)&buf[len]; dnsEnd->type = htons(DNS_QUERY_A); dnsEnd->clas = htons(DNS_CLASS_IN); return len + sizeof(struct DnsQuestionEnd); } int getDnsResponse (const char *buf, int len, uint32_t *addr) { int i; struct DnsHeader *dnsHeader; struct DnsAnswer *dnsAnswer; // header dnsHeader = (struct DnsHeader*)buf; if (ntohs(dnsHeader->id) != id || (ntohs(dnsHeader->flags) & 0x800f) != 0x8000) { return -1; } // skip question for (i = sizeof(struct DnsHeader); buf[i] && i < len; i ++); i = i + 1 + sizeof(struct DnsQuestionEnd); // answer while (i < len) { dnsAnswer = (struct DnsAnswer*)&buf[i]; if (dnsAnswer->clas != htons(DNS_CLASS_IN)) { return -1; } i = i + sizeof(struct DnsAnswer); if (dnsAnswer->type == htons(DNS_QUERY_A)) { // A record *addr = ((uint32_t)buf[i] << 24) + ((uint32_t)buf[i + 1] << 16) + ((uint32_t)buf[i + 2] << 8) + (uint32_t)buf[i + 3]; return 0; } // next answer i = i + dnsAnswer->length; } return -1; } void isr_dns (UDPSocketEvent e) { char buf[512]; Host dsthost; int len; if (e == UDPSOCKET_READABLE) { // recv responce; len = dns->recvfrom(buf, sizeof(buf), &dsthost); #ifdef DEBUG for (int i = 0; i < len; i ++) { printf(" %02x", (unsigned char)buf[i]); } puts("\r"); #endif if (len >= sizeof(struct DnsHeader)) { getDnsResponse(buf, len, (uint32_t*)&dnsaddr); } } } int getHostByName (IpAddr nameserver, const char *name, uint32_t *addr) { UDPSocketErr err; Host myhost, dnshost; char buf[100]; int i, len; // localhost if (!strcmp(name, "localhost")) { *addr = 0x0f000001; return 0; } dnsaddr = 0; dns = new UDPSocket; dns->setOnEvent(isr_dns); // bind myhost.setIp(eth.getIp()); myhost.setPort(DNS_SRC_PORT); err = dns->bind(myhost); if (err != UDPSOCKET_OK) goto exit; // send request dnshost.setIp(nameserver); dnshost.setPort(DNS_PORT); len = createDnsRequest((char*)name, buf); #ifdef DEBUG for (int i = 0; i < len; i ++) { printf(" %02x", (unsigned char)buf[i]); } puts("\r"); #endif dns->sendto(buf, len, &dnshost); // wait responce for (i = 0; i < DNS_TIMEOUT / 10; i ++) { if (dnsaddr) { // responce *addr = dnsaddr; break; } if (i % 500 == 499) { // retry dns->sendto(buf, len, &dnshost); } Net::poll(); wait_ms(10); } exit: dns->resetOnEvent(); delete dns; return dnsaddr ? 0 : -1; }