Tiny DNS Resolver
Dependencies: EthernetNetIf mbed
TinyResolver.cpp@0:477d4e2f281a, 2011-07-21 (annotated)
- Committer:
- okini3939
- Date:
- Thu Jul 21 16:53:11 2011 +0000
- Revision:
- 0:477d4e2f281a
Who changed what in which revision?
User | Revision | Line number | New 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 | } |