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