Tiny DNS Resolver

Dependencies:   EthernetNetIf mbed

Files at this revision

API Documentation at this revision

Comitter:
okini3939
Date:
Thu Jul 21 16:53:11 2011 +0000
Commit message:

Changed in this revision

EthernetNetIf.lib Show annotated file Show diff for this revision Revisions of this file
TinyResolver.cpp Show annotated file Show diff for this revision Revisions of this file
TinyResolver.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetNetIf.lib	Thu Jul 21 16:53:11 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/donatien/code/EthernetNetIf/#bc7df6da7589
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyResolver.cpp	Thu Jul 21 16:53:11 2011 +0000
@@ -0,0 +1,181 @@
+/*
+ * 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TinyResolver.h	Thu Jul 21 16:53:11 2011 +0000
@@ -0,0 +1,65 @@
+/*
+ * mbed Tiny DNS Resolver
+ * Copyright (c) 2011 Hiroshi Suga
+ * Released under the MIT License: http://mbed.org/license/mit
+ */
+
+/** @file
+ * @brief Tiny DNS Resolver
+ */
+
+#ifndef TinyResolver_h
+#define TinyResolver_h
+
+#include <inttypes.h>
+
+#define DEBUG
+
+#define DNS_PORT 53
+#define DNS_SRC_PORT 1234
+#define DNS_TIMEOUT 15000 // ms
+
+// dns
+#define DNS_QUERY_A 1
+#define DNS_QUERY_NS 2
+#define DNS_QUERY_CNAME 5
+#define DNS_QUERY_PTR 12
+#define DNS_QUERY_MX 15
+#define DNS_QUERY_AAAA 28
+#define DNS_QUERY_ANY 255
+#define DNS_CLASS_IN 1
+
+struct DnsHeader {
+        uint16_t id; 
+        uint16_t flags; 
+        uint16_t questions; 
+        uint16_t answers; 
+        uint16_t authorities; 
+        uint16_t additional; 
+};
+
+struct DnsQuestionEnd { 
+        uint16_t type; 
+        uint16_t clas; 
+};
+
+struct DnsAnswer {
+        uint16_t name; 
+        uint16_t type; 
+        uint16_t clas; 
+        uint32_t ttl; 
+        uint16_t length; 
+} __attribute__((packed)); 
+
+int createDnsRequest (char *name, char *buf);
+int getDnsResponse (const char *buf, int len, uint32_t *addr);
+
+/** resolv host by name
+ * @param nameserver DNS server
+ * @param name hostname
+ * @param addr IP address (return)
+ * @return 0:success, -1:failue
+ */
+int getHostByName (IpAddr nameserver, const char *name, uint32_t *addr);
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Jul 21 16:53:11 2011 +0000
@@ -0,0 +1,26 @@
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "TinyResolver.h"
+
+DigitalOut myled(LED1);
+Serial pc(USBTX, USBRX);
+EthernetNetIf eth; 
+
+int main () {
+    EthernetErr ethErr;
+    uint32_t addr;
+
+    myled = 1;
+
+    ethErr = eth.setup();
+    if(ethErr) {
+        return -1;
+    }
+
+	getHostByName(IpAddr(192,168,1,1), "mbed.org", &addr);
+
+	printf("IP address: %d.%d.%d.%d\r\n", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
+
+    myled = 0;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Jul 21 16:53:11 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912