Tiny DNS Resolver

Dependencies:   EthernetNetIf mbed

Committer:
okini3939
Date:
Thu Jul 21 16:53:11 2011 +0000
Revision:
0:477d4e2f281a

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:477d4e2f281a 1 /*
okini3939 0:477d4e2f281a 2 * mbed Tiny DNS Resolver
okini3939 0:477d4e2f281a 3 * Copyright (c) 2011 Hiroshi Suga
okini3939 0:477d4e2f281a 4 * Released under the MIT License: http://mbed.org/license/mit
okini3939 0:477d4e2f281a 5 */
okini3939 0:477d4e2f281a 6
okini3939 0:477d4e2f281a 7 /** @file
okini3939 0:477d4e2f281a 8 * @brief Tiny DNS Resolver
okini3939 0:477d4e2f281a 9 */
okini3939 0:477d4e2f281a 10
okini3939 0:477d4e2f281a 11 #include "mbed.h"
okini3939 0:477d4e2f281a 12 #include "EthernetNetIf.h"
okini3939 0:477d4e2f281a 13 #include "UDPSocket.h"
okini3939 0:477d4e2f281a 14 #include "TinyResolver.h"
okini3939 0:477d4e2f281a 15
okini3939 0:477d4e2f281a 16 // host to network short
okini3939 0:477d4e2f281a 17 #define htons( x ) ( (( (x) << 8 ) & 0xFF00) | (( (x) >> 8 ) & 0x00FF) )
okini3939 0:477d4e2f281a 18 #define ntohs( x ) htons(x)
okini3939 0:477d4e2f281a 19 // host to network long
okini3939 0:477d4e2f281a 20 #define htonl( x ) ( (( (x) << 24 ) & 0xFF000000) \
okini3939 0:477d4e2f281a 21 | (( (x) << 8 ) & 0x00FF0000) \
okini3939 0:477d4e2f281a 22 | (( (x) >> 8 ) & 0x0000FF00) \
okini3939 0:477d4e2f281a 23 | (( (x) >> 24 ) & 0x000000FF) )
okini3939 0:477d4e2f281a 24 #define ntohl( x ) htonl(x)
okini3939 0:477d4e2f281a 25
okini3939 0:477d4e2f281a 26 extern EthernetNetIf eth;
okini3939 0:477d4e2f281a 27 static UDPSocket *dns;
okini3939 0:477d4e2f281a 28 static volatile unsigned long dnsaddr;
okini3939 0:477d4e2f281a 29 static volatile unsigned long id;
okini3939 0:477d4e2f281a 30
okini3939 0:477d4e2f281a 31 int createDnsRequest (char *name, char *buf) {
okini3939 0:477d4e2f281a 32 struct DnsHeader *dnsHeader;
okini3939 0:477d4e2f281a 33 struct DnsQuestionEnd *dnsEnd;
okini3939 0:477d4e2f281a 34 int len, num;
okini3939 0:477d4e2f281a 35
okini3939 0:477d4e2f281a 36 id ++;
okini3939 0:477d4e2f281a 37 dnsHeader = (struct DnsHeader*)buf;
okini3939 0:477d4e2f281a 38 dnsHeader->id = htons(id);
okini3939 0:477d4e2f281a 39 dnsHeader->flags = htons(0x100);
okini3939 0:477d4e2f281a 40 dnsHeader->questions = htons(1);
okini3939 0:477d4e2f281a 41 dnsHeader->answers = 0;
okini3939 0:477d4e2f281a 42 dnsHeader->authorities = 0;
okini3939 0:477d4e2f281a 43 dnsHeader->additional = 0;
okini3939 0:477d4e2f281a 44
okini3939 0:477d4e2f281a 45 len = sizeof(struct DnsHeader);
okini3939 0:477d4e2f281a 46 while ((num = (int)strchr(name, '.')) != NULL) {
okini3939 0:477d4e2f281a 47 num = num - (int)name;
okini3939 0:477d4e2f281a 48 buf[len] = num;
okini3939 0:477d4e2f281a 49 len ++;
okini3939 0:477d4e2f281a 50 strncpy(&buf[len], name, num);
okini3939 0:477d4e2f281a 51 name = name + num + 1;
okini3939 0:477d4e2f281a 52 len = len + num;
okini3939 0:477d4e2f281a 53 }
okini3939 0:477d4e2f281a 54
okini3939 0:477d4e2f281a 55 if ((num = strlen(name)) != NULL) {
okini3939 0:477d4e2f281a 56 buf[len] = num;
okini3939 0:477d4e2f281a 57 len ++;
okini3939 0:477d4e2f281a 58 strncpy(&buf[len], name, num);
okini3939 0:477d4e2f281a 59 len = len + num;
okini3939 0:477d4e2f281a 60 }
okini3939 0:477d4e2f281a 61 buf[len] = 0;
okini3939 0:477d4e2f281a 62 len ++;
okini3939 0:477d4e2f281a 63
okini3939 0:477d4e2f281a 64 dnsEnd = (struct DnsQuestionEnd *)&buf[len];
okini3939 0:477d4e2f281a 65 dnsEnd->type = htons(DNS_QUERY_A);
okini3939 0:477d4e2f281a 66 dnsEnd->clas = htons(DNS_CLASS_IN);
okini3939 0:477d4e2f281a 67
okini3939 0:477d4e2f281a 68 return len + sizeof(struct DnsQuestionEnd);
okini3939 0:477d4e2f281a 69 }
okini3939 0:477d4e2f281a 70
okini3939 0:477d4e2f281a 71 int getDnsResponse (const char *buf, int len, uint32_t *addr) {
okini3939 0:477d4e2f281a 72 int i;
okini3939 0:477d4e2f281a 73 struct DnsHeader *dnsHeader;
okini3939 0:477d4e2f281a 74 struct DnsAnswer *dnsAnswer;
okini3939 0:477d4e2f281a 75
okini3939 0:477d4e2f281a 76 // header
okini3939 0:477d4e2f281a 77 dnsHeader = (struct DnsHeader*)buf;
okini3939 0:477d4e2f281a 78 if (ntohs(dnsHeader->id) != id || (ntohs(dnsHeader->flags) & 0x800f) != 0x8000) {
okini3939 0:477d4e2f281a 79 return -1;
okini3939 0:477d4e2f281a 80 }
okini3939 0:477d4e2f281a 81
okini3939 0:477d4e2f281a 82 // skip question
okini3939 0:477d4e2f281a 83 for (i = sizeof(struct DnsHeader); buf[i] && i < len; i ++);
okini3939 0:477d4e2f281a 84 i = i + 1 + sizeof(struct DnsQuestionEnd);
okini3939 0:477d4e2f281a 85
okini3939 0:477d4e2f281a 86 // answer
okini3939 0:477d4e2f281a 87 while (i < len) {
okini3939 0:477d4e2f281a 88 dnsAnswer = (struct DnsAnswer*)&buf[i];
okini3939 0:477d4e2f281a 89
okini3939 0:477d4e2f281a 90 if (dnsAnswer->clas != htons(DNS_CLASS_IN)) {
okini3939 0:477d4e2f281a 91 return -1;
okini3939 0:477d4e2f281a 92 }
okini3939 0:477d4e2f281a 93
okini3939 0:477d4e2f281a 94 i = i + sizeof(struct DnsAnswer);
okini3939 0:477d4e2f281a 95 if (dnsAnswer->type == htons(DNS_QUERY_A)) {
okini3939 0:477d4e2f281a 96 // A record
okini3939 0:477d4e2f281a 97 *addr = ((uint32_t)buf[i] << 24) + ((uint32_t)buf[i + 1] << 16) + ((uint32_t)buf[i + 2] << 8) + (uint32_t)buf[i + 3];
okini3939 0:477d4e2f281a 98 return 0;
okini3939 0:477d4e2f281a 99 }
okini3939 0:477d4e2f281a 100 // next answer
okini3939 0:477d4e2f281a 101 i = i + dnsAnswer->length;
okini3939 0:477d4e2f281a 102 }
okini3939 0:477d4e2f281a 103
okini3939 0:477d4e2f281a 104 return -1;
okini3939 0:477d4e2f281a 105 }
okini3939 0:477d4e2f281a 106
okini3939 0:477d4e2f281a 107 void isr_dns (UDPSocketEvent e) {
okini3939 0:477d4e2f281a 108 char buf[512];
okini3939 0:477d4e2f281a 109 Host dsthost;
okini3939 0:477d4e2f281a 110 int len;
okini3939 0:477d4e2f281a 111
okini3939 0:477d4e2f281a 112 if (e == UDPSOCKET_READABLE) {
okini3939 0:477d4e2f281a 113 // recv responce;
okini3939 0:477d4e2f281a 114 len = dns->recvfrom(buf, sizeof(buf), &dsthost);
okini3939 0:477d4e2f281a 115 #ifdef DEBUG
okini3939 0:477d4e2f281a 116 for (int i = 0; i < len; i ++) {
okini3939 0:477d4e2f281a 117 printf(" %02x", (unsigned char)buf[i]);
okini3939 0:477d4e2f281a 118 }
okini3939 0:477d4e2f281a 119 puts("\r");
okini3939 0:477d4e2f281a 120 #endif
okini3939 0:477d4e2f281a 121 if (len >= sizeof(struct DnsHeader)) {
okini3939 0:477d4e2f281a 122 getDnsResponse(buf, len, (uint32_t*)&dnsaddr);
okini3939 0:477d4e2f281a 123 }
okini3939 0:477d4e2f281a 124 }
okini3939 0:477d4e2f281a 125 }
okini3939 0:477d4e2f281a 126
okini3939 0:477d4e2f281a 127 int getHostByName (IpAddr nameserver, const char *name, uint32_t *addr) {
okini3939 0:477d4e2f281a 128 UDPSocketErr err;
okini3939 0:477d4e2f281a 129 Host myhost, dnshost;
okini3939 0:477d4e2f281a 130 char buf[100];
okini3939 0:477d4e2f281a 131 int i, len;
okini3939 0:477d4e2f281a 132
okini3939 0:477d4e2f281a 133 // localhost
okini3939 0:477d4e2f281a 134 if (!strcmp(name, "localhost")) {
okini3939 0:477d4e2f281a 135 *addr = 0x0f000001;
okini3939 0:477d4e2f281a 136 return 0;
okini3939 0:477d4e2f281a 137 }
okini3939 0:477d4e2f281a 138
okini3939 0:477d4e2f281a 139 dnsaddr = 0;
okini3939 0:477d4e2f281a 140 dns = new UDPSocket;
okini3939 0:477d4e2f281a 141 dns->setOnEvent(isr_dns);
okini3939 0:477d4e2f281a 142
okini3939 0:477d4e2f281a 143 // bind
okini3939 0:477d4e2f281a 144 myhost.setIp(eth.getIp());
okini3939 0:477d4e2f281a 145 myhost.setPort(DNS_SRC_PORT);
okini3939 0:477d4e2f281a 146 err = dns->bind(myhost);
okini3939 0:477d4e2f281a 147 if (err != UDPSOCKET_OK) goto exit;
okini3939 0:477d4e2f281a 148
okini3939 0:477d4e2f281a 149 // send request
okini3939 0:477d4e2f281a 150 dnshost.setIp(nameserver);
okini3939 0:477d4e2f281a 151 dnshost.setPort(DNS_PORT);
okini3939 0:477d4e2f281a 152 len = createDnsRequest((char*)name, buf);
okini3939 0:477d4e2f281a 153 #ifdef DEBUG
okini3939 0:477d4e2f281a 154 for (int i = 0; i < len; i ++) {
okini3939 0:477d4e2f281a 155 printf(" %02x", (unsigned char)buf[i]);
okini3939 0:477d4e2f281a 156 }
okini3939 0:477d4e2f281a 157 puts("\r");
okini3939 0:477d4e2f281a 158 #endif
okini3939 0:477d4e2f281a 159 dns->sendto(buf, len, &dnshost);
okini3939 0:477d4e2f281a 160
okini3939 0:477d4e2f281a 161 // wait responce
okini3939 0:477d4e2f281a 162 for (i = 0; i < DNS_TIMEOUT / 10; i ++) {
okini3939 0:477d4e2f281a 163 if (dnsaddr) {
okini3939 0:477d4e2f281a 164 // responce
okini3939 0:477d4e2f281a 165 *addr = dnsaddr;
okini3939 0:477d4e2f281a 166 break;
okini3939 0:477d4e2f281a 167 }
okini3939 0:477d4e2f281a 168 if (i % 500 == 499) {
okini3939 0:477d4e2f281a 169 // retry
okini3939 0:477d4e2f281a 170 dns->sendto(buf, len, &dnshost);
okini3939 0:477d4e2f281a 171 }
okini3939 0:477d4e2f281a 172 Net::poll();
okini3939 0:477d4e2f281a 173 wait_ms(10);
okini3939 0:477d4e2f281a 174 }
okini3939 0:477d4e2f281a 175
okini3939 0:477d4e2f281a 176 exit:
okini3939 0:477d4e2f281a 177 dns->resetOnEvent();
okini3939 0:477d4e2f281a 178 delete dns;
okini3939 0:477d4e2f281a 179
okini3939 0:477d4e2f281a 180 return dnsaddr ? 0 : -1;
okini3939 0:477d4e2f281a 181 }