00001
00002
00003
00004
00005 static const char version[] = "2.7";
00006
00007
00008 #define sethostent _sethostent
00009 #define gethostent _gethostent
00010 #define endhostent _endhostent
00011
00012 #define nil ((void*)0)
00013 #include <sys/types.h>
00014 #include <stdio.h>
00015 #include <syslog.h>
00016 #include <stddef.h>
00017 #include <stdlib.h>
00018 #include <unistd.h>
00019 #include <fcntl.h>
00020 #include <errno.h>
00021 #include <string.h>
00022 #include <time.h>
00023 #include <limits.h>
00024 #include <signal.h>
00025 #include <assert.h>
00026 #include <sys/stat.h>
00027 #include <sys/ioctl.h>
00028 #include <sys/asynchio.h>
00029 #include <net/hton.h>
00030 #include <net/netlib.h>
00031 #include <net/gen/in.h>
00032 #include <net/gen/inet.h>
00033 #include <net/gen/nameser.h>
00034 #include <net/gen/resolv.h>
00035 #include <net/gen/netdb.h>
00036 #include <net/gen/socket.h>
00037 #include <net/gen/tcp.h>
00038 #include <net/gen/tcp_io.h>
00039 #include <net/gen/udp.h>
00040 #include <net/gen/udp_hdr.h>
00041 #include <net/gen/udp_io.h>
00042 #include <net/gen/dhcp.h>
00043
00044 #include <minix/paths.h>
00045
00046 #define HTTL 3600L
00047 #define SHORT_TIMEOUT 2
00048 #define MEDIUM_TIMEOUT 4
00049 #define LONG_TIMEOUT 300
00050 #define N_IDS 256
00051 #define N_DATAMAX (4096*sizeof(char *))
00052 #define N_NAMEDS 8
00053 #define NO_FD (-1)
00054 #define T_NXD ((u16_t) -1)
00055
00056
00057 #define DO_TCP (__minix_vmd || !__minix)
00058
00059
00060 static char HOSTS[]= _PATH_HOSTS;
00061 static char PIDFILE[]= "/usr/run/nonamed.pid";
00062 static char NNCACHE[]= "/usr/adm/nonamed.cache";
00063 static char DHCPCACHE[]= _PATH_DHCPCACHE;
00064
00065
00066 static char MAGIC[4]= "NND\2";
00067
00068 #define arraysize(a) (sizeof(a) / sizeof((a)[0]))
00069 #define arraylimit(a) ((a) + arraysize(a))
00070 #define between(a, c, z) ((unsigned) ((c) - (a)) <= (unsigned) ((z) - (a)))
00071
00072
00073 #define IMMEDIATE ((time_t) 0)
00074 #define NEVER ((time_t) ((time_t) -1 < 0 ? LONG_MAX : ULONG_MAX))
00075
00076 static unsigned debug;
00077 static time_t now;
00078 static u32_t stale;
00079 static u32_t httl;
00080 static int reinit, done;
00081 static int single;
00082 static int localonly;
00083 #define LOCALHOST 0x7F000001
00084
00085 static void report(const char *label)
00086 {
00087 fprintf(stderr, "nonamed: %s: %s\n", label, strerror(errno));
00088 }
00089
00090 static void fatal(const char *label)
00091 {
00092 report(label);
00093 if (debug >= 3) { fflush(nil); abort(); }
00094 exit(1);
00095 }
00096
00097 static void *allocate(void *mem, size_t size)
00098 {
00099 if ((mem= realloc(mem, size)) == nil) fatal("malloc()");
00100 return mem;
00101 }
00102
00103 static void deallocate(void *mem)
00104 {
00105 free(mem);
00106 }
00107
00108 static char *timegmt(time_t t)
00109
00110 {
00111 unsigned h, m, s;
00112 static char asctime[sizeof("00:00:00")];
00113
00114 s= t % 60;
00115 t /= 60;
00116 m= t % 60;
00117 t /= 60;
00118 h= t % 24;
00119 sprintf(asctime, "%02u:%02u:%02u", h, m, s);
00120 return asctime;
00121 }
00122
00123 static char *nowgmt(void)
00124 {
00125 return timegmt(now);
00126 }
00127
00128 #define PC(n) ((void) sizeof(char [sizeof(*(n)) == 1]), (char *) (n))
00129 #define namecpy(n1, n2) strcpy(PC(n1), PC(n2))
00130 #define namecat(n1, n2) strcat(PC(n1), PC(n2))
00131 #define namechr(n, c) ((u8_t *) strchr(PC(n), (c)))
00132 #define namecmp(n1, n2) strcasecmp(PC(n1), PC(n2))
00133 #define namencmp(n1, n2, len) strncasecmp(PC(n1), PC(n2), len)
00134
00135 typedef struct dns {
00136 dns_hdr_t hdr;
00137 u8_t data[PACKETSZ - sizeof(dns_hdr_t)];
00138 } dns_t;
00139
00140
00141 #define dns2oct(dp) ((u8_t *) (dp))
00142 #define oct2dns(dp) ((dns_t *) (dp))
00143
00144 typedef struct query {
00145 struct query *less;
00146 struct query *more;
00147 time_t age;
00148 time_t stale;
00149 u16_t usage;
00150 u8_t flags;
00151 size_t size;
00152 dns_t dns;
00153 } query_t;
00154
00155 #define QF_REFRESH 0x01
00156 #define QU_SHIFT 1
00157
00158
00159 #define query_allocsize(dnssize) (offsetof(query_t, dns) + (dnssize))
00160 #define query_size(qp) query_allocsize((qp)->size)
00161
00162 static query_t *mru, *lru;
00163 static int q_refresh;
00164
00165 static void pack16(u8_t *buf, u16_t s)
00166
00167 {
00168 buf[0]= ((u8_t *) &s)[0];
00169 buf[1]= ((u8_t *) &s)[1];
00170 }
00171
00172 static void pack32(u8_t *buf, u32_t l)
00173
00174 {
00175 buf[0]= ((u8_t *) &l)[0];
00176 buf[1]= ((u8_t *) &l)[1];
00177 buf[2]= ((u8_t *) &l)[2];
00178 buf[3]= ((u8_t *) &l)[3];
00179 }
00180
00181 static u16_t upack16(u8_t *buf)
00182
00183 {
00184 u16_t s;
00185
00186 ((u8_t *) &s)[0]= buf[0];
00187 ((u8_t *) &s)[1]= buf[1];
00188 return s;
00189 }
00190
00191 static u32_t upack32(u8_t *buf)
00192
00193 {
00194 u32_t l;
00195
00196 ((u8_t *) &l)[0]= buf[0];
00197 ((u8_t *) &l)[1]= buf[1];
00198 ((u8_t *) &l)[2]= buf[2];
00199 ((u8_t *) &l)[3]= buf[3];
00200 return l;
00201 }
00202
00203
00204 static char *encoding[] = {
00205 "c*",
00206 "i",
00207 "d",
00208 "d",
00209 "d",
00210 "d",
00211 "ddlllll",
00212 "d",
00213 "d",
00214 "d",
00215 "c*",
00216 "icc*",
00217 "d",
00218 "ss",
00219 "dd",
00220 "hd",
00221 "s*",
00222 };
00223
00224 static char *itoa(char *fmt, u32_t i)
00225 {
00226 static char output[32 + 3 * sizeof(i)];
00227
00228 sprintf(output, fmt, (unsigned long) i);
00229 return output;
00230 }
00231
00232 static char *classname(unsigned class)
00233
00234 {
00235 static char *classes[] = { "IN", "CS", "CHAOS", "HS" };
00236
00237 if ((class - C_IN) < arraysize(classes)) return classes[class - C_IN];
00238 return itoa("C_%u", class);
00239 }
00240
00241 static char *typename(unsigned type)
00242
00243 {
00244 static char type_A[][6] = {
00245 "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", "NULL",
00246 "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT",
00247 };
00248 static char type_AXFR[][6] = {
00249 "AXFR", "MAILB", "MAILA", "ANY",
00250 };
00251 if ((type - T_A) < arraysize(type_A)) return type_A[type - T_A];
00252 if ((type - T_AXFR) < arraysize(type_AXFR)) return type_AXFR[type - T_AXFR];
00253 return itoa("T_%u", type);
00254 }
00255
00256 static int print_qrr(dns_t *dp, size_t size, u8_t *cp0, int q)
00257
00258
00259
00260 {
00261 u8_t name[MAXDNAME+1];
00262 u8_t *cp;
00263 char *ep;
00264 u8_t *dlim, *rlim;
00265 u16_t type, class, rdlength;
00266 u32_t ttl;
00267 int r;
00268
00269 cp= cp0;
00270 dlim= dns2oct(dp) + size;
00271 r= dn_expand(dns2oct(dp), dlim, cp, name, MAXDNAME);
00272 if (r == -1) return -1;
00273 cp += r;
00274 if (cp + 2 * sizeof(u16_t) > dlim) return -1;
00275 type= ntohs(upack16(cp));
00276 cp += sizeof(u16_t);
00277 class= ntohs(upack16(cp));
00278 cp += sizeof(u16_t);
00279 printf("%-25s", (char *) name);
00280 if (q) {
00281
00282 printf(" %8s", classname(class));
00283 printf(" %-5s", typename(type));
00284 return cp - cp0;
00285 }
00286 if (cp + sizeof(u32_t) + sizeof(u16_t) > dlim) return -1;
00287 ttl= ntohl(upack32(cp));
00288 cp += sizeof(u32_t);
00289 rdlength= ntohs(upack16(cp));
00290 cp += sizeof(u16_t);
00291 if (cp + rdlength > dlim) return -1;
00292 rlim = cp + rdlength;
00293 printf(" %5lu", (unsigned long) ttl);
00294 printf(" %s", classname(class));
00295 printf(" %-5s", typename(type));
00296 ep= type < arraysize(encoding) ? encoding[type] : encoding[0];
00297 while (*ep != 0) {
00298 switch (*ep++) {
00299 case 'i':
00300 if (cp + sizeof(u32_t) > rlim) return -1;
00301 printf(" %s", inet_ntoa(upack32(cp)));
00302 cp += sizeof(u32_t);
00303 break;
00304 case 'l':
00305 if (cp + sizeof(u32_t) > rlim) return -1;
00306 printf(" %ld", (long)(i32_t) ntohl(upack32(cp)));
00307 cp += sizeof(u32_t);
00308 break;
00309 case 'd':
00310 r= dn_expand(dns2oct(dp), dlim, cp, name, MAXDNAME);
00311 if (r == -1) return -1;
00312 printf(" %s", (char *) name);
00313 cp += r;
00314 break;
00315 case 'c':
00316 if (cp >= rlim) return -1;
00317 printf(" %02X", *cp++);
00318 break;
00319 case 's':
00320 r= *cp + 1;
00321 if (cp + r > rlim) return -1;
00322 printf(" \"%.*s\"", *cp, (char *) (cp + 1));
00323 cp += r;
00324 break;
00325 case 'h':
00326 if (cp + sizeof(u16_t) > rlim) return -1;
00327 printf(" %u", ntohs(upack16(cp)));
00328 cp += sizeof(u16_t);
00329 break;
00330 }
00331 if (*ep == '*') ep= cp < rlim ? ep-1 : ep+1;
00332 }
00333 return cp - cp0;
00334 }
00335
00336 static void dns_tell(int indent, dns_t *dp, size_t size)
00337
00338 {
00339 u8_t *cp;
00340 int r, i;
00341 unsigned count[4];
00342 static char label[4][4]= { "QD:", "AN:", "NS:", "AR:" };
00343 static char rcodes[][9] = {
00344 "NOERROR", "FORMERR", "SERVFAIL", "NXDOMAIN", "NOTIMP", "REFUSED"
00345 };
00346
00347 if (size < sizeof(dns_hdr_t)) return;
00348
00349 printf("%*s", indent, "");
00350 printf("DNS %s:", (dp->hdr.dh_flag1 & DHF_QR) ? "reply" : "query");
00351 r= dp->hdr.dh_flag2 & DHF_RCODE;
00352 printf(" %s", r < arraysize(rcodes) ? rcodes[r] : itoa("ERR_%lu", r));
00353 if (dp->hdr.dh_flag1 & DHF_AA) printf(" AA");
00354 if (dp->hdr.dh_flag1 & DHF_TC) printf(" TC");
00355 if (dp->hdr.dh_flag1 & DHF_RD) printf(" RD");
00356 if (dp->hdr.dh_flag2 & DHF_RA) printf(" RA");
00357 #ifdef DHF_AD
00358 if (dp->hdr.dh_flag2 & DHF_AD) printf(" AD");
00359 if (dp->hdr.dh_flag2 & DHF_CD) printf(" CD");
00360 #endif
00361 fputc('\n', stdout);
00362
00363 count[0]= ntohs(dp->hdr.dh_qdcount);
00364 count[1]= ntohs(dp->hdr.dh_ancount);
00365 count[2]= ntohs(dp->hdr.dh_nscount);
00366 count[3]= ntohs(dp->hdr.dh_arcount);
00367 cp = dp->data;
00368 for (i= 0; i < 4; i++) {
00369 while (count[i] > 0) {
00370 printf("%*s", indent, "");
00371 printf(" %s ", label[i]);
00372 r= print_qrr(dp, size, cp, (i == 0));
00373 fputc('\n', stdout);
00374 if (r == -1) return;
00375 cp += r;
00376 count[i]--;
00377 }
00378 }
00379 }
00380
00381 static u32_t dns_ttl(dns_t *dp, size_t size, u32_t delta)
00382
00383
00384
00385
00386 {
00387 u8_t *cp, *rdp, *dlim;
00388 int r, i, hasttl, hassoa;
00389 unsigned type, count[4];
00390 u32_t ttl, minimum, minttl;
00391 unsigned rcode;
00392 u8_t name[MAXDNAME+1];
00393
00394 hasttl= hassoa= 0;
00395 minttl= 365*24*3600L;
00396 dlim= dns2oct(dp) + size;
00397 if (size < sizeof(dns_hdr_t)) return 0;
00398
00399 rcode= dp->hdr.dh_flag2 & DHF_RCODE;
00400 count[0]= ntohs(dp->hdr.dh_qdcount);
00401 count[1]= ntohs(dp->hdr.dh_ancount);
00402 count[2]= ntohs(dp->hdr.dh_nscount);
00403 count[3]= ntohs(dp->hdr.dh_arcount);
00404 cp = dp->data;
00405 for (i= 0; i < 4 && cp < dlim; i++) {
00406 while (count[i] > 0) {
00407 r= dn_expand(dns2oct(dp), dlim, cp, name, MAXDNAME);
00408 if (r == -1) break;
00409 cp += r + 2 * sizeof(u16_t);
00410 if (i != 0) {
00411 if (cp + sizeof(u32_t) + sizeof(u16_t) > dlim) break;
00412 type= upack16(cp - 2 * sizeof(u16_t));
00413 ttl= ntohl(upack32(cp));
00414 ttl= ttl < delta ? 0 : ttl - delta;
00415 if (rcode == NXDOMAIN && i == 2 && type == HTONS(T_SOA)) {
00416 rdp= cp + sizeof(u32_t) + sizeof(u16_t);
00417 r= dn_expand(dns2oct(dp), dlim, rdp, name, MAXDNAME);
00418 if (r == -1) break;
00419 rdp += r;
00420 r= dn_expand(dns2oct(dp), dlim, rdp, name, MAXDNAME);
00421 if (r == -1) break;
00422 rdp += r + 4 * sizeof(u32_t);
00423 if (rdp + sizeof(u32_t) > dlim) break;
00424 minimum= ntohl(upack32(rdp));
00425 if (ttl > minimum) ttl= minimum;
00426 hassoa= 1;
00427 }
00428 if (delta != 0) pack32(cp, htonl(ttl));
00429 if (ttl < minttl) minttl= ttl;
00430 hasttl= 1;
00431 cp += sizeof(u32_t);
00432 cp += sizeof(u16_t) + ntohs(upack16(cp));
00433 }
00434 count[i]--;
00435 }
00436 }
00437 return ((rcode == NOERROR && hasttl) || (rcode == NXDOMAIN && hassoa))
00438 ? minttl : 0;
00439 }
00440
00441
00442 static size_t n_datamax= N_DATAMAX;
00443 static size_t n_data;
00444
00445 static query_t *extract_query(query_t *qp)
00446
00447 {
00448 assert(qp != nil);
00449 *(qp->less != nil ? &qp->less->more : &lru) = qp->more;
00450 *(qp->more != nil ? &qp->more->less : &mru) = qp->less;
00451 n_data -= query_size(qp);
00452 return qp;
00453 }
00454
00455 static query_t *get_query(u8_t *name, unsigned type)
00456
00457 {
00458 query_t *qp, *less;
00459 u8_t qname[MAXDNAME+1];
00460 int r;
00461
00462 for (qp= mru; qp != nil; qp= less) {
00463 less= qp->less;
00464 if (qp->stale <= now - stale) {
00465
00466 deallocate(extract_query(qp));
00467 } else {
00468 r= dn_expand(dns2oct(&qp->dns), dns2oct(&qp->dns) + qp->size,
00469 qp->dns.data, qname, MAXDNAME);
00470 if (r == -1) continue;
00471 if (namecmp(qname, name) == 0 && upack16(qp->dns.data+r) == type) {
00472
00473 return extract_query(qp);
00474 }
00475 }
00476 }
00477 return nil;
00478 }
00479
00480 static void insert_query(query_t *qp)
00481
00482 {
00483 *(qp->less != nil ? &qp->less->more : &lru) = qp;
00484 *(qp->more != nil ? &qp->more->less : &mru) = qp;
00485 n_data += query_size(qp);
00486
00487
00488
00489
00490 while (n_data > n_datamax && lru != nil) {
00491 if ((lru->usage >>= QU_SHIFT) == 0 || lru->stale <= now - stale) {
00492 deallocate(extract_query(lru));
00493 } else {
00494 lru->less= mru;
00495 mru->more= lru;
00496 mru= lru;
00497 lru= lru->more;
00498 lru->less= nil;
00499 mru->more= nil;
00500 }
00501 }
00502
00503 if (debug >= 2) {
00504 unsigned n= 0;
00505 for (qp= mru; qp != nil; qp= qp->less) n++;
00506 printf("%u cached repl%s, %u bytes, sbrk(0) = %u\n",
00507 n, n == 1 ? "y" : "ies",
00508 (unsigned) n_data,
00509 (unsigned) sbrk(0));
00510 }
00511 }
00512
00513 static void put_query(query_t *qp)
00514
00515 {
00516 qp->less= mru;
00517 qp->more= nil;
00518 insert_query(qp);
00519 }
00520
00521 static void cache2file(void)
00522
00523 {
00524 FILE *fp;
00525 query_t *qp;
00526 u8_t data[4+1+2+2];
00527 u16_t usage;
00528 char newcache[sizeof(NNCACHE) + sizeof(".new")];
00529
00530 if (single) return;
00531
00532 strcpy(newcache, NNCACHE);
00533 strcat(newcache, ".new");
00534
00535 if ((fp= fopen(newcache, "w")) == nil) {
00536 if ((errno != ENOENT && errno != EROFS) || debug >= 2) report(newcache);
00537 return;
00538 }
00539 if (debug >= 2) printf("Writing %s:\n", newcache);
00540
00541
00542 fwrite(MAGIC, 1, sizeof(MAGIC), fp);
00543
00544 for (qp= lru; qp != nil; qp= qp->more) {
00545 if (qp->stale <= now - stale) continue;
00546 if (debug >= 2) {
00547 printf("Usage = %u, Age = %ld, Flags = %02X:\n",
00548 qp->usage, (long) (now - qp->age), qp->flags);
00549 dns_tell(2, &qp->dns, qp->size);
00550 }
00551 pack32(data+0, htonl(qp->age));
00552 data[4]= qp->flags;
00553 pack16(data+5, htons(qp->size));
00554 pack16(data+7, htons(qp->usage));
00555 fwrite(data, 1, sizeof(data), fp);
00556 fwrite(&qp->dns, 1, qp->size, fp);
00557 if (ferror(fp)) break;
00558 }
00559
00560 if (ferror(fp) || fclose(fp) == EOF) {
00561 report(newcache);
00562 (void) unlink(newcache);
00563 return;
00564 }
00565
00566 if (debug >= 2) printf("mv %s %s\n", newcache, NNCACHE);
00567 if (rename(newcache, NNCACHE) < 0) {
00568 fprintf(stderr, "nonamed: mv %s %s: %s\n",
00569 newcache, NNCACHE, strerror(errno));
00570 (void) unlink(newcache);
00571 }
00572 }
00573
00574 static void file2cache(void)
00575
00576 {
00577 query_t *qp;
00578 FILE *fp;
00579 u8_t data[4+1+2+2];
00580 size_t dlen;
00581
00582 if (single) return;
00583
00584 if ((fp= fopen(NNCACHE, "r")) == nil) {
00585 if (errno != ENOENT || debug >= 2) report(NNCACHE);
00586 return;
00587 }
00588 if (debug >= 2) printf("Reading %s:\n", NNCACHE);
00589
00590
00591 fread(data, 1, sizeof(MAGIC), fp);
00592 if (ferror(fp) || memcmp(MAGIC, data, sizeof(MAGIC)) != 0) goto err;
00593
00594 for (;;) {
00595 fread(data, 1, sizeof(data), fp);
00596 if (feof(fp) || ferror(fp)) break;
00597 dlen= ntohs(upack16(data+5));
00598 qp= allocate(nil, query_allocsize(dlen));
00599 qp->age= htonl(upack32(data+0));
00600 qp->flags= data[4];
00601 if (qp->flags & QF_REFRESH) q_refresh= 1;
00602 qp->size= dlen;
00603 qp->usage= htons(upack16(data+7));
00604 fread(&qp->dns, 1, qp->size, fp);
00605 if (feof(fp) || ferror(fp)) {
00606 deallocate(qp);
00607 goto err;
00608 }
00609 qp->stale= qp->age + dns_ttl(&qp->dns, dlen, 0);
00610 if (debug >= 2) {
00611 printf("Usage = %u, Age = %ld, Flags = %02X:\n",
00612 qp->usage, (long) (now - qp->age), qp->flags);
00613 dns_tell(2, &qp->dns, dlen);
00614 }
00615 put_query(qp);
00616 }
00617 if (ferror(fp)) {
00618 err:
00619
00620 fprintf(stderr, "nonamed: %s: %s\n", NNCACHE,
00621 ferror(fp) ? strerror(errno) : "Corrupt");
00622 while (lru != nil) deallocate(extract_query(lru));
00623 }
00624 fclose(fp);
00625 }
00626
00627 typedef int handler_t(void *data, int expired);
00628
00629
00630 typedef struct job {
00631 struct job *next, **prev;
00632 handler_t *handler;
00633 time_t timeout;
00634 void *data;
00635 } job_t;
00636
00637 static job_t *queue;
00638
00639 static void newjob(handler_t *handler, time_t timeout, void *data)
00640
00641 {
00642 job_t *job, **prev;
00643
00644 job= allocate(nil, sizeof(*job));
00645 job->handler= handler;
00646 job->timeout= timeout;
00647 job->data= data;
00648
00649 for (prev= &queue; *prev != nil; prev= &(*prev)->next) {
00650 if (job->timeout < (*prev)->timeout) break;
00651 }
00652 job->next= *prev;
00653 job->prev= prev;
00654 *prev= job;
00655 if (job->next != nil) job->next->prev= &job->next;
00656 }
00657
00658 static int execjob(job_t *job, int expired)
00659
00660
00661
00662
00663 {
00664 if ((*job->handler)(job->data, expired)) {
00665 *job->prev= job->next;
00666 if (job->next != nil) job->next->prev= job->prev;
00667 deallocate(job);
00668 return 1;
00669 }
00670 return 0;
00671 }
00672
00673 static void force_expire(handler_t *handler)
00674
00675 {
00676 job_t *job, **prev= &queue;
00677
00678 while ((job= *prev) != nil) {
00679 if (job->handler == handler && job->timeout != IMMEDIATE) {
00680 *prev= job->next;
00681 if (job->next != nil) job->next->prev= prev;
00682 newjob(job->handler, IMMEDIATE, job->data);
00683 deallocate(job);
00684 } else {
00685 prev= &job->next;
00686 }
00687 }
00688 }
00689
00690 static int nxdomain(u8_t *name)
00691
00692
00693
00694
00695
00696 {
00697 u8_t *end, *top, *p;
00698 size_t n;
00699
00700 end= namechr(name, 0);
00701 top= end;
00702 while (top > name && *--top != '.') {}
00703 while (top > name && *--top != '.') {}
00704 n= end - top;
00705 p= top;
00706 for (;;) {
00707 if (p == name) return 0;
00708 if (*--p == '.') {
00709 if (namencmp(p, top, n) == 0 && p[n] == '.') return 1;
00710 if (namencmp(p, ".in-addr.arpa.", 14) == 0) return 1;
00711 }
00712 }
00713 }
00714
00715 typedef struct id2id {
00716 u16_t id;
00717 u16_t port;
00718 ipaddr_t ip;
00719 } id2id_t;
00720
00721 static id2id_t id2id[N_IDS];
00722 static u16_t id_counter;
00723
00724 static u16_t new_id(u16_t in_id, u16_t in_port, ipaddr_t in_ip)
00725
00726
00727
00728 {
00729 id2id_t *idp;
00730 u16_t id;
00731
00732 id= id_counter++;
00733 idp= &id2id[id % N_IDS];
00734 idp->id= in_id;
00735 idp->port= in_port;
00736 idp->ip= in_ip;
00737 return htons(id);
00738 }
00739
00740 static int old_id(u16_t id, u16_t *out_id, u16_t *out_port, ipaddr_t *out_ip)
00741
00742
00743
00744 {
00745 id= ntohs(id);
00746 if ((u16_t) (id_counter - id) > N_IDS) {
00747
00748 return 0;
00749 } else {
00750
00751 id2id_t *idp= &id2id[id % N_IDS];
00752
00753 if (idp->port == 0) return 0;
00754 *out_id= idp->id;
00755 *out_port= idp->port;
00756 *out_ip= idp->ip;
00757 idp->port= 0;
00758 return 1;
00759 }
00760 }
00761
00762
00763
00764
00765 #define ID_IPSELF HTONL(0)
00766 #define ID_PROBE HTONS(0)
00767 #define ID_REFRESH HTONS(1)
00768
00769 static char *tcp_device, *udp_device;
00770 static int udp_fd;
00771 static asynchio_t asyn;
00772 static ipaddr_t my_ip;
00773 static u16_t my_port, named_port;
00774
00775 static ipaddr_t named[N_NAMEDS];
00776 static unsigned n_nameds;
00777 static unsigned i_named;
00778 static int expect;
00779 static int search_ct= -1;
00780 static int dirty;
00781
00782 #define current_named() (+named[i_named])
00783 #define searching() (search_ct > 0)
00784 #define start_searching() ((void) (search_ct= -1))
00785 #define stop_searching() ((void) (search_ct= 0))
00786 #define expecting() (+expect)
00787 #define start_expecting() ((void) (expect= 1))
00788 #define stop_expecting() ((void) (expect= 0))
00789
00790 static time_t filetime(const char *file)
00791
00792 {
00793 struct stat st;
00794
00795 return stat(file, &st) == 0 ? st.st_mtime : 0;
00796 }
00797
00798 static void init_config(ipaddr_t ifip)
00799
00800 {
00801 struct hostent *he;
00802 u32_t nip, hip;
00803 static time_t hosts_time, dhcp_time;
00804 time_t ht, dt;
00805
00806
00807 if (((ifip ^ HTONL(LOCALHOST)) & HTONL(0xFF000000)) == 0) ifip= my_ip;
00808 ht= filetime(HOSTS);
00809 dt= filetime(DHCPCACHE);
00810 if (ifip == my_ip && ht == hosts_time && dt == dhcp_time) return;
00811 my_ip= ifip;
00812 hosts_time= ht;
00813 dhcp_time= dt;
00814
00815 if (debug >= 2) {
00816 printf("%s: I am nonamed %s at %s:%u\n",
00817 nowgmt(), version, inet_ntoa(my_ip), ntohs(my_port));
00818 }
00819
00820 httl= HTONL(HTTL);
00821 stale= 0;
00822 n_nameds= 0;
00823
00824 if (!single) {
00825 sethostent(0);
00826 while ((he= gethostent()) != nil) {
00827 memcpy(&nip, he->h_addr, sizeof(u32_t));
00828 hip= ntohl(nip);
00829 if (namecmp(he->h_name, "%ttl") == 0) httl= nip;
00830 if (namecmp(he->h_name, "%stale") == 0) stale= hip;
00831 if (namecmp(he->h_name, "%memory") == 0) n_datamax= hip;
00832 if (namecmp(he->h_name, "%nameserver") == 0) {
00833 if (nip != my_ip || named_port != my_port) {
00834 if (n_nameds < N_NAMEDS) named[n_nameds++]= nip;
00835 }
00836 }
00837 }
00838 endhostent();
00839 }
00840
00841 if (n_nameds == 0) {
00842
00843 int fd;
00844 dhcp_t d;
00845 ssize_t r;
00846 u8_t *data;
00847 size_t len;
00848
00849 if ((fd= open(DHCPCACHE, O_RDONLY)) < 0) {
00850 if (errno != ENOENT) fatal(DHCPCACHE);
00851 } else {
00852 while ((r= read(fd, &d, sizeof(d))) == sizeof(d)) {
00853 if (d.yiaddr == my_ip) break;
00854 }
00855 if (r < 0) fatal(DHCPCACHE);
00856 close(fd);
00857
00858 if (r == sizeof(d) && dhcp_gettag(&d, DHCP_TAG_DNS, &data, &len)) {
00859 while (len >= sizeof(nip)) {
00860 memcpy(&nip, data, sizeof(nip));
00861 data += sizeof(nip);
00862 len -= sizeof(nip);
00863 if (nip != my_ip || named_port != my_port) {
00864 if (n_nameds < N_NAMEDS) named[n_nameds++]= nip;
00865 }
00866 }
00867 }
00868 }
00869 }
00870 i_named= 0;
00871 }
00872
00873 static handler_t job_save_cache, job_read_udp, job_find_named, job_expect_named;
00874 #if DO_TCP
00875 static handler_t job_setup_listen, job_listen, job_setup_connect, job_connect;
00876 static handler_t job_read_query, job_write_query;
00877 static handler_t job_read_reply, job_write_reply;
00878 #endif
00879
00880 static int query_hosts(u8_t *qname, unsigned type, dns_t *dp, size_t *pdlen)
00881
00882
00883
00884 {
00885 struct hostent *he;
00886 int i, r;
00887 dns_t dns;
00888 u8_t *domain;
00889 u8_t *cp;
00890 u8_t name[MAXDNAME+1];
00891 u8_t *dnvec[40];
00892 unsigned ancount;
00893 struct hostent localhost;
00894 static char *noaliases[]= { nil };
00895 static ipaddr_t localaddr= HTONL(LOCALHOST);
00896 static char *localaddrlist[]= { (char *) &localaddr, nil };
00897
00898 if (single) return 0;
00899
00900
00901 dns.hdr.dh_flag1= DHF_QR | DHF_AA;
00902 dns.hdr.dh_flag2= DHF_RA;
00903 dns.hdr.dh_qdcount= HTONS(1);
00904 ancount= 0;
00905 dns.hdr.dh_nscount= HTONS(0);
00906 dns.hdr.dh_arcount= HTONS(0);
00907
00908 dnvec[0]= dns2oct(&dns);
00909 dnvec[1]= nil;
00910 cp= dns.data;
00911 r= dn_comp(qname, cp, arraysize(dns.data), dnvec, arraylimit(dnvec));
00912 if (r == -1) return 0;
00913 cp += r;
00914 pack16(cp, type);
00915 cp += sizeof(u16_t);
00916 pack16(cp, HTONS(C_IN));
00917 cp += sizeof(u16_t);
00918
00919
00920 localhost.h_name=
00921 namencmp(qname, "localhost.", 10) == 0 ? (char *) qname : "localhost";
00922 localhost.h_aliases= noaliases;
00923 localhost.h_addr_list= localaddrlist;
00924 he= &localhost;
00925
00926 sethostent(0);
00927 do {
00928 switch (type) {
00929 case HTONS(T_A):
00930 if (namecmp(qname, he->h_name) == 0) {
00931 addA:
00932 r= dn_comp((u8_t *) he->h_name, cp, arraylimit(dns.data) - cp,
00933 dnvec, arraylimit(dnvec));
00934 if (r == -1) return 0;
00935 cp += r;
00936 if (cp + 3 * sizeof(u16_t) + 2 * sizeof(u32_t)
00937 > arraylimit(dns.data)) { r= -1; break; }
00938 pack16(cp, HTONS(T_A));
00939 cp += sizeof(u16_t);
00940 pack16(cp, HTONS(C_IN));
00941 cp += sizeof(u16_t);
00942 pack32(cp, httl);
00943 cp += sizeof(u32_t);
00944 pack16(cp, HTONS(sizeof(u32_t)));
00945 cp += sizeof(u16_t);
00946 memcpy(cp, he->h_addr, sizeof(u32_t));
00947 cp += sizeof(u32_t);
00948 ancount++;
00949 break;
00950 }
00951
00952 case HTONS(T_CNAME):
00953 domain= namechr(he->h_name, '.');
00954 for (i= 0; he->h_aliases[i] != nil; i++) {
00955 namecpy(name, he->h_aliases[i]);
00956 if (domain != nil && namechr(name, '.') == nil) {
00957 namecat(name, domain);
00958 }
00959 if (namecmp(qname, name) == 0) {
00960 r= dn_comp(name, cp, arraylimit(dns.data) - cp,
00961 dnvec, arraylimit(dnvec));
00962 if (r == -1) break;
00963 cp += r;
00964 if (cp + 3 * sizeof(u16_t)
00965 + 1 * sizeof(u32_t) > arraylimit(dns.data)) return 0;
00966 pack16(cp, HTONS(T_CNAME));
00967 cp += sizeof(u16_t);
00968 pack16(cp, HTONS(C_IN));
00969 cp += sizeof(u16_t);
00970 pack32(cp, httl);
00971 cp += sizeof(u32_t);
00972
00973 cp += sizeof(u16_t);
00974 r= dn_comp((u8_t *) he->h_name, cp,
00975 arraylimit(dns.data) - cp,
00976 dnvec, arraylimit(dnvec));
00977 if (r == -1) break;
00978 pack16(cp - sizeof(u16_t), htons(r));
00979 cp += r;
00980 ancount++;
00981 if (type == HTONS(T_A)) goto addA;
00982 break;
00983 }
00984 }
00985 break;
00986 case HTONS(T_PTR):
00987 if (ancount > 0) break;
00988 if (he->h_name[0] == '%') break;
00989 sprintf((char *) name, "%d.%d.%d.%d.in-addr.arpa",
00990 ((u8_t *) he->h_addr)[3],
00991 ((u8_t *) he->h_addr)[2],
00992 ((u8_t *) he->h_addr)[1],
00993 ((u8_t *) he->h_addr)[0]);
00994 if (namecmp(qname, name) == 0) {
00995 r= dn_comp(name, cp, arraylimit(dns.data) - cp,
00996 dnvec, arraylimit(dnvec));
00997 if (r == -1) break;
00998 cp += r;
00999 if (cp + 3 * sizeof(u16_t) + 1 * sizeof(u32_t)
01000 > arraylimit(dns.data)) { r= -1; break; }
01001 pack16(cp, HTONS(T_PTR));
01002 cp += sizeof(u16_t);
01003 pack16(cp, HTONS(C_IN));
01004 cp += sizeof(u16_t);
01005 pack32(cp, httl);
01006 cp += sizeof(u32_t);
01007
01008 cp += sizeof(u16_t);
01009 r= dn_comp((u8_t *) he->h_name, cp,
01010 arraylimit(dns.data) - cp, dnvec, arraylimit(dnvec));
01011 if (r == -1) return 0;
01012 pack16(cp - sizeof(u16_t), htons(r));
01013 cp += r;
01014 ancount++;
01015 }
01016 break;
01017 }
01018 } while (r != -1 && (he= gethostent()) != nil);
01019 endhostent();
01020
01021 if (r == -1 || ancount == 0) return 0;
01022
01023 dns.hdr.dh_ancount= htons(ancount);
01024 memcpy(dp, &dns, *pdlen= cp - dns2oct(&dns));
01025 return 1;
01026 }
01027
01028 static int query_chaos(u8_t *qname, unsigned type, dns_t *dp, size_t *pdlen)
01029
01030 {
01031 int i, n, r;
01032 dns_t dns;
01033 u8_t *cp;
01034 u8_t *dnvec[40];
01035
01036 if (type != HTONS(T_TXT) || namecmp(qname, "version.bind") != 0) return 0;
01037
01038 dns.hdr.dh_flag1= DHF_QR | DHF_AA;
01039 dns.hdr.dh_flag2= DHF_RA;
01040 dns.hdr.dh_qdcount= HTONS(1);
01041 dns.hdr.dh_ancount= HTONS(1);
01042 dns.hdr.dh_nscount= HTONS(0);
01043 dns.hdr.dh_arcount= htons(n_nameds);
01044
01045 dnvec[0]= dns2oct(&dns);
01046 dnvec[1]= nil;
01047 cp= dns.data;
01048 r= dn_comp(qname, cp, arraysize(dns.data), dnvec, arraylimit(dnvec));
01049 if (r == -1) return 0;
01050 cp += r;
01051 pack16(cp, type);
01052 cp += sizeof(u16_t);
01053 pack16(cp, HTONS(C_CHAOS));
01054 cp += sizeof(u16_t);
01055
01056 r= dn_comp(qname, cp, arraylimit(dns.data) - cp, dnvec, arraylimit(dnvec));
01057 if (r == -1) return 0;
01058 cp += r;
01059 pack16(cp, HTONS(T_TXT));
01060 cp += sizeof(u16_t);
01061 pack16(cp, HTONS(C_CHAOS));
01062 cp += sizeof(u16_t);
01063 pack32(cp, HTONL(0));
01064 cp += sizeof(u32_t);
01065
01066 cp += sizeof(u16_t);
01067 sprintf((char *) cp + 1, "nonamed %s at %s:%u",
01068 version, inet_ntoa(my_ip), ntohs(my_port));
01069 r= strlen((char *) cp + 1) + 1;
01070 pack16(cp - sizeof(u16_t), htons(r));
01071 *cp= r-1;
01072 cp += r;
01073 for (n= 0, i= i_named; n < n_nameds; n++, i= (i+1) % n_nameds) {
01074 r= dn_comp((u8_t *) "%nameserver", cp, arraylimit(dns.data) - cp,
01075 dnvec, arraylimit(dnvec));
01076 if (r == -1) return 0;
01077 cp += r;
01078 if (cp + 3 * sizeof(u16_t)
01079 + 2 * sizeof(u32_t) > arraylimit(dns.data)) return 0;
01080 pack16(cp, HTONS(T_A));
01081 cp += sizeof(u16_t);
01082 pack16(cp, HTONS(C_IN));
01083 cp += sizeof(u16_t);
01084 pack32(cp, HTONL(0));
01085 cp += sizeof(u32_t);
01086 pack16(cp, HTONS(sizeof(u32_t)));
01087 cp += sizeof(u16_t);
01088 memcpy(cp, &named[i], sizeof(u32_t));
01089 cp += sizeof(u32_t);
01090 }
01091
01092 memcpy(dp, &dns, *pdlen= cp - dns2oct(&dns));
01093 return 1;
01094 }
01095
01096 static void cache_reply(dns_t *dp, size_t dlen)
01097
01098 {
01099 int r;
01100 query_t *qp, *less, *more;
01101 unsigned usage;
01102 u16_t type;
01103 u8_t *cp;
01104 u8_t name[MAXDNAME];
01105 u32_t minttl;
01106
01107 if ((dp->hdr.dh_flag1 & (DHF_RD | DHF_TC)) != DHF_RD) return;
01108 if (dp->hdr.dh_qdcount != HTONS(1)) return;
01109 cp= dp->data;
01110 r= dn_expand(dns2oct(dp), dns2oct(dp) + dlen, cp, name, MAXDNAME);
01111 if (r == -1) return;
01112 cp += r;
01113 type= upack16(cp);
01114 cp += sizeof(u16_t);
01115 if (upack16(cp) != HTONS(C_IN)) return;
01116
01117
01118 if ((qp= get_query(name, type)) != nil) {
01119 less= qp->less;
01120 more= qp->more;
01121 usage= qp->usage;
01122 deallocate(qp);
01123 } else {
01124
01125 less= mru;
01126 more= nil;
01127 usage= 1;
01128 }
01129
01130
01131 if ((minttl= dns_ttl(dp, dlen, 0)) == 0) return;
01132
01133
01134 qp= allocate(nil, query_allocsize(dlen));
01135 qp->less= less;
01136 qp->more= more;
01137 qp->age= now;
01138 qp->flags= 0;
01139 qp->usage= usage;
01140 qp->size= dlen;
01141 memcpy(&qp->dns, dp, dlen);
01142 qp->stale= qp->age + minttl;
01143 insert_query(qp);
01144 if (debug >= 1) printf("Answer cached\n");
01145
01146
01147 if (!dirty) {
01148 dirty= 1;
01149 newjob(job_save_cache, now + LONG_TIMEOUT, nil);
01150 }
01151 }
01152
01153 static int job_save_cache(void *data, int expired)
01154
01155 {
01156 if (!expired) return 0;
01157 cache2file();
01158 dirty= 0;
01159 }
01160
01161 static int compose_reply(dns_t *dp, size_t *pdlen)
01162
01163
01164
01165
01166 {
01167 size_t dlen= *pdlen;
01168 int r, rd;
01169 query_t *qp;
01170 unsigned id, type, class;
01171 u8_t *cp;
01172 u8_t name[MAXDNAME];
01173
01174 cp= dp->data;
01175 r= dn_expand(dns2oct(dp), dns2oct(dp) + dlen, cp, name, MAXDNAME);
01176 if (r != -1) {
01177 cp += r;
01178 if (cp + 2 * sizeof(u16_t) > dns2oct(dp) + dlen) {
01179 r= -1;
01180 } else {
01181 type= upack16(cp);
01182 cp += sizeof(u16_t);
01183 class= upack16(cp);
01184 cp += sizeof(u16_t);
01185 }
01186 }
01187
01188
01189 id= dp->hdr.dh_id;
01190 rd= dp->hdr.dh_flag1 & DHF_RD;
01191
01192 if (r == -1) {
01193
01194 dp->hdr.dh_flag1 &= ~(DHF_TC);
01195 dp->hdr.dh_flag1 |= DHF_QR | DHF_AA;
01196 dp->hdr.dh_flag2 &= ~(DHF_UNUSED | DHF_RCODE);
01197 dp->hdr.dh_flag2 |= DHF_RA | FORMERR;
01198 } else
01199 if (class == HTONS(C_IN) && query_hosts(name, type, dp, pdlen)) {
01200
01201 dlen= *pdlen;
01202 } else
01203 if (class == HTONS(C_IN) && (qp= get_query(name, type)) != nil) {
01204
01205 memcpy(dp, &qp->dns, dlen= qp->size);
01206 dp->hdr.dh_flag1 &= ~DHF_AA;
01207 (void) dns_ttl(dp, dlen, now - qp->age);
01208 if (rd) {
01209 if (qp->stale <= now) {
01210 qp->flags |= QF_REFRESH;
01211 q_refresh= 1;
01212 }
01213 qp->usage++;
01214 }
01215 put_query(qp);
01216 } else
01217 if (class == HTONS(C_CHAOS) && query_chaos(name, type, dp, pdlen)) {
01218
01219 dlen= *pdlen;
01220 } else
01221 if (n_nameds == 0 || nxdomain(name)) {
01222
01223
01224
01225 dp->hdr.dh_flag1 &= ~(DHF_TC);
01226 dp->hdr.dh_flag1 |= DHF_QR | DHF_AA;
01227 dp->hdr.dh_flag2 &= ~(DHF_UNUSED | DHF_RCODE);
01228 dp->hdr.dh_flag2 |= DHF_RA | NXDOMAIN;
01229 } else
01230 if (!rd) {
01231
01232 dp->hdr.dh_flag1 &= ~(DHF_TC);
01233 dp->hdr.dh_flag1 |= DHF_QR;
01234 dp->hdr.dh_flag2 &= ~(DHF_UNUSED | DHF_RCODE);
01235 dp->hdr.dh_flag2 |= DHF_RA | NOERROR;
01236 } else {
01237
01238 return 0;
01239 }
01240
01241
01242 dp->hdr.dh_id= id;
01243 dp->hdr.dh_flag1 &= ~DHF_RD;
01244 dp->hdr.dh_flag1 |= rd;
01245 *pdlen= dlen;
01246 return 1;
01247 }
01248
01249 typedef struct udp_dns {
01250 udp_io_hdr_t hdr;
01251 dns_t dns;
01252 } udp_dns_t;
01253
01254 static void refresh_cache(void)
01255
01256
01257
01258 {
01259 query_t *qp;
01260 unsigned type;
01261 int r;
01262 u8_t *cp;
01263 size_t dlen, ulen;
01264 u8_t qname[MAXDNAME+1];
01265 u8_t *dnvec[40];
01266 udp_dns_t udp;
01267
01268 if (!q_refresh) return;
01269 for (qp= lru; qp != nil; qp= qp->more) {
01270 if ((qp->flags & QF_REFRESH) && qp->stale > now - stale) break;
01271 }
01272 if (qp == nil) {
01273 q_refresh= 0;
01274 return;
01275 }
01276
01277
01278 qp->flags &= ~QF_REFRESH;
01279 r= dn_expand(dns2oct(&qp->dns), dns2oct(&qp->dns) + qp->size,
01280 qp->dns.data, qname, MAXDNAME);
01281 if (r == -1) return;
01282 type= upack16(qp->dns.data+r);
01283
01284 dnvec[0]= dns2oct(&udp.dns);
01285 dnvec[1]= nil;
01286 cp= udp.dns.data;
01287 r= dn_comp(qname, cp, arraysize(udp.dns.data), dnvec, arraylimit(dnvec));
01288 if (r == -1) return;
01289 cp += r;
01290 pack16(cp, type);
01291 cp += sizeof(u16_t);
01292 pack16(cp, HTONS(C_IN));
01293 cp += sizeof(u16_t);
01294 dlen= cp - dns2oct(&udp.dns);
01295
01296 udp.dns.hdr.dh_id= new_id(ID_REFRESH, my_port, ID_IPSELF);
01297 udp.dns.hdr.dh_flag1= DHF_RD;
01298 udp.dns.hdr.dh_flag2= 0;
01299 udp.dns.hdr.dh_qdcount= HTONS(1);
01300 udp.dns.hdr.dh_ancount= HTONS(0);
01301 udp.dns.hdr.dh_nscount= HTONS(0);
01302 udp.dns.hdr.dh_arcount= HTONS(0);
01303
01304 udp.hdr.uih_dst_addr= current_named();
01305 udp.hdr.uih_dst_port= named_port;
01306 udp.hdr.uih_ip_opt_len= 0;
01307 udp.hdr.uih_data_len= dlen;
01308
01309 if (debug >= 1) {
01310 printf("Refresh to %s:%u:\n",
01311 inet_ntoa(current_named()), ntohs(named_port));
01312 dns_tell(0, &udp.dns, dlen);
01313 }
01314 ulen= offsetof(udp_dns_t, dns) + dlen;
01315 if (write(udp_fd, &udp, ulen) < 0) fatal(udp_device);
01316 }
01317
01318 static int job_read_udp(void *data, int expired)
01319
01320 {
01321 size_t ulen, dlen;
01322 static udp_dns_t udp;
01323 u16_t id, port;
01324 ipaddr_t ip;
01325 time_t dtime;
01326
01327 assert(!expired);
01328
01329
01330 ulen= asyn_read(&asyn, udp_fd, &udp, sizeof(udp));
01331 dlen= ulen - offsetof(udp_dns_t, dns);
01332
01333 if (ulen == -1) {
01334 if (errno == EINPROGRESS && !expired) return 0;
01335 if (errno == EIO) fatal(udp_device);
01336
01337 if (debug >= 2) {
01338 printf("%s: UDP read: %s\n", nowgmt(), strerror(errno));
01339 }
01340 } else {
01341 if (debug >= 2) {
01342 printf("%s: UDP read, %d bytes\n", nowgmt(), (int) ulen);
01343 }
01344 }
01345
01346
01347 newjob(job_read_udp, NEVER, nil);
01348
01349 if (ulen < (ssize_t) (sizeof(udp_io_hdr_t) + sizeof(dns_hdr_t))) return 1;
01350
01351 if (debug >= 1) {
01352 printf("%s:%u UDP ", inet_ntoa(udp.hdr.uih_src_addr),
01353 ntohs(udp.hdr.uih_src_port));
01354 dns_tell(0, &udp.dns, dlen);
01355 }
01356
01357
01358 init_config(udp.hdr.uih_dst_addr);
01359
01360 if (udp.dns.hdr.dh_flag1 & DHF_QR) {
01361
01362
01363
01364 if (!old_id(udp.dns.hdr.dh_id, &id, &port, &ip)) return 1;
01365
01366 if (ip == ID_IPSELF && id == ID_PROBE) {
01367 if (searching()) {
01368
01369 int i;
01370
01371
01372 for (i= 0; i < n_nameds; i++) {
01373 if (named[i] == udp.hdr.uih_src_addr) {
01374 i_named= i;
01375 if (debug >= 1) {
01376 printf("Current named = %s\n",
01377 inet_ntoa(current_named()));
01378 }
01379 stop_searching();
01380 force_expire(job_find_named);
01381 }
01382 }
01383 }
01384 }
01385
01386
01387 if (expecting()) {
01388 stop_expecting();
01389 force_expire(job_expect_named);
01390 }
01391
01392
01393 cache_reply(&udp.dns, dlen);
01394
01395
01396 refresh_cache();
01397
01398
01399 if (ip == ID_IPSELF) return 1;
01400
01401
01402 udp.dns.hdr.dh_id= id;
01403 udp.hdr.uih_dst_addr= ip;
01404 udp.hdr.uih_dst_port= port;
01405 if (debug >= 1) printf("To client %s:%u\n", inet_ntoa(ip), ntohs(port));
01406 } else {
01407
01408 if (udp.dns.hdr.dh_qdcount != HTONS(1)) return 1;
01409
01410 if(localonly) {
01411
01412 if(ntohl(udp.hdr.uih_src_addr) != LOCALHOST) {
01413 syslog(LOG_WARNING, "nonamed: dropped query from %s",
01414 inet_ntoa(udp.hdr.uih_src_addr));
01415 return 1;
01416 }
01417 }
01418
01419
01420 if (compose_reply(&udp.dns, &dlen)) {
01421 udp.hdr.uih_dst_addr= udp.hdr.uih_src_addr;
01422 udp.hdr.uih_dst_port= udp.hdr.uih_src_port;
01423 udp.hdr.uih_ip_opt_len= 0;
01424 udp.hdr.uih_data_len= dlen;
01425 ulen= offsetof(udp_dns_t, dns) + dlen;
01426
01427
01428 if (debug >= 1) {
01429 printf("%s:%u UDP ", inet_ntoa(udp.hdr.uih_dst_addr),
01430 ntohs(udp.hdr.uih_dst_port));
01431 dns_tell(0, &udp.dns, dlen);
01432 }
01433 } else {
01434
01435 udp.dns.hdr.dh_id= new_id(udp.dns.hdr.dh_id,
01436 udp.hdr.uih_src_port, udp.hdr.uih_src_addr);
01437 udp.hdr.uih_dst_addr= current_named();
01438 udp.hdr.uih_dst_port= named_port;
01439 if (!expecting()) {
01440 start_expecting();
01441 newjob(job_expect_named, now + MEDIUM_TIMEOUT, nil);
01442 }
01443 if (debug >= 1) {
01444 printf("To named %s:%u\n",
01445 inet_ntoa(current_named()), ntohs(named_port));
01446 }
01447 }
01448 }
01449 if (write(udp_fd, &udp, ulen) < 0) fatal(udp_device);
01450 return 1;
01451 }
01452
01453 #if DO_TCP
01454
01455 typedef struct data_cl {
01456 int fd;
01457 int dn_fd;
01458 int retry;
01459 nwio_tcpcl_t tcpcl;
01460 } data_cl_t;
01461
01462 typedef struct data_rw {
01463 int r_fd;
01464 int w_fd;
01465 struct data_rw *rev;
01466 u8_t *buf;
01467 ssize_t offset;
01468 size_t size;
01469 } data_rw_t;
01470
01471 static int job_setup_listen(void *data, int expired)
01472
01473 {
01474 data_cl_t *data_cl= data;
01475 nwio_tcpconf_t tcpconf;
01476 nwio_tcpopt_t tcpopt;
01477 int fd;
01478
01479 if (!expired) return 0;
01480 if (debug >= 2) printf("%s: Setup listen\n", nowgmt());
01481
01482 if (data_cl == nil) {
01483 if ((fd= open(tcp_device, O_RDWR)) < 0) {
01484 if (errno != EMFILE) report(tcp_device);
01485 newjob(job_setup_listen, now + SHORT_TIMEOUT, nil);
01486 return 1;
01487 }
01488
01489 tcpconf.nwtc_flags= NWTC_SHARED | NWTC_LP_SET | NWTC_UNSET_RA
01490 | NWTC_UNSET_RP;
01491 tcpconf.nwtc_locport= my_port;
01492 if (ioctl(fd, NWIOSTCPCONF, &tcpconf) == -1) fatal(tcp_device);
01493
01494 tcpopt.nwto_flags= NWTO_DEL_RST;
01495 if (ioctl(fd, NWIOSTCPOPT, &tcpopt) == -1) fatal(tcp_device);
01496
01497 data_cl= allocate(nil, sizeof(*data_cl));
01498 data_cl->fd= fd;
01499 data_cl->tcpcl.nwtcl_flags= 0;
01500 }
01501
01502 newjob(job_listen, NEVER, data_cl);
01503 return 1;
01504 }
01505
01506 static int job_listen(void *data, int expired)
01507
01508 {
01509 data_cl_t *data_cl= data;
01510
01511
01512 if (asyn_ioctl(&asyn, data_cl->fd, NWIOTCPLISTEN, &data_cl->tcpcl) < 0) {
01513 if (errno == EINPROGRESS) return 0;
01514 report(tcp_device);
01515
01516
01517 newjob(job_setup_listen, now + SHORT_TIMEOUT, data_cl);
01518 return 1;
01519 }
01520 if (debug >= 2) printf("%s: Listen\n", nowgmt());
01521
01522
01523 newjob(job_setup_listen, IMMEDIATE, nil);
01524
01525
01526 data_cl->retry= 0;
01527 newjob(job_setup_connect, IMMEDIATE, data_cl);
01528 return 1;
01529 }
01530
01531 static void start_relay(int fd, int dn_fd)
01532
01533 {
01534 data_rw_t *query;
01535 data_rw_t *reply;
01536
01537 query= allocate(nil, sizeof(*query));
01538 query->r_fd= fd;
01539 query->buf= allocate(nil, sizeof(u16_t));
01540 query->offset= 0;
01541 query->size= sizeof(u16_t);
01542 if (dn_fd == NO_FD) {
01543
01544 query->w_fd= fd;
01545 query->rev= nil;
01546 } else {
01547
01548 reply= allocate(nil, sizeof(*reply));
01549 reply->r_fd= dn_fd;
01550 reply->w_fd= fd;
01551 reply->buf= allocate(nil, sizeof(u16_t));
01552 reply->offset= 0;
01553 reply->size= sizeof(u16_t);
01554 reply->rev= query;
01555 query->w_fd= dn_fd;
01556 query->rev= reply;
01557 newjob(job_read_reply, now + LONG_TIMEOUT, reply);
01558 }
01559 newjob(job_read_query, now + LONG_TIMEOUT, query);
01560 }
01561
01562 static void close_relay(data_rw_t *data_rw)
01563
01564 {
01565 if (data_rw->rev != nil) {
01566
01567 (void) ioctl(data_rw->w_fd, NWIOTCPSHUTDOWN, nil);
01568 data_rw->rev->rev= nil;
01569 } else {
01570
01571 asyn_close(&asyn, data_rw->r_fd);
01572 close(data_rw->r_fd);
01573 if (data_rw->w_fd != data_rw->r_fd) {
01574 asyn_close(&asyn, data_rw->w_fd);
01575 close(data_rw->w_fd);
01576 }
01577 }
01578 deallocate(data_rw->buf);
01579 deallocate(data_rw);
01580 }
01581
01582 static int job_setup_connect(void *data, int expired)
01583
01584 {
01585 nwio_tcpconf_t tcpconf;
01586 int dn_fd;
01587 data_cl_t *data_cl= data;
01588
01589 if (!expired) return 0;
01590 if (debug >= 2) printf("%s: Setup connect\n", nowgmt());
01591
01592 if (n_nameds == 0) {
01593
01594 start_relay(data_cl->fd, NO_FD);
01595 deallocate(data_cl);
01596 return 1;
01597 }
01598
01599 if ((dn_fd= open(tcp_device, O_RDWR)) < 0) {
01600 if (errno != EMFILE) report(tcp_device);
01601 if (++data_cl->retry < 5) {
01602
01603 newjob(job_setup_connect, now + SHORT_TIMEOUT, data_cl);
01604 } else {
01605
01606 start_relay(data_cl->fd, NO_FD);
01607 deallocate(data_cl);
01608 }
01609 return 1;
01610 }
01611
01612 tcpconf.nwtc_flags= NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
01613 tcpconf.nwtc_remaddr= current_named();
01614 tcpconf.nwtc_remport= named_port;
01615 if (ioctl(dn_fd, NWIOSTCPCONF, &tcpconf) == -1) fatal(tcp_device);
01616
01617
01618 data_cl->dn_fd= dn_fd;
01619 data_cl->tcpcl.nwtcl_flags= 0;
01620 newjob(job_connect, NEVER, data_cl);
01621 return 1;
01622 }
01623
01624 static int job_connect(void *data, int expired)
01625
01626 {
01627 data_cl_t *data_cl= data;
01628
01629
01630 if (asyn_ioctl(&asyn, data_cl->dn_fd, NWIOTCPCONN, &data_cl->tcpcl) < 0) {
01631 if (errno == EINPROGRESS) return 0;
01632 if (errno == EIO) fatal(tcp_device);
01633
01634
01635 if (debug >= 2) printf("%s: Connect: %s\n", nowgmt(), strerror(errno));
01636 asyn_close(&asyn, data_cl->dn_fd);
01637 close(data_cl->dn_fd);
01638 data_cl->dn_fd= NO_FD;
01639 if (++data_cl->retry < 5) {
01640
01641 if (!searching()) {
01642 start_searching();
01643 force_expire(job_find_named);
01644 }
01645 newjob(job_setup_connect, NEVER, data_cl);
01646 return 1;
01647 }
01648
01649 }
01650 if (debug >= 2) printf("%s: Connect\n", nowgmt());
01651
01652
01653 start_relay(data_cl->fd, data_cl->dn_fd);
01654 deallocate(data_cl);
01655 return 1;
01656 }
01657
01658 static void tcp_dns_tell(int fd, u8_t *buf)
01659
01660 {
01661 nwio_tcpconf_t tcpconf;
01662
01663 if (ioctl(fd, NWIOGTCPCONF, &tcpconf) < 0) {
01664 printf("??\?:?? TCP ");
01665 } else {
01666 printf("%s:%u TCP ", inet_ntoa(tcpconf.nwtc_remaddr),
01667 ntohs(tcpconf.nwtc_remport));
01668 }
01669 dns_tell(0, oct2dns(buf + sizeof(u16_t)), ntohs(upack16(buf)));
01670 }
01671
01672 static int job_read_query(void *data, int expired)
01673
01674 {
01675 data_rw_t *data_rw= data;
01676 ssize_t count;
01677
01678
01679 count= asyn_read(&asyn, data_rw->r_fd,
01680 data_rw->buf + data_rw->offset,
01681 data_rw->size - data_rw->offset);
01682
01683 if (count < 0) {
01684 if (errno == EINPROGRESS && !expired) return 0;
01685 if (errno == EIO) fatal(tcp_device);
01686
01687
01688 if (debug >= 2) {
01689 printf("%s: TCP read query: %s\n", nowgmt(), strerror(errno));
01690 }
01691 close_relay(data_rw);
01692 return 1;
01693 }
01694
01695 if (debug >= 2) {
01696 printf("%s: TCP read query, %d/%u bytes\n",
01697 nowgmt(), data_rw->offset + count, data_rw->size);
01698 }
01699 if (count == 0) {
01700
01701 close_relay(data_rw);
01702 return 1;
01703 }
01704 data_rw->offset += count;
01705 if (data_rw->offset == data_rw->size) {
01706 data_rw->size= sizeof(u16_t) + ntohs(upack16(data_rw->buf));
01707 if (data_rw->size < sizeof(u16_t)) {
01708
01709 close_relay(data_rw);
01710 return 1;
01711 }
01712 if (data_rw->offset < data_rw->size) {
01713
01714 data_rw->buf= allocate(data_rw->buf, data_rw->size);
01715 newjob(job_read_query, now + LONG_TIMEOUT, data_rw);
01716 return 1;
01717 }
01718 }
01719
01720 if (data_rw->size < sizeof(u16_t) + sizeof(dns_hdr_t)) {
01721 close_relay(data_rw);
01722 return 1;
01723 }
01724 if (debug >= 1) tcp_dns_tell(data_rw->r_fd, data_rw->buf);
01725
01726
01727 if (data_rw->w_fd != data_rw->r_fd) {
01728
01729 data_rw->offset= 0;
01730 newjob(job_write_query, now + LONG_TIMEOUT, data_rw);
01731 } else {
01732
01733 dns_t *dp;
01734 size_t dlen;
01735
01736 if (data_rw->size < sizeof(u16_t) + PACKETSZ) {
01737 data_rw->buf= allocate(data_rw->buf, sizeof(u16_t) + PACKETSZ);
01738 }
01739
01740
01741 dp= oct2dns(data_rw->buf + sizeof(u16_t));
01742 dlen= data_rw->size - sizeof(u16_t);
01743 if (!compose_reply(dp, &dlen)) {
01744
01745 close_relay(data_rw);
01746 return 1;
01747 }
01748
01749
01750 pack16(data_rw->buf, htons(dlen));
01751 data_rw->size= sizeof(u16_t) + dlen;
01752 data_rw->buf= allocate(data_rw->buf, data_rw->size);
01753 data_rw->offset= 0;
01754 newjob(job_write_reply, now + LONG_TIMEOUT, data_rw);
01755 }
01756 return 1;
01757 }
01758
01759 static int job_write_query(void *data, int expired)
01760
01761 {
01762 data_rw_t *data_rw= data;
01763 ssize_t count;
01764
01765
01766 count= asyn_write(&asyn, data_rw->w_fd,
01767 data_rw->buf + data_rw->offset,
01768 data_rw->size - data_rw->offset);
01769
01770 if (count <= 0) {
01771 if (errno == EINPROGRESS && !expired) return 0;
01772 if (errno == EIO) fatal(tcp_device);
01773
01774
01775 if (debug >= 2) {
01776 printf("%s: TCP write query: %s\n", nowgmt(), strerror(errno));
01777 }
01778 close_relay(data_rw);
01779 return 1;
01780 }
01781
01782 if (debug >= 2) {
01783 printf("%s: TCP write query, %d/%u bytes\n",
01784 nowgmt(), data_rw->offset + count, data_rw->size);
01785 }
01786 data_rw->offset += count;
01787 if (data_rw->offset < data_rw->size) {
01788
01789 newjob(job_write_query, now + LONG_TIMEOUT, data_rw);
01790 return 1;
01791 }
01792 if (debug >= 1) tcp_dns_tell(data_rw->w_fd, data_rw->buf);
01793
01794
01795 data_rw->offset= 0;
01796 data_rw->size= sizeof(u16_t);
01797 newjob(job_read_query, now + LONG_TIMEOUT, data_rw);
01798 return 1;
01799 }
01800
01801 static int job_read_reply(void *data, int expired)
01802
01803 {
01804 data_rw_t *data_rw= data;
01805 ssize_t count;
01806
01807
01808 count= asyn_read(&asyn, data_rw->r_fd,
01809 data_rw->buf + data_rw->offset,
01810 data_rw->size - data_rw->offset);
01811
01812 if (count < 0) {
01813 if (errno == EINPROGRESS && !expired) return 0;
01814 if (errno == EIO) fatal(tcp_device);
01815
01816
01817 if (debug >= 2) {
01818 printf("%s: TCP read reply: %s\n", nowgmt(), strerror(errno));
01819 }
01820 close_relay(data_rw);
01821 return 1;
01822 }
01823
01824 if (debug >= 2) {
01825 printf("%s: TCP read reply, %d/%u bytes\n",
01826 nowgmt(), data_rw->offset + count, data_rw->size);
01827 }
01828 if (count == 0) {
01829
01830 close_relay(data_rw);
01831 return 1;
01832 }
01833 data_rw->offset += count;
01834 if (data_rw->offset == data_rw->size) {
01835 data_rw->size= sizeof(u16_t) + ntohs(upack16(data_rw->buf));
01836 if (data_rw->size < sizeof(u16_t)) {
01837
01838 close_relay(data_rw);
01839 return 1;
01840 }
01841 if (data_rw->offset < data_rw->size) {
01842
01843 data_rw->buf= allocate(data_rw->buf, data_rw->size);
01844 newjob(job_read_reply, now + LONG_TIMEOUT, data_rw);
01845 return 1;
01846 }
01847 }
01848 if (debug >= 1) tcp_dns_tell(data_rw->r_fd, data_rw->buf);
01849
01850
01851 data_rw->offset= 0;
01852 newjob(job_write_reply, now + LONG_TIMEOUT, data_rw);
01853 return 1;
01854 }
01855
01856 static int job_write_reply(void *data, int expired)
01857
01858 {
01859 data_rw_t *data_rw= data;
01860 ssize_t count;
01861
01862
01863 count= asyn_write(&asyn, data_rw->w_fd,
01864 data_rw->buf + data_rw->offset,
01865 data_rw->size - data_rw->offset);
01866
01867 if (count <= 0) {
01868 if (errno == EINPROGRESS && !expired) return 0;
01869 if (errno == EIO) fatal(tcp_device);
01870
01871
01872 if (debug >= 2) {
01873 printf("%s: TCP write reply: %s\n", nowgmt(), strerror(errno));
01874 }
01875 close_relay(data_rw);
01876 return 1;
01877 }
01878
01879 if (debug >= 2) {
01880 printf("%s: TCP write reply, %d/%u bytes\n",
01881 nowgmt(), data_rw->offset + count, data_rw->size);
01882 }
01883 data_rw->offset += count;
01884 if (data_rw->offset < data_rw->size) {
01885
01886 newjob(job_write_reply, now + LONG_TIMEOUT, data_rw);
01887 return 1;
01888 }
01889 if (debug >= 1) tcp_dns_tell(data_rw->w_fd, data_rw->buf);
01890
01891
01892 data_rw->offset= 0;
01893 data_rw->size= sizeof(u16_t);
01894 newjob(data_rw->w_fd != data_rw->r_fd ? job_read_reply : job_read_query,
01895 now + LONG_TIMEOUT, data_rw);
01896 return 1;
01897 }
01898 #else
01899
01900 static int job_dummy(void *data, int expired)
01901 {
01902 return 1;
01903 }
01904 #define job_setup_listen job_dummy
01905 #define job_setup_connect job_dummy
01906 #endif
01907
01908 static void named_probe(ipaddr_t ip)
01909
01910 {
01911 udp_dns_t udp;
01912 # define dlen (offsetof(dns_t, data) + 5)
01913 # define ulen (offsetof(udp_dns_t, dns) + dlen)
01914
01915
01916
01917
01918 udp.dns.hdr.dh_id= new_id(ID_PROBE, my_port, ID_IPSELF);
01919 udp.dns.hdr.dh_flag1= 0;
01920 udp.dns.hdr.dh_flag2= 0;
01921 udp.dns.hdr.dh_qdcount= HTONS(1);
01922 udp.dns.hdr.dh_ancount= HTONS(0);
01923 udp.dns.hdr.dh_nscount= HTONS(0);
01924 udp.dns.hdr.dh_arcount= HTONS(0);
01925
01926 udp.dns.data[0] = 0;
01927 pack16(udp.dns.data+1, HTONS(T_NS));
01928 pack16(udp.dns.data+3, HTONS(C_IN));
01929 if (debug >= 1) {
01930 printf("PROBE %s ", inet_ntoa(ip));
01931 dns_tell(0, &udp.dns, dlen);
01932 }
01933
01934 udp.hdr.uih_dst_addr= ip;
01935 udp.hdr.uih_dst_port= named_port;
01936 udp.hdr.uih_ip_opt_len= 0;
01937 udp.hdr.uih_data_len= dlen;
01938
01939 if (write(udp_fd, &udp, ulen) < 0) fatal(udp_device);
01940 #undef dlen
01941 #undef ulen
01942 }
01943
01944 static int job_find_named(void *data, int expired)
01945
01946 {
01947 if (!expired) return 0;
01948 if (debug >= 2) printf("%s: Find named\n", nowgmt());
01949
01950
01951 if (search_ct < 0) {
01952 search_ct= n_nameds;
01953 i_named= -1;
01954 }
01955
01956 if (--search_ct < 0) {
01957
01958
01959
01960 newjob(job_find_named,
01961 (stale > 0 || i_named > 0) ? now + LONG_TIMEOUT : NEVER, nil);
01962 force_expire(job_setup_connect);
01963 return 1;
01964 }
01965
01966
01967 i_named= (i_named+1) % n_nameds;
01968 named_probe(current_named());
01969
01970
01971 newjob(job_find_named, now + SHORT_TIMEOUT, nil);
01972 return 1;
01973 }
01974
01975 static int job_expect_named(void *data, int expired)
01976
01977 {
01978 if (!expired) return 0;
01979 if (debug >= 2) printf("%s: Expect named\n", nowgmt());
01980
01981 if (expecting() && !searching()) {
01982
01983 start_searching();
01984 force_expire(job_find_named);
01985 }
01986 return 1;
01987 }
01988
01989 static void sig_handler(int sig)
01990
01991 {
01992 switch (sig) {
01993 case SIGINT:
01994 case SIGTERM: done= 1; break;
01995 case SIGHUP: reinit= 1; break;
01996 case SIGUSR1: debug++; break;
01997 case SIGUSR2: debug= 0; break;
01998 }
01999 }
02000
02001 static void usage(void)
02002 {
02003 fprintf(stderr, "Usage: nonamed [-qs] [-d[level]] [-p port]\n");
02004 exit(1);
02005 }
02006
02007 int main(int argc, char **argv)
02008 {
02009 job_t *job;
02010 nwio_udpopt_t udpopt;
02011 int i;
02012 struct servent *servent;
02013 struct sigaction sa;
02014 FILE *fp;
02015 int quit= 0;
02016
02017
02018 setvbuf(stdout, nil, _IOLBF, 0);
02019
02020
02021 if ((servent= getservbyname("domain", nil)) == nil) {
02022 fprintf(stderr, "nonamed: \"domain\": unknown service\n");
02023 exit(1);
02024 }
02025 my_port= servent->s_port;
02026 named_port= servent->s_port;
02027
02028 i= 1;
02029 while (i < argc && argv[i][0] == '-') {
02030 char *opt= argv[i++] + 1, *end;
02031
02032 if (opt[0] == '-' && opt[1] == 0) break;
02033
02034 switch (*opt++) {
02035 case 'd':
02036 debug= 1;
02037 if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10);
02038 break;
02039 case 'p':
02040 if (*opt == 0) {
02041 if (i == argc) usage();
02042 opt= argv[i++];
02043 }
02044 my_port= htons(strtoul(opt, &end, 0));
02045 if (opt == end || *end != 0) usage();
02046 opt= end;
02047 break;
02048 case 's':
02049 single= 1;
02050 break;
02051 case 'q':
02052 quit= 1;
02053 break;
02054 case 'L':
02055 localonly= 1;
02056 break;
02057 default:
02058 usage();
02059 }
02060 }
02061 if (i != argc) usage();
02062
02063 if (quit) {
02064
02065 debug= 2;
02066 now= time(nil);
02067 n_datamax= -1;
02068 file2cache();
02069 return 0;
02070 }
02071
02072
02073 sa.sa_handler= SIG_IGN;
02074 sigemptyset(&sa.sa_mask);
02075 sa.sa_flags= 0;
02076 sigaction(SIGPIPE, &sa, nil);
02077 sa.sa_handler= sig_handler;
02078 sigaction(SIGINT, &sa, nil);
02079 sigaction(SIGHUP, &sa, nil);
02080 sigaction(SIGUSR1, &sa, nil);
02081 sigaction(SIGUSR2, &sa, nil);
02082 sigaction(SIGTERM, &sa, nil);
02083
02084
02085 if ((tcp_device= getenv("TCP_DEVICE")) == nil) tcp_device= TCP_DEVICE;
02086 if ((udp_device= getenv("UDP_DEVICE")) == nil) udp_device= UDP_DEVICE;
02087
02088
02089 if ((udp_fd= open(udp_device, O_RDWR)) < 0) fatal(udp_device);
02090
02091 udpopt.nwuo_flags= NWUO_EXCL | NWUO_LP_SET | NWUO_EN_LOC | NWUO_DI_BROAD
02092 | NWUO_RP_ANY | NWUO_RA_ANY | NWUO_RWDATALL | NWUO_DI_IPOPT;
02093 udpopt.nwuo_locport= my_port;
02094 if (ioctl(udp_fd, NWIOSUDPOPT, &udpopt) == -1
02095 || ioctl(udp_fd, NWIOGUDPOPT, &udpopt) == -1
02096 ) {
02097 fatal(udp_device);
02098 }
02099
02100
02101 now= time(nil);
02102
02103
02104 init_config(udpopt.nwuo_locaddr);
02105 file2cache();
02106
02107 if (!single) {
02108
02109 if ((fp= fopen(PIDFILE, "w")) != nil) {
02110 fprintf(fp, "%u\n", (unsigned) getpid());
02111 fclose(fp);
02112 }
02113 }
02114
02115
02116 newjob(job_read_udp, NEVER, nil);
02117 newjob(job_setup_listen, IMMEDIATE, nil);
02118 newjob(job_find_named, IMMEDIATE, nil);
02119
02120
02121 openlog("nonamed", LOG_PID, LOG_DAEMON);
02122
02123 while (!done) {
02124
02125 assert(queue != nil);
02126
02127
02128 while (queue->timeout <= now) {
02129 (void) execjob(queue, 1);
02130 assert(queue != nil);
02131 }
02132
02133
02134 for (job= queue; job != nil; job= job->next) {
02135 if (execjob(job, 0)) break;
02136 }
02137
02138 if (queue->timeout != IMMEDIATE) {
02139 struct timeval tv, *tvp;
02140
02141 if (debug >= 2) printf("%s: I/O wait", nowgmt());
02142
02143 if (queue->timeout != NEVER) {
02144 tv.tv_sec= queue->timeout;
02145 tv.tv_usec= 0;
02146 tvp= &tv;
02147 if (debug >= 2) printf(" (expires %s)\n", timegmt(tv.tv_sec));
02148 } else {
02149 tvp= nil;
02150 if (debug >= 2) fputc('\n', stdout);
02151 }
02152 fflush(stdout);
02153
02154 if (asyn_wait(&asyn, 0, tvp) < 0) {
02155 if (errno != EINTR && errno != EAGAIN) fatal("fwait()");
02156 }
02157 now= time(nil);
02158 }
02159
02160 if (reinit) {
02161
02162 reinit= 0;
02163 if (ioctl(udp_fd, NWIOGUDPOPT, &udpopt) == -1) fatal(udp_device);
02164 init_config(udpopt.nwuo_locaddr);
02165 start_searching();
02166 force_expire(job_find_named);
02167 }
02168 }
02169 cache2file();
02170 (void) unlink(PIDFILE);
02171 if (debug >= 2) printf("sbrk(0) = %u\n", (unsigned) sbrk(0));
02172 return 0;
02173 }