Tiny DNS Resolver

Dependencies:   EthernetNetIf mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TinyResolver.cpp Source File

TinyResolver.cpp

Go to the documentation of this file.
00001 /*
00002  * mbed Tiny DNS Resolver
00003  * Copyright (c) 2011 Hiroshi Suga
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  */
00006 
00007 /** @file
00008  * @brief Tiny DNS Resolver
00009  */
00010 
00011 #include "mbed.h"
00012 #include "EthernetNetIf.h"
00013 #include "UDPSocket.h"
00014 #include "TinyResolver.h"
00015 
00016 // host to network short
00017 #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) )
00018 #define ntohs( x ) htons(x)
00019 // host to network long
00020 #define htonl( x ) ( (( (x) << 24 ) & 0xFF000000)  \
00021                    | (( (x) <<  8 ) & 0x00FF0000)  \
00022                    | (( (x) >>  8 ) & 0x0000FF00)  \
00023                    | (( (x) >> 24 ) & 0x000000FF)  )
00024 #define ntohl( x ) htonl(x)
00025 
00026 extern EthernetNetIf eth;
00027 static UDPSocket *dns;
00028 static volatile unsigned long dnsaddr;
00029 static volatile unsigned long id;
00030 
00031 int createDnsRequest (char *name, char *buf) {
00032     struct DnsHeader *dnsHeader;
00033     struct DnsQuestionEnd *dnsEnd;
00034     int len, num;
00035 
00036     id ++;
00037     dnsHeader = (struct DnsHeader*)buf;
00038     dnsHeader->id = htons(id);
00039     dnsHeader->flags = htons(0x100);
00040     dnsHeader->questions = htons(1);
00041     dnsHeader->answers = 0;
00042     dnsHeader->authorities = 0;
00043     dnsHeader->additional = 0;
00044 
00045     len = sizeof(struct DnsHeader);
00046     while ((num = (int)strchr(name, '.')) != NULL) {
00047         num = num - (int)name;
00048         buf[len] = num;
00049         len ++;
00050         strncpy(&buf[len], name, num); 
00051         name = name + num + 1;
00052         len = len + num;
00053     }
00054 
00055     if ((num = strlen(name)) != NULL) {
00056         buf[len] = num;
00057         len ++; 
00058         strncpy(&buf[len], name, num); 
00059         len = len + num;
00060     }
00061     buf[len] = 0;
00062     len ++; 
00063 
00064     dnsEnd = (struct DnsQuestionEnd *)&buf[len];
00065     dnsEnd->type = htons(DNS_QUERY_A);
00066     dnsEnd->clas = htons(DNS_CLASS_IN);
00067 
00068     return len + sizeof(struct DnsQuestionEnd);
00069 }
00070 
00071 int getDnsResponse (const char *buf, int len, uint32_t *addr) {
00072     int i;
00073     struct DnsHeader *dnsHeader;
00074     struct DnsAnswer *dnsAnswer;
00075 
00076     // header
00077     dnsHeader = (struct DnsHeader*)buf;
00078     if (ntohs(dnsHeader->id) != id || (ntohs(dnsHeader->flags) & 0x800f) != 0x8000) {
00079         return -1;
00080     }
00081 
00082     // skip question
00083     for (i = sizeof(struct DnsHeader); buf[i] && i < len; i ++);
00084     i = i + 1 + sizeof(struct DnsQuestionEnd);
00085 
00086     // answer
00087     while (i < len) {
00088         dnsAnswer = (struct DnsAnswer*)&buf[i];
00089 
00090         if (dnsAnswer->clas != htons(DNS_CLASS_IN)) {
00091             return -1;
00092         }
00093 
00094         i = i + sizeof(struct DnsAnswer);
00095         if (dnsAnswer->type == htons(DNS_QUERY_A)) {
00096             // A record
00097             *addr = ((uint32_t)buf[i] << 24) + ((uint32_t)buf[i + 1] << 16) + ((uint32_t)buf[i + 2] << 8) + (uint32_t)buf[i + 3];
00098             return 0;
00099         }
00100         // next answer
00101         i = i + dnsAnswer->length;
00102     }
00103 
00104     return -1;
00105 }
00106 
00107 void isr_dns (UDPSocketEvent e) {
00108     char buf[512];
00109     Host dsthost;
00110     int len;
00111 
00112     if (e == UDPSOCKET_READABLE) {
00113         // recv responce;
00114         len = dns->recvfrom(buf, sizeof(buf), &dsthost);
00115 #ifdef DEBUG
00116         for (int i = 0; i < len; i ++) {
00117             printf(" %02x", (unsigned char)buf[i]);
00118         }
00119         puts("\r");
00120 #endif
00121         if (len >= sizeof(struct DnsHeader)) {
00122             getDnsResponse(buf, len, (uint32_t*)&dnsaddr);
00123         }
00124     }
00125 }
00126 
00127 int getHostByName (IpAddr nameserver, const char *name, uint32_t *addr) {
00128     UDPSocketErr err;
00129     Host myhost, dnshost;
00130     char buf[100];
00131     int i, len;
00132 
00133     // localhost
00134     if (!strcmp(name, "localhost")) {
00135         *addr = 0x0f000001;
00136         return 0;
00137     }
00138 
00139     dnsaddr = 0;
00140     dns = new UDPSocket;
00141     dns->setOnEvent(isr_dns);
00142 
00143     // bind
00144     myhost.setIp(eth.getIp());
00145     myhost.setPort(DNS_SRC_PORT);
00146     err = dns->bind(myhost);
00147     if (err != UDPSOCKET_OK) goto exit;
00148 
00149     // send request
00150     dnshost.setIp(nameserver);
00151     dnshost.setPort(DNS_PORT);
00152     len = createDnsRequest((char*)name, buf);
00153 #ifdef DEBUG
00154     for (int i = 0; i < len; i ++) {
00155         printf(" %02x", (unsigned char)buf[i]);
00156     }
00157     puts("\r");
00158 #endif
00159     dns->sendto(buf, len, &dnshost);
00160 
00161     // wait responce
00162     for (i = 0; i < DNS_TIMEOUT / 10; i ++) {
00163         if (dnsaddr) {
00164             // responce
00165             *addr = dnsaddr;
00166             break;
00167         }
00168         if (i % 500 == 499) {
00169             // retry
00170             dns->sendto(buf, len, &dnshost);
00171         }
00172         Net::poll();
00173         wait_ms(10);
00174     }
00175 
00176 exit:
00177     dns->resetOnEvent();
00178     delete dns;
00179 
00180     return dnsaddr ? 0 : -1;
00181 }