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