00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 #include <cfg/os.h>
00092 #include <string.h>
00093
00094 #include <sys/device.h>
00095 #include <sys/timer.h>
00096 #include <sys/heap.h>
00097
00098 #include <arpa/inet.h>
00099 #include <net/if_var.h>
00100 #include <sys/socket.h>
00101
00102 #ifdef NUTDEBUG
00103 #include <stdio.h>
00104 #endif
00105
00110
00111 typedef struct {
00112 uint8_t *doc_hostname;
00113 uint8_t *doc_domain;
00114 uint32_t doc_ip1;
00115 uint32_t doc_ip2;
00116 } DNSCONFIG;
00117
00118 static DNSCONFIG doc;
00119
00120 typedef struct {
00121 uint16_t doh_id;
00122 uint16_t doh_flags;
00123 uint16_t doh_quests;
00124 uint16_t doh_answers;
00125 uint16_t doh_authrr;
00126 uint16_t doh_addrr;
00127 } DNSHEADER;
00128
00129 typedef struct {
00130 uint8_t *doq_name;
00131 uint16_t doq_type;
00132 uint16_t doq_class;
00133 } DNSQUESTION;
00134
00135 typedef struct {
00136 uint8_t *dor_name;
00137 uint16_t dor_type;
00138 uint16_t dor_class;
00139 uint32_t dor_ttl;
00140 uint16_t dor_len;
00141 uint8_t *dor_data;
00142 } DNSRESOURCE;
00143
00144 #ifdef NUTDEBUG
00145 void DumpDnsHeader(FILE * stream, DNSHEADER * doh)
00146 {
00147 fprintf(stream,
00148 "HEADER: id=%u flg=%04X #q=%u #an=%u #au=%u #ad=%u\r\n",
00149 doh->doh_id, doh->doh_flags, doh->doh_quests, doh->doh_answers, doh->doh_authrr, doh->doh_addrr);
00150 }
00151
00152 void DumpDnsQuestion(FILE * stream, DNSQUESTION * doq)
00153 {
00154 fprintf(stream, "QUESTION: name='%s' type=%u class=%u\r\n", doq->doq_name, doq->doq_type, doq->doq_class);
00155 }
00156
00157 void DumpDnsResource(FILE * stream, DNSRESOURCE * dor)
00158 {
00159 uint16_t i;
00160
00161 fprintf(stream, "RESOURCE: name='%s' type=%u class=%u ttl=%lu len=%u ",
00162 dor->dor_name, dor->dor_type, dor->dor_class, dor->dor_ttl, dor->dor_len);
00163 for (i = 0; i < dor->dor_len; i++)
00164 fprintf(stream, "%02X ", dor->dor_data[i]);
00165 fputc('\n', stream);
00166 }
00167 #endif
00168
00169 static uint16_t AddShort(uint8_t * cp, uint16_t val)
00170 {
00171 *cp++ = (uint8_t) (val >> 8);
00172 *cp++ = (uint8_t) val;
00173
00174 return 2;
00175 }
00176
00177 static uint16_t AddName(uint8_t * cp, CONST uint8_t * name)
00178 {
00179 uint8_t *lcp;
00180 uint16_t rc = strlen((char *)name) + 2;
00181
00182 lcp = cp++;
00183 *lcp = 0;
00184 while (*name) {
00185 if (*name == '.') {
00186 lcp = cp++;
00187 *lcp = 0;
00188 name++;
00189 } else {
00190 *cp++ = *name++;
00191 (*lcp)++;
00192 }
00193 }
00194 *cp = 0;
00195
00196 return rc;
00197 }
00198
00199 static uint16_t ScanShort(uint8_t * cp, uint16_t * val)
00200 {
00201 *val = (uint16_t)(*cp++) << 8;
00202 *val |= *cp;
00203
00204 return 2;
00205 }
00206
00207 static uint16_t ScanLong(uint8_t * cp, uint32_t * val)
00208 {
00209 *val = *cp++;
00210 *val <<= 8;
00211 *val |= *cp++;
00212 *val <<= 8;
00213 *val |= *cp++;
00214 *val <<= 8;
00215 *val |= *cp;
00216
00217 return 4;
00218 }
00219
00220 static uint16_t ScanName(uint8_t * cp, uint8_t ** npp)
00221 {
00222 uint8_t len;
00223 uint16_t rc;
00224 uint8_t *np;
00225
00226 if (*npp) {
00227 NutHeapFree(*npp);
00228 *npp = 0;
00229 }
00230
00231 if ((*cp & 0xC0) == 0xC0)
00232 return 2;
00233
00234 rc = strlen((char *)cp) + 1;
00235 np = *npp = NutHeapAlloc(rc);
00236 len = *cp++;
00237 while (len) {
00238 while (len--)
00239 *np++ = *cp++;
00240 if ((len = *cp++) != 0)
00241 *np++ = '.';
00242 }
00243 *np = 0;
00244
00245 return rc;
00246 }
00247
00248 static uint16_t ScanBinary(uint8_t * cp, uint8_t ** npp, uint16_t len)
00249 {
00250 if (*npp)
00251 NutHeapFree(*npp);
00252 *npp = NutHeapAlloc(len);
00253 memcpy(*npp, cp, len);
00254
00255 return len;
00256 }
00257
00258 static DNSHEADER *CreateDnsHeader(DNSHEADER * doh, uint16_t id)
00259 {
00260 if (doh == 0)
00261 doh = NutHeapAllocClear(sizeof(DNSHEADER));
00262 if (doh) {
00263 doh->doh_id = id;
00264 doh->doh_flags = 0x0100;
00265 doh->doh_quests = 1;
00266 }
00267 return doh;
00268 }
00269
00270 static void ReleaseDnsHeader(DNSHEADER * doh)
00271 {
00272 if (doh)
00273 NutHeapFree(doh);
00274 }
00275
00276 static uint16_t EncodeDnsHeader(uint8_t * buf, DNSHEADER * doh)
00277 {
00278 uint16_t rc;
00279
00280 rc = AddShort(buf, doh->doh_id);
00281 rc += AddShort(buf + rc, doh->doh_flags);
00282 rc += AddShort(buf + rc, doh->doh_quests);
00283 rc += AddShort(buf + rc, doh->doh_answers);
00284 rc += AddShort(buf + rc, doh->doh_authrr);
00285 rc += AddShort(buf + rc, doh->doh_addrr);
00286
00287 return rc;
00288 }
00289
00290 static uint16_t DecodeDnsHeader(DNSHEADER * doh, uint8_t * buf)
00291 {
00292 uint16_t rc;
00293
00294 rc = ScanShort(buf, &doh->doh_id);
00295 rc += ScanShort(buf + rc, &doh->doh_flags);
00296 rc += ScanShort(buf + rc, &doh->doh_quests);
00297 rc += ScanShort(buf + rc, &doh->doh_answers);
00298 rc += ScanShort(buf + rc, &doh->doh_authrr);
00299 rc += ScanShort(buf + rc, &doh->doh_addrr);
00300
00301 return rc;
00302 }
00303
00304 static DNSQUESTION *CreateDnsQuestion(DNSQUESTION * doq, CONST uint8_t * name, uint16_t type)
00305 {
00306 if (doq == 0)
00307 doq = NutHeapAllocClear(sizeof(DNSQUESTION));
00308 if (doq) {
00309 if (doq->doq_name)
00310 NutHeapFree(doq->doq_name);
00311 doq->doq_name = NutHeapAlloc(strlen((char *)name) + 1);
00312 strcpy((char *)doq->doq_name, (char *)name);
00313 doq->doq_type = type;
00314 doq->doq_class = 1;
00315 }
00316 return doq;
00317 }
00318
00319 static void ReleaseDnsQuestion(DNSQUESTION * doq)
00320 {
00321 if (doq) {
00322 if (doq->doq_name)
00323 NutHeapFree(doq->doq_name);
00324 NutHeapFree(doq);
00325 }
00326 }
00327
00328 static uint16_t EncodeDnsQuestion(uint8_t * buf, DNSQUESTION * doq)
00329 {
00330 uint16_t rc;
00331
00332 rc = AddName(buf, doq->doq_name);
00333 rc += AddShort(buf + rc, doq->doq_type);
00334 rc += AddShort(buf + rc, doq->doq_class);
00335
00336 return rc;
00337 }
00338
00339 static uint16_t DecodeDnsQuestion(DNSQUESTION * doq, uint8_t * buf)
00340 {
00341 uint16_t rc;
00342
00343 rc = ScanName(buf, &doq->doq_name);
00344 rc += ScanShort(buf + rc, &doq->doq_type);
00345 rc += ScanShort(buf + rc, &doq->doq_class);
00346
00347 return rc;
00348 }
00349
00350 static DNSRESOURCE *CreateDnsResource(DNSRESOURCE * dor)
00351 {
00352 if (dor == 0)
00353 dor = NutHeapAllocClear(sizeof(DNSRESOURCE));
00354 return dor;
00355 }
00356
00357 static void ReleaseDnsResource(DNSRESOURCE * dor)
00358 {
00359 if (dor) {
00360 if (dor->dor_name)
00361 NutHeapFree(dor->dor_name);
00362 if (dor->dor_data)
00363 NutHeapFree(dor->dor_data);
00364 NutHeapFree(dor);
00365 }
00366 }
00367
00368 static uint16_t DecodeDnsResource(DNSRESOURCE * dor, uint8_t * buf)
00369 {
00370 uint16_t rc;
00371
00372 rc = ScanName(buf, &dor->dor_name);
00373 rc += ScanShort(buf + rc, &dor->dor_type);
00374 rc += ScanShort(buf + rc, &dor->dor_class);
00375 rc += ScanLong(buf + rc, &dor->dor_ttl);
00376 rc += ScanShort(buf + rc, &dor->dor_len);
00377 rc += ScanBinary(buf + rc, &dor->dor_data, dor->dor_len);
00378
00379 return rc;
00380 }
00381
00390 void NutDnsConfig2(uint8_t * hostname, uint8_t * domain, uint32_t pdnsip, uint32_t sdnsip)
00391 {
00392 if (doc.doc_hostname) {
00393 NutHeapFree(doc.doc_hostname);
00394 doc.doc_hostname = 0;
00395 }
00396 if (doc.doc_domain) {
00397 NutHeapFree(doc.doc_domain);
00398 doc.doc_domain = 0;
00399 }
00400 if (hostname) {
00401 doc.doc_hostname = NutHeapAlloc(strlen((char *)hostname) + 1);
00402 strcpy((char *)doc.doc_hostname, (char *)hostname);
00403 }
00404 if (domain) {
00405 doc.doc_domain = NutHeapAlloc(strlen((char *)domain) + 1);
00406 strcpy((char *)doc.doc_domain, (char *)domain);
00407 }
00408 doc.doc_ip1 = pdnsip;
00409 doc.doc_ip2 = sdnsip;
00410 }
00411
00421 void NutDnsConfig(uint8_t * hostname, uint8_t * domain, uint32_t dnsip)
00422 {
00423 NutDnsConfig2(hostname, domain, dnsip, 0);
00424 }
00425
00426 void NutDnsGetConfig2(char ** hostname, char ** domain, uint32_t *pdnsip, uint32_t *sdnsip)
00427 {
00428 if (hostname) {
00429 *hostname = (char *)doc.doc_hostname;
00430 }
00431 if (domain) {
00432 *domain = (char *)doc.doc_domain;
00433 }
00434 if (pdnsip) {
00435 *pdnsip = doc.doc_ip1;
00436 }
00437 if (sdnsip) {
00438 *sdnsip = doc.doc_ip2;
00439 }
00440 }
00441
00454 uint32_t NutDnsGetResource(CONST uint8_t * hostname, CONST uint16_t type);
00455
00456 uint32_t NutDnsGetHostByName(CONST uint8_t * hostname)
00457 {
00458 return NutDnsGetResource(hostname, 1);
00459 }
00460
00461 uint32_t NutDnsGetMxByDomain(CONST uint8_t * hostname)
00462 {
00463 return NutDnsGetResource(hostname, 0x0F);
00464 }
00465
00466 uint32_t NutDnsGetResource(CONST uint8_t * hostname, CONST uint16_t type)
00467 {
00468 uint32_t ip = 0;
00469 uint8_t *pkt;
00470 uint16_t len;
00471 uint16_t id = 0;
00472 UDPSOCKET *sock;
00473 DNSHEADER *doh = 0;
00474 DNSQUESTION *doq = 0;
00475 DNSRESOURCE *dor = 0;
00476 int n;
00477 int retries;
00478 uint32_t raddr;
00479 uint16_t rport;
00480
00481
00482
00483
00484 if (doc.doc_ip1 == 0 && doc.doc_ip2 == 0)
00485 return 0;
00486
00487
00488
00489
00490
00491 if ((sock = NutUdpCreateSocket(0)) == 0)
00492 return 0;
00493 pkt = NutHeapAlloc(512);
00494
00495 for (retries = 0; retries < 6; retries++) {
00496
00497
00498
00499
00500 doh = CreateDnsHeader(doh, ++id);
00501 doq = CreateDnsQuestion(doq, hostname, type);
00502
00503 #ifdef NUTDEBUG
00504
00505
00506 #endif
00507
00508
00509
00510
00511
00512 len = EncodeDnsHeader(pkt, doh);
00513 len += EncodeDnsQuestion(pkt + len, doq);
00514
00515 if ((retries & 1) == 0 || doc.doc_ip2 == 0) {
00516 if (NutUdpSendTo(sock, doc.doc_ip1, 53, pkt, len) < 0)
00517 break;
00518 } else {
00519 if (NutUdpSendTo(sock, doc.doc_ip2, 53, pkt, len) < 0)
00520 break;
00521 }
00522
00523
00524
00525
00526
00527 for (;;) {
00528 len = 0;
00529 n = NutUdpReceiveFrom(sock, &raddr, &rport, pkt, 512, 1000);
00530 if (n <= 0)
00531 break;
00532 if (n > 12) {
00533 len = DecodeDnsHeader(doh, pkt);
00534 #ifdef NUTDEBUG
00535
00536 #endif
00537 if (doh->doh_id == id)
00538 break;
00539 }
00540 }
00541
00542
00543
00544
00545 if (len && doh->doh_quests == 1) {
00546 len += DecodeDnsQuestion(doq, pkt + len);
00547 #ifdef NUTDEBUG
00548
00549 #endif
00550 if (doh->doh_answers < 1)
00551 break;
00552 else {
00553 for (n = 1; n <= (int) doh->doh_answers; n++) {
00554 dor = CreateDnsResource(dor);
00555 len += DecodeDnsResource(dor, pkt + len);
00556 #ifdef NUTDEBUG
00557
00558 #endif
00559 if (dor->dor_type == 1)
00560 break;
00561 }
00562 if (dor->dor_len == 4) {
00563 ip = *dor->dor_data;
00564 ip += (uint32_t)(*(dor->dor_data + 1)) << 8;
00565 ip += (uint32_t)(*(dor->dor_data + 2)) << 16;
00566 ip += (uint32_t)(*(dor->dor_data + 3)) << 24;
00567 break;
00568 }
00569
00570 }
00571 }
00572 }
00573
00574
00575
00576
00577 ReleaseDnsHeader(doh);
00578 ReleaseDnsQuestion(doq);
00579 ReleaseDnsResource(dor);
00580
00581 NutHeapFree(pkt);
00582 NutUdpDestroySocket(sock);
00583
00584 return ip;
00585 }
00586