nonamed.c

Go to the documentation of this file.
00001 /*      nonamed - Not a name daemon, but plays one on TV.
00002  *                                                      Author: Kees J. Bot
00003  *                                                              29 Nov 1994
00004  */
00005 static const char version[] = "2.7";
00006 
00007 /* Use the file reading gethostent() family of functions. */
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   /* Default time to live for /etc/hosts data. */
00047 #define SHORT_TIMEOUT      2    /* If you expect an answer soon. */
00048 #define MEDIUM_TIMEOUT     4    /* Soon, but not that soon. */
00049 #define LONG_TIMEOUT     300    /* For stream connections to a real named. */
00050 #define N_IDS            256    /* Keep track of this many queries. */
00051 #define N_DATAMAX (4096*sizeof(char *)) /* Default response cache size. */
00052 #define N_NAMEDS           8    /* Max # name daemons we can keep track of. */
00053 #define NO_FD           (-1)    /* No name daemon channel here. */
00054 #define T_NXD   ((u16_t) -1)    /* A "type" signalling a nonexistent domain. */
00055 
00056 /* Can't do async I/O under standard Minix, so forget about TCP. */
00057 #define DO_TCP (__minix_vmd || !__minix)
00058 
00059 /* Host data, file to store our process id in, our cache, DHCP's cache. */
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 /* Magic string to head the cache file. */
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 /* The start of time and the far future. */
00073 #define IMMEDIATE       ((time_t) 0)
00074 #define NEVER           ((time_t) ((time_t) -1 < 0 ? LONG_MAX : ULONG_MAX))
00075 
00076 static unsigned debug;          /* Debug level. */
00077 static time_t now;              /* Current time. */
00078 static u32_t stale;             /* Extension time for stale data. */
00079 static u32_t httl;              /* TTL for /etc/hosts data. */
00080 static int reinit, done;        /* Reinit config / program is done. */
00081 static int single;              /* Run single on a nondefault interface. */
00082 static int localonly;           /* Only accept local queries. */
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 /* Simple "time in seconds to GMT time today" converter. */
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 {            /* A DNS packet. */
00136         dns_hdr_t       hdr;            /* DNS header. */
00137         u8_t            data[PACKETSZ - sizeof(dns_hdr_t)];     /* DNS data. */
00138 } dns_t;
00139 
00140 /* Addres of DNS packet to octet address, or vv. */
00141 #define dns2oct(dp)             ((u8_t *) (dp))
00142 #define oct2dns(dp)             ((dns_t *) (dp))
00143 
00144 typedef struct query {          /* One cached answer to a query. */
00145         struct query    *less;          /* Less recently used. */
00146         struct query    *more;          /* More recently used. */
00147         time_t          age;            /* Time it was added. */
00148         time_t          stale;          /* Time it goes stale by TTL. */
00149         u16_t           usage;          /* Counts of queries answered. */
00150         u8_t            flags;          /* QF_REFRESH. */
00151         size_t          size;           /* Size of DNS packet. */
00152         dns_t           dns;            /* Answer to query as a DNS packet. */
00153 } query_t;
00154 
00155 #define QF_REFRESH      0x01            /* This stale data must be refreshed. */
00156 #define QU_SHIFT        1               /* To shift usage by when evicting. */
00157 
00158 /* Size of new query_t or existing query_t. */
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;      /* Most and least recently used answers. */
00163 static int q_refresh;           /* Set when an entry needs refreshing. */
00164 
00165 static void pack16(u8_t *buf, u16_t s)
00166 /* Pack a 16 bit value into a byte array. */
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 /* Pack a 32 bit value into a byte array. */
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 /* Unpack a 16 bit value from a byte array. */
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 /* Unpack a 32 bit value from a byte array. */
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 /* Encoding of RRs: i(paddr), d(omain), l(ong), c(har), s(tring), (s)h(ort). */
00204 static char *encoding[] = {
00205         "c*",           /* anything unknown is c* */
00206         "i",            /* A */
00207         "d",            /* NS */
00208         "d",            /* MD */
00209         "d",            /* MF */
00210         "d",            /* CNAME */
00211         "ddlllll",      /* SOA */
00212         "d",            /* MB */
00213         "d",            /* MG */
00214         "d",            /* MR */
00215         "c*",           /* NULL */
00216         "icc*",         /* WKS */
00217         "d",            /* PTR */
00218         "ss",           /* HINFO */
00219         "dd",           /* MINFO */
00220         "hd",           /* MX */
00221         "s*",           /* TXT */
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 /* Class name of a resource record, for debug purposes. */
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 /* Type name of a resource record, for debug purposes. */
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 /* Print a query (q) or resource record (!q) from 'cp0' in a DNS packet for
00258  * debug purposes.  Return number of bytes skipped or -1 on error.
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         /* We're just printing a query segment, stop right here. */
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 /* Explain a DNS packet, for debug purposes. */
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 /* Compute the minimum TTL of all RRs in a DNS packet and subtract delta from
00383  * all TTLs.  (We are actually only interested in the minimum (delta = 0) or
00384  * the subtraction (delta > 0).  It was easier to roll this into one routine.)
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 /* Total cached query data. */
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 /* Take a query out of the query cache. */
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 /* Find a query and if so remove it from the cache and return it. */
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             /* This answer has expired. */
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                 /* Found an answer to the query. */
00473                 return extract_query(qp);
00474             }
00475         }
00476     }
00477     return nil;
00478 }
00479 
00480 static void insert_query(query_t *qp)
00481 /* (Re)insert a query into the cache. */
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     /* Try to delete the LRU while there is too much memory in use.  If
00488      * its usage count is too high then it gets a second chance.
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;     /* Make list circular. */
00495             mru->more= lru;
00496             mru= lru;           /* Move one over, making LRU the MRU. */
00497             lru= lru->more;
00498             lru->less= nil;     /* Break the circle. */
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 /* Add a new query to the cache as the MRU. */
00515 {
00516     qp->less= mru;
00517     qp->more= nil;
00518     insert_query(qp);
00519 }
00520 
00521 static void cache2file(void)
00522 /* Store the cached data into the cache file. */
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     /* Magic number: */
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 /* Read cached data from the cache file. */
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     /* Magic number? */
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         /* The cache file did not end at EOF or is otherwise a mess. */
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 /* All actions are in the form of "jobs". */
00630 typedef struct job {
00631         struct job      *next, **prev;  /* To make a job queue. */
00632         handler_t       *handler;       /* Function to handle this job. */
00633         time_t          timeout;        /* Moment it times out. */
00634         void            *data;          /* Data associated with the job. */
00635 } job_t;
00636 
00637 static job_t *queue;            /* Main job queue. */
00638 
00639 static void newjob(handler_t *handler, time_t timeout, void *data)
00640 /* Create a new job with the given handler, timeout time and data. */
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 /* Execute a job by calling the handler.  Remove the job if it returns true,
00660  * indicating that it is done.  Expired is set if the job timed out.  It is
00661  * otherwise called to check for I/O.
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 /* Force jobs to expire immediately, the named searcher for instance. */
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 /* True iff the two top level components in a name are repeated in the name,
00692  * or if in-addr.arpa is found within a name.  Such things happen often in a
00693  * search for an already fully qualified local name.  For instance:
00694  * flotsam.cs.vu.nl.cs.vu.nl.  (We don't want this at boot time.)
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;             /* ID of old query. */
00717         u16_t           port;           /* Reply port. */
00718         ipaddr_t        ip;             /* Reply address. */
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 /* An incoming UDP query must be relabeled with a new ID before it can be
00726  * send on to a real name daemon.
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 /* Translate a reply id back to the id, port, and address used in the query.
00742  * Return true if the translation is possible.
00743  */
00744 {
00745     id= ntohs(id);
00746     if ((u16_t) (id_counter - id) > N_IDS) {
00747         /* Too old. */
00748         return 0;
00749     } else {
00750         /* We know this one. */
00751         id2id_t *idp= &id2id[id % N_IDS];
00752 
00753         if (idp->port == 0) return 0;   /* Named is trying to fool us? */
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 /* IDs used to mark my own queries to name servers, must be new_id translated
00763  * to make them unique "on the wire".
00764  */
00765 #define ID_IPSELF       HTONL(0)        /* "I did it myself" address. */
00766 #define ID_PROBE        HTONS(0)        /* Name server probe. */
00767 #define ID_REFRESH      HTONS(1)        /* Query to refresh a cache entry. */
00768 
00769 static char *tcp_device, *udp_device;   /* TCP and UDP device names. */
00770 static int udp_fd;                      /* To send or receive UDP packets. */
00771 static asynchio_t asyn;                 /* For I/O in progress. */
00772 static ipaddr_t my_ip;                  /* My IP address. */
00773 static u16_t my_port, named_port;       /* Port numbers, normally "domain". */
00774 
00775 static ipaddr_t named[N_NAMEDS];        /* Addresses of all name servers. */
00776 static unsigned n_nameds;               /* Number of configured name daemons. */
00777 static unsigned i_named;                /* Index to current name server. */
00778 static int expect;                      /* Set when we expect an answer. */
00779 static int search_ct= -1;               /* Named search count and state. */
00780 static int dirty;                       /* True when new entry put in cache. */
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 /* Get the modified time of a file. */
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 /* Read name daemon list and other special stuff from the hosts file. */
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     /* See if anything really changed. */
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         /* No name daemons found in the host file.  What about DHCP? */
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 /* Read the /etc/hosts file to try and answer an A or PTR query.  Return
00882  * true iff an answer can be found, with the answer copied to *dp.
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     /* Assume we can answer. */
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     /* Localhost is fixed to 127.0.0.1. */
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             /*FALL THROUGH*/
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                     /* pack16(cp, htonl(RDLENGTH)) */
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;  /* really wants A */
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                 /* pack16(cp, htonl(RDLENGTH)) */
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 /* Report my version.  Can't let BIND take all the credit. :-) */
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     /* pack16(cp, htonl(RDLENGTH)) */
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 /* Store a DNS packet in the cache. */
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     /* Delete old cached data, if any.  Note where it is in the LRU. */
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         /* Not yet in the cache. */
01125         less= mru;
01126         more= nil;
01127         usage= 1;
01128     }
01129 
01130     /* Determine minimum TTL.  Discard if zero, never cache zero TTLs. */
01131     if ((minttl= dns_ttl(dp, dlen, 0)) == 0) return;
01132 
01133     /* Enter new reply in cache. */
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     /* Save the cache soon. */
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 /* Some time after the cache is changed it is written back to disk. */
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 /* Try to compose a reply to a request in *dp using the hosts file or
01163  * cached data.  Return answer in *dp with its size in *pdlen.  Return true
01164  * iff an answer is given.
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     /* Remember ID and RD. */
01189     id= dp->hdr.dh_id;
01190     rd= dp->hdr.dh_flag1 & DHF_RD;
01191 
01192     if (r == -1) {
01193         /* Malformed query, reply "FORMERR". */
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         /* Answer to this query is in the hosts file. */
01201         dlen= *pdlen;
01202     } else
01203     if (class == HTONS(C_IN) && (qp= get_query(name, type)) != nil) {
01204         /* Answer to this query is present in the cache. */
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         /* Return our version numbers. */
01219         dlen= *pdlen;
01220     } else
01221     if (n_nameds == 0 || nxdomain(name)) {
01222         /* No real name daemon present, or this name has a repeated top level
01223          * domain sequence.  Reply "no such domain".
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         /* "Recursion Desired" is off, so don't bother to relay. */
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         /* Caller needs to consult with a real name daemon. */
01238         return 0;
01239     }
01240 
01241     /* Copy ID and RD back to answer. */
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 {        /* One DNS packet over UDP. */
01250         udp_io_hdr_t    hdr;            /* UDP header (source/destination). */
01251         dns_t           dns;            /* DNS packet. */
01252 } udp_dns_t;
01253 
01254 static void refresh_cache(void)
01255 /* Find a stale entry in the cache that was used to answer a query, and send
01256  * a request to a name server that should refresh this entry.
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     /* Found one to refresh. */
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 /* Read UDP queries and replies. */
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     /* Try to read a packet. */
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     /* Restart this job no matter what. */
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     /* Check, and if necessary reinitialize my configuration. */
01358     init_config(udp.hdr.uih_dst_addr);
01359 
01360     if (udp.dns.hdr.dh_flag1 & DHF_QR) {
01361         /* This is a remote named reply, not a query. */
01362 
01363         /* Response to a query previously relayed? */
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                 /* We have found a name server! */
01369                 int i;
01370 
01371                 /* In my list? */
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         /* We got an answer, so stop worrying. */
01387         if (expecting()) {
01388             stop_expecting();
01389             force_expire(job_expect_named);
01390         }
01391 
01392         /* Put the information in the cache. */
01393         cache_reply(&udp.dns, dlen);
01394 
01395         /* Refresh a cached entry that was used when stale. */
01396         refresh_cache();
01397 
01398         /* Discard reply to myself. */
01399         if (ip == ID_IPSELF) return 1;
01400 
01401         /* Send the reply to the process that asked for it. */
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         /* A query. */
01408         if (udp.dns.hdr.dh_qdcount != HTONS(1)) return 1;
01409 
01410         if(localonly) {
01411                 /* Check if it's a local query. */
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         /* Try to compose a reply from local data. */
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             /* Send an UDP DNS reply. */
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             /* Let a real name daemon handle the query. */
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 {        /* Data for connect or listen jobs. */
01456         int             fd;             /* Open TCP channel. */
01457         int             dn_fd;          /* TCP channel to the name daemon. */
01458         int             retry;          /* Retrying a connect? */
01459         nwio_tcpcl_t    tcpcl;          /* Flags. */
01460 } data_cl_t;
01461 
01462 typedef struct data_rw {        /* Data for TCP read or write jobs. */
01463         int             r_fd;           /* Read from this TCP channel. */
01464         int             w_fd;           /* And write to this TCP channel. */
01465         struct data_rw  *rev;           /* Optional reverse TCP channel. */
01466         u8_t            *buf;           /* Buffer for bytes to transfer. */
01467         ssize_t         offset;         /* Offset in buf to r/w at. */
01468         size_t          size;           /* Size of buf. */
01469 } data_rw_t;
01470 
01471 static int job_setup_listen(void *data, int expired)
01472 /* Set up a listening channel for TCP DNS queries. */
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     /* And listen. */
01502     newjob(job_listen, NEVER, data_cl);
01503     return 1;
01504 }
01505 
01506 static int job_listen(void *data, int expired)
01507 /* A connection on the TCP DNS query channel. */
01508 {
01509     data_cl_t *data_cl= data;
01510 
01511     /* Wait for a client. */
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         /* Try again after a short time. */
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     /* Immediately resume listening. */
01523     newjob(job_setup_listen, IMMEDIATE, nil);
01524 
01525     /* Set up a connect to the real name daemon. */
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 /* Start one or two read jobs after job_setup_connect() or job_connect(). */
01533 {
01534     data_rw_t *query;   /* Client to DNS daemon relay. */
01535     data_rw_t *reply;   /* DNS daemon to client relay. */
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         /* Answer mode. */
01544         query->w_fd= fd;
01545         query->rev= nil;
01546     } else {
01547         /* Relay mode. */
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 /* Close a relay channel. */
01564 {
01565     if (data_rw->rev != nil) {
01566         /* Other end still active, signal EOF. */
01567         (void) ioctl(data_rw->w_fd, NWIOTCPSHUTDOWN, nil);
01568         data_rw->rev->rev= nil;
01569     } else {
01570         /* Close both ends down. */
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 /* Set up a connect for a TCP channel to the real name daemon. */
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         /* No name daemons to relay to, answer myself. */
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             /* Retry. */
01603             newjob(job_setup_connect, now + SHORT_TIMEOUT, data_cl);
01604         } else {
01605             /* Reply myself (bound to fail). */
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     /* And connect. */
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 /* Connect to a TCP DNS query channel. */
01626 {
01627     data_cl_t *data_cl= data;
01628 
01629     /* Try to connect. */
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         /* Connection refused. */
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             /* Search a new name daemon. */
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         /* Reply with a failure eventually. */
01649     }
01650     if (debug >= 2) printf("%s: Connect\n", nowgmt());
01651 
01652     /* Read the query from the user, send on to the name daemon, etc. */
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 /* Tell about a DNS packet on a TCP channel. */
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 /* Read TCP queries from the client. */
01674 {
01675     data_rw_t *data_rw= data;
01676     ssize_t count;
01677 
01678     /* Try to read count bytes. */
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         /* Remote end is late, or an error occurred. */
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         /* EOF. */
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             /* Malformed. */
01709             close_relay(data_rw);
01710             return 1;
01711         }
01712         if (data_rw->offset < data_rw->size) {
01713             /* Query not complete, read more. */
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     /* Relay or reply. */
01727     if (data_rw->w_fd != data_rw->r_fd) {
01728         /* We have a real name daemon to do the work. */
01729         data_rw->offset= 0;
01730         newjob(job_write_query, now + LONG_TIMEOUT, data_rw);
01731     } else {
01732         /* No real name daemons or none reachable, so use the hosts file. */
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         /* Build a reply packet. */
01741         dp= oct2dns(data_rw->buf + sizeof(u16_t));
01742         dlen= data_rw->size - sizeof(u16_t);
01743         if (!compose_reply(dp, &dlen)) {
01744             /* We're told to ask a name daemon, but that won't work. */
01745             close_relay(data_rw);
01746             return 1;
01747         }
01748 
01749         /* Start a reply write. */
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 /* Relay a TCP query to the name daemon. */
01761 {
01762     data_rw_t *data_rw= data;
01763     ssize_t count;
01764 
01765     /* Try to write count bytes to the name daemon. */
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         /* A write expired or failed (usually a broken connection.) */
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         /* Partial write, continue. */
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     /* Query fully send on, go read more queries. */
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 /* Read a TCP reply from the real name daemon. */
01803 {
01804     data_rw_t *data_rw= data;
01805     ssize_t count;
01806 
01807     /* Try to read count bytes. */
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         /* Remote end is late, or an error occurred. */
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         /* EOF. */
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             /* Malformed. */
01838             close_relay(data_rw);
01839             return 1;
01840         }
01841         if (data_rw->offset < data_rw->size) {
01842             /* Reply not complete, read more. */
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     /* Reply fully read, send it on. */
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 /* Send a TCP reply to the client. */
01858 {
01859     data_rw_t *data_rw= data;
01860     ssize_t count;
01861 
01862     /* Try to write count bytes to the client. */
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         /* A write expired or failed (usually a broken connection.) */
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         /* Partial write, continue. */
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     /* Reply fully send on, go read more replies (or queries). */
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 /* !DO_TCP */
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 /* !DO_TCP */
01907 
01908 static void named_probe(ipaddr_t ip)
01909 /* Send a probe to a name daemon, like 'host -r -t ns . <ip>'. */
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     /* Send a simple DNS query that all name servers can answer easily:
01916      * "What are the name servers for the root domain?"
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;        /* Null name. */
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 /* Look for a real name daemon to answer real DNS queries. */
01946 {
01947     if (!expired) return 0;
01948     if (debug >= 2) printf("%s: Find named\n", nowgmt());
01949 
01950     /* New search? */
01951     if (search_ct < 0) {
01952         search_ct= n_nameds;
01953         i_named= -1;
01954     }
01955 
01956     if (--search_ct < 0) {
01957         /* Forced end of search (named response!), or end of search with
01958          * nothing found.  Search again after a long time.
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     /* Send a named probe. */
01967     i_named= (i_named+1) % n_nameds;
01968     named_probe(current_named());
01969 
01970     /* Schedule the next call. */
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 /* The real name server is expected to answer by now. */
01977 {
01978     if (!expired) return 0;
01979     if (debug >= 2) printf("%s: Expect named\n", nowgmt());
01980 
01981     if (expecting() && !searching()) {
01982         /* No answer yet, start searching. */
01983         start_searching();
01984         force_expire(job_find_named);
01985     }
01986     return 1;
01987 }
01988 
01989 static void sig_handler(int sig)
01990 /* A signal forces a search for a real name daemon, etc. */
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     /* Debug output must be line buffered. */
02018     setvbuf(stdout, nil, _IOLBF, 0);
02019 
02020     /* DNS service port number? */
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':               /* Debug level. */
02036             debug= 1;
02037             if (between('0', *opt, '9')) debug= strtoul(opt, &opt, 10);
02038             break;
02039         case 'p':               /* Port to listen to (for testing.) */
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':               /* Quit after printing cache contents. */
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         /* Oops, just having a look at the cache. */
02065         debug= 2;
02066         now= time(nil);
02067         n_datamax= -1;
02068         file2cache();
02069         return 0;
02070     }
02071 
02072     /* Don't die on broken pipes, reinitialize on hangup, etc. */
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     /* TCP and UDP device names. */
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     /* Open an UDP channel for incoming DNS queries. */
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     /* The current time is... */
02101     now= time(nil);
02102 
02103     /* Read configuration and data cached by the previous nonamed. */
02104     init_config(udpopt.nwuo_locaddr);
02105     file2cache();
02106 
02107     if (!single) {
02108         /* Save process id. */
02109         if ((fp= fopen(PIDFILE, "w")) != nil) {
02110             fprintf(fp, "%u\n", (unsigned) getpid());
02111             fclose(fp);
02112         }
02113     }
02114 
02115     /* Jobs that start the ball rolling. */
02116     newjob(job_read_udp, NEVER, nil);
02117     newjob(job_setup_listen, IMMEDIATE, nil);
02118     newjob(job_find_named, IMMEDIATE, nil);
02119 
02120     /* Open syslog. */
02121     openlog("nonamed", LOG_PID, LOG_DAEMON);
02122 
02123     while (!done) {
02124         /* There is always something in the queue. */
02125         assert(queue != nil);
02126 
02127         /* Any expired jobs? */
02128         while (queue->timeout <= now) {
02129             (void) execjob(queue, 1);
02130             assert(queue != nil);
02131         }
02132 
02133         /* Check I/O jobs. */
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             /* A hangup makes us go back to square one. */
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 }

Generated on Fri Apr 14 22:57:09 2006 for minix by  doxygen 1.4.6