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
00092
00093
00094
00095
00096
00097
00098
00099 #include <cfg/os.h>
00100
00101 #include <sys/device.h>
00102 #include <sys/timer.h>
00103 #include <sys/heap.h>
00104
00105 #include <arpa/inet.h>
00106 #include <net/if_var.h>
00107 #include <sys/socket.h>
00108
00109 #include <stdlib.h>
00110 #include <string.h>
00111 #include <memdebug.h>
00112
00113 #ifdef NUTDEBUG
00114 #include <stdio.h>
00115 #endif
00116
00121
00122 typedef struct {
00123 uint8_t *doc_hostname;
00124 uint8_t *doc_domain;
00125 uint32_t doc_ip1;
00126 uint32_t doc_ip2;
00127 } DNSCONFIG;
00128
00129 static DNSCONFIG doc;
00130
00131 typedef struct {
00132 uint16_t doh_id;
00133 uint16_t doh_flags;
00134 uint16_t doh_quests;
00135 uint16_t doh_answers;
00136 uint16_t doh_authrr;
00137 uint16_t doh_addrr;
00138 } DNSHEADER;
00139
00140 typedef struct {
00141 uint8_t *doq_name;
00142 uint16_t doq_type;
00143 uint16_t doq_class;
00144 } DNSQUESTION;
00145
00146 typedef struct {
00147 uint8_t *dor_name;
00148 uint16_t dor_type;
00149 uint16_t dor_class;
00150 uint32_t dor_ttl;
00151 uint16_t dor_len;
00152 uint8_t *dor_data;
00153 } DNSRESOURCE;
00154
00155 #ifdef NUTDEBUG
00156 void DumpDnsHeader(FILE * stream, DNSHEADER * doh)
00157 {
00158 fprintf(stream,
00159 "HEADER: id=%u flg=%04X #q=%u #an=%u #au=%u #ad=%u\r\n",
00160 doh->doh_id, doh->doh_flags, doh->doh_quests, doh->doh_answers, doh->doh_authrr, doh->doh_addrr);
00161 }
00162
00163 void DumpDnsQuestion(FILE * stream, DNSQUESTION * doq)
00164 {
00165 fprintf(stream, "QUESTION: name='%s' type=%u class=%u\r\n", doq->doq_name, doq->doq_type, doq->doq_class);
00166 }
00167
00168 void DumpDnsResource(FILE * stream, DNSRESOURCE * dor)
00169 {
00170 uint16_t i;
00171
00172 fprintf(stream, "RESOURCE: name='%s' type=%u class=%u ttl=%lu len=%u ",
00173 dor->dor_name, dor->dor_type, dor->dor_class, dor->dor_ttl, dor->dor_len);
00174 for (i = 0; i < dor->dor_len; i++)
00175 fprintf(stream, "%02X ", dor->dor_data[i]);
00176 fputc('\n', stream);
00177 }
00178 #endif
00179
00180 static uint16_t AddShort(uint8_t * cp, uint16_t val)
00181 {
00182 *cp++ = (uint8_t) (val >> 8);
00183 *cp++ = (uint8_t) val;
00184
00185 return 2;
00186 }
00187
00188 static uint16_t AddName(uint8_t * cp, CONST uint8_t * name)
00189 {
00190 uint8_t *lcp;
00191 uint16_t rc = strlen((char *)name) + 2;
00192
00193 lcp = cp++;
00194 *lcp = 0;
00195 while (*name) {
00196 if (*name == '.') {
00197 lcp = cp++;
00198 *lcp = 0;
00199 name++;
00200 } else {
00201 *cp++ = *name++;
00202 (*lcp)++;
00203 }
00204 }
00205 *cp = 0;
00206
00207 return rc;
00208 }
00209
00210 static uint16_t ScanShort(uint8_t * cp, uint16_t * val)
00211 {
00212 *val = (uint16_t)(*cp++) << 8;
00213 *val |= *cp;
00214
00215 return 2;
00216 }
00217
00218 static uint16_t ScanLong(uint8_t * cp, uint32_t * val)
00219 {
00220 *val = *cp++;
00221 *val <<= 8;
00222 *val |= *cp++;
00223 *val <<= 8;
00224 *val |= *cp++;
00225 *val <<= 8;
00226 *val |= *cp;
00227
00228 return 4;
00229 }
00230
00231 static uint16_t ScanName(uint8_t * cp, uint8_t ** npp)
00232 {
00233 uint8_t len;
00234 uint16_t rc;
00235 uint8_t *np;
00236
00237 if (*npp) {
00238 free(*npp);
00239 *npp = 0;
00240 }
00241
00242 if ((*cp & 0xC0) == 0xC0)
00243 return 2;
00244
00245 rc = strlen((char *)cp) + 1;
00246 np = *npp = malloc(rc);
00247 len = *cp++;
00248 while (len) {
00249 while (len--)
00250 *np++ = *cp++;
00251 if ((len = *cp++) != 0)
00252 *np++ = '.';
00253 }
00254 *np = 0;
00255
00256 return rc;
00257 }
00258
00259 static uint16_t ScanBinary(uint8_t * cp, uint8_t ** npp, uint16_t len)
00260 {
00261 if (*npp)
00262 free(*npp);
00263 *npp = malloc(len);
00264 memcpy(*npp, cp, len);
00265
00266 return len;
00267 }
00268
00269 static DNSHEADER *CreateDnsHeader(DNSHEADER * doh, uint16_t id)
00270 {
00271 if (doh == NULL)
00272 doh = calloc(1, sizeof(DNSHEADER));
00273 if (doh) {
00274 doh->doh_id = id;
00275 doh->doh_flags = 0x0100;
00276 doh->doh_quests = 1;
00277 }
00278 return doh;
00279 }
00280
00281 static void ReleaseDnsHeader(DNSHEADER * doh)
00282 {
00283 if (doh)
00284 free(doh);
00285 }
00286
00287 static uint16_t EncodeDnsHeader(uint8_t * buf, DNSHEADER * doh)
00288 {
00289 uint16_t rc;
00290
00291 rc = AddShort(buf, doh->doh_id);
00292 rc += AddShort(buf + rc, doh->doh_flags);
00293 rc += AddShort(buf + rc, doh->doh_quests);
00294 rc += AddShort(buf + rc, doh->doh_answers);
00295 rc += AddShort(buf + rc, doh->doh_authrr);
00296 rc += AddShort(buf + rc, doh->doh_addrr);
00297
00298 return rc;
00299 }
00300
00301 static uint16_t DecodeDnsHeader(DNSHEADER * doh, uint8_t * buf)
00302 {
00303 uint16_t rc;
00304
00305 rc = ScanShort(buf, &doh->doh_id);
00306 rc += ScanShort(buf + rc, &doh->doh_flags);
00307 rc += ScanShort(buf + rc, &doh->doh_quests);
00308 rc += ScanShort(buf + rc, &doh->doh_answers);
00309 rc += ScanShort(buf + rc, &doh->doh_authrr);
00310 rc += ScanShort(buf + rc, &doh->doh_addrr);
00311
00312 return rc;
00313 }
00314
00315 static DNSQUESTION *CreateDnsQuestion(DNSQUESTION * doq, CONST uint8_t * name, uint16_t type)
00316 {
00317 if (doq == NULL)
00318 doq = calloc(1, sizeof(DNSQUESTION));
00319 if (doq) {
00320 if (doq->doq_name)
00321 free(doq->doq_name);
00322 doq->doq_name = (uint8_t *)strdup((char *)name);
00323 doq->doq_type = type;
00324 doq->doq_class = 1;
00325 }
00326 return doq;
00327 }
00328
00329 static void ReleaseDnsQuestion(DNSQUESTION * doq)
00330 {
00331 if (doq) {
00332 if (doq->doq_name)
00333 free(doq->doq_name);
00334 free(doq);
00335 }
00336 }
00337
00338 static uint16_t EncodeDnsQuestion(uint8_t * buf, DNSQUESTION * doq)
00339 {
00340 uint16_t rc;
00341
00342 rc = AddName(buf, doq->doq_name);
00343 rc += AddShort(buf + rc, doq->doq_type);
00344 rc += AddShort(buf + rc, doq->doq_class);
00345
00346 return rc;
00347 }
00348
00349 static uint16_t DecodeDnsQuestion(DNSQUESTION * doq, uint8_t * buf)
00350 {
00351 uint16_t rc;
00352
00353 rc = ScanName(buf, &doq->doq_name);
00354 rc += ScanShort(buf + rc, &doq->doq_type);
00355 rc += ScanShort(buf + rc, &doq->doq_class);
00356
00357 return rc;
00358 }
00359
00360 static DNSRESOURCE *CreateDnsResource(DNSRESOURCE * dor)
00361 {
00362 if (dor == NULL)
00363 dor = calloc(1, sizeof(DNSRESOURCE));
00364 return dor;
00365 }
00366
00367 static void ReleaseDnsResource(DNSRESOURCE * dor)
00368 {
00369 if (dor) {
00370 if (dor->dor_name)
00371 free(dor->dor_name);
00372 if (dor->dor_data)
00373 free(dor->dor_data);
00374 free(dor);
00375 }
00376 }
00377
00378 static uint16_t DecodeDnsResource(DNSRESOURCE * dor, uint8_t * buf)
00379 {
00380 uint16_t rc;
00381
00382 rc = ScanName(buf, &dor->dor_name);
00383 rc += ScanShort(buf + rc, &dor->dor_type);
00384 rc += ScanShort(buf + rc, &dor->dor_class);
00385 rc += ScanLong(buf + rc, &dor->dor_ttl);
00386 rc += ScanShort(buf + rc, &dor->dor_len);
00387 rc += ScanBinary(buf + rc, &dor->dor_data, dor->dor_len);
00388
00389 return rc;
00390 }
00391
00400 void NutDnsConfig2(uint8_t * hostname, uint8_t * domain, uint32_t pdnsip, uint32_t sdnsip)
00401 {
00402 if (doc.doc_hostname) {
00403 free(doc.doc_hostname);
00404 doc.doc_hostname = 0;
00405 }
00406 if (doc.doc_domain) {
00407 free(doc.doc_domain);
00408 doc.doc_domain = 0;
00409 }
00410 if (hostname) {
00411 doc.doc_hostname = (uint8_t *)strdup((char *)hostname);
00412 }
00413 if (domain) {
00414 doc.doc_domain = (uint8_t *)strdup((char *)domain);
00415 }
00416 doc.doc_ip1 = pdnsip;
00417 doc.doc_ip2 = sdnsip;
00418 }
00419
00429 void NutDnsConfig(uint8_t * hostname, uint8_t * domain, uint32_t dnsip)
00430 {
00431 NutDnsConfig2(hostname, domain, dnsip, 0);
00432 }
00433
00434 void NutDnsGetConfig2(char ** hostname, char ** domain, uint32_t *pdnsip, uint32_t *sdnsip)
00435 {
00436 if (hostname) {
00437 *hostname = (char *)doc.doc_hostname;
00438 }
00439 if (domain) {
00440 *domain = (char *)doc.doc_domain;
00441 }
00442 if (pdnsip) {
00443 *pdnsip = doc.doc_ip1;
00444 }
00445 if (sdnsip) {
00446 *sdnsip = doc.doc_ip2;
00447 }
00448 }
00449
00462 uint32_t NutDnsGetResource(CONST uint8_t * hostname, CONST uint16_t type);
00463
00464 uint32_t NutDnsGetHostByName(CONST uint8_t * hostname)
00465 {
00466 return NutDnsGetResource(hostname, 1);
00467 }
00468
00469 uint32_t NutDnsGetMxByDomain(CONST uint8_t * hostname)
00470 {
00471 return NutDnsGetResource(hostname, 0x0F);
00472 }
00473
00474 uint32_t NutDnsGetResource(CONST uint8_t * hostname, CONST uint16_t type)
00475 {
00476 uint32_t ip = 0;
00477 uint8_t *pkt;
00478 uint16_t len;
00479 uint16_t id = 0;
00480 UDPSOCKET *sock;
00481 DNSHEADER *doh = 0;
00482 DNSQUESTION *doq = 0;
00483 DNSRESOURCE *dor = 0;
00484 int n;
00485 int retries;
00486 uint32_t raddr;
00487 uint16_t rport;
00488
00489
00490
00491
00492 if (doc.doc_ip1 == 0 && doc.doc_ip2 == 0)
00493 return 0;
00494
00495
00496
00497
00498
00499 if ((sock = NutUdpCreateSocket(0)) == 0)
00500 return 0;
00501 pkt = malloc(512);
00502
00503 for (retries = 0; retries < 6; retries++) {
00504
00505
00506
00507
00508 doh = CreateDnsHeader(doh, ++id);
00509 doq = CreateDnsQuestion(doq, hostname, type);
00510
00511 #ifdef NUTDEBUG
00512
00513
00514 #endif
00515
00516
00517
00518
00519
00520 len = EncodeDnsHeader(pkt, doh);
00521 len += EncodeDnsQuestion(pkt + len, doq);
00522
00523 if ((retries & 1) == 0 || doc.doc_ip2 == 0) {
00524 if (NutUdpSendTo(sock, doc.doc_ip1, 53, pkt, len) < 0)
00525 break;
00526 } else {
00527 if (NutUdpSendTo(sock, doc.doc_ip2, 53, pkt, len) < 0)
00528 break;
00529 }
00530
00531
00532
00533
00534
00535 for (;;) {
00536 len = 0;
00537 n = NutUdpReceiveFrom(sock, &raddr, &rport, pkt, 512, 1000);
00538 if (n <= 0)
00539 break;
00540 if (n > 12) {
00541 len = DecodeDnsHeader(doh, pkt);
00542 #ifdef NUTDEBUG
00543
00544 #endif
00545 if (doh->doh_id == id)
00546 break;
00547 }
00548 }
00549
00550
00551
00552
00553 if (len && doh->doh_quests == 1) {
00554 len += DecodeDnsQuestion(doq, pkt + len);
00555 #ifdef NUTDEBUG
00556
00557 #endif
00558 if (doh->doh_answers < 1)
00559 break;
00560 else {
00561 for (n = 1; n <= (int) doh->doh_answers; n++) {
00562 dor = CreateDnsResource(dor);
00563 len += DecodeDnsResource(dor, pkt + len);
00564 #ifdef NUTDEBUG
00565
00566 #endif
00567 if (dor->dor_type == 1)
00568 break;
00569 }
00570 if (dor->dor_len == 4) {
00571 ip = *dor->dor_data;
00572 ip += (uint32_t)(*(dor->dor_data + 1)) << 8;
00573 ip += (uint32_t)(*(dor->dor_data + 2)) << 16;
00574 ip += (uint32_t)(*(dor->dor_data + 3)) << 24;
00575 break;
00576 }
00577
00578 }
00579 }
00580 }
00581
00582
00583
00584
00585 ReleaseDnsHeader(doh);
00586 ReleaseDnsQuestion(doq);
00587 ReleaseDnsResource(dor);
00588
00589 free(pkt);
00590 NutUdpDestroySocket(sock);
00591
00592 return ip;
00593 }
00594