home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / SRC_0618.ZIP / DOMAIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  40.1 KB  |  1,781 lines

  1. /*
  2.  *    DOMAIN.C -- domain name system stub resolver
  3.  *
  4.  *    Original code by Phil Karn, KA9Q.
  5.  *
  6.  *    Apr 90    Bill Simpson added address->name resolution, time-to-live,
  7.  *    thru    memory caching, generalized multi-record multi-type searches,
  8.  *    Oct 90    and many minor changes to conform more closely to the RFCs.
  9.  *    Feb 91    Bill Simpson added "query" command and TYPE_ANY processing.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <time.h>
  15. #include <sys/stat.h>
  16. #include "global.h"
  17. #include "mbuf.h"
  18. #include "proc.h"
  19. #include "ip.h"
  20. #include "netuser.h"
  21. #include "socket.h"
  22. #include "cmdparse.h"
  23. #include "commands.h"
  24. #include "files.h"
  25. #include "main.h"
  26. #include "domain.h"
  27.  
  28. #undef    DEBUG                /* for certain trace messages */
  29. #undef    DEBUG_PAIN            /* for painful debugging */
  30.  
  31. static struct rr *Dcache = NULLRR;    /* Cache of resource records */
  32. static int Dcache_size = 20;        /* size limit */
  33. static time_t Dcache_time = 0L;     /* timestamp */
  34.  
  35. static int Dfile_clean = FALSE;     /* discard expired records (flag) */
  36. static int Dfile_reading = 0;        /* read interlock (count) */
  37. static int Dfile_writing = 0;        /* write interlock (count) */
  38.  
  39. struct proc *Dfile_updater = NULLPROC;
  40. static int32 Dfile_wait_absolute = 0L;    /* timeout Clock time */
  41. static int Dfile_wait_relative = 300;    /* timeout file activity (seconds) */
  42.  
  43. static struct dserver *Dservers = NULLDOM; /* List of potential servers */
  44. static int Dserver_retries = 2;        /* Attempts to reach servers */
  45.  
  46. static char *Dsuffix = NULLCHAR;    /* Default suffix for names without periods */
  47. static int Dtrace = FALSE;
  48. static char *Dtypes[] = {
  49.     "",
  50.     "A",
  51.     "NS",
  52.     "MD",
  53.     "MF",
  54.     "CNAME",
  55.     "SOA",
  56.     "MB",
  57.     "MG",
  58.     "MR",
  59.     "NULL",
  60.     "WKS",
  61.     "PTR",
  62.     "HINFO",
  63.     "MINFO",
  64.     "MX",
  65.     "TXT"
  66. };
  67. static int Ndtypes = 17;
  68. static char delim[] = " \t\r\n";
  69.  
  70. static int docache __ARGS((int argc,char *argv[],void *p));
  71. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  72.  
  73. static int docacheclean __ARGS((int argc,char *argv[],void *p));
  74. static int docachelist __ARGS((int argc,char *argv[],void *p));
  75. static int docachesize __ARGS((int argc,char *argv[],void *p));
  76. static int docachewait __ARGS((int argc,char *argv[],void *p));
  77.  
  78. static void dlist_add __ARGS((struct dserver *dp));
  79. static void dlist_drop __ARGS((struct dserver *dp));
  80. static int dodnsadd __ARGS((int argc,char *argv[],void *p));
  81. static int dodnsdrop __ARGS((int argc,char *argv[],void *p));
  82. static int dodnslist __ARGS((int argc,char *argv[],void *p));
  83. static int dodnsquery __ARGS((int argc,char *argv[],void *p));
  84. static int dodnsretry __ARGS((int argc,char *argv[],void *p));
  85. static int dodnstrace __ARGS((int argc,char *argv[],void *p));
  86.  
  87. static char * dtype __ARGS((int value));
  88. static int check_ttl __ARGS((struct rr *rrlp));
  89. static int compare_rr __ARGS((struct rr *search_rrp,struct rr *target_rrp));
  90. static int compare_rr_list __ARGS((struct rr *rrlp,struct rr *target_rrp));
  91. static struct rr *copy_rr __ARGS((struct rr *rrp));
  92. static struct rr *copy_rr_list __ARGS((struct rr *rrlp));
  93. static struct rr *make_rr __ARGS((int source,
  94.     char *dname,int16 class,int16 type,int32 ttl,int16 rdl,void *data));
  95.  
  96. static void dcache_add __ARGS((struct rr *rrlp));
  97. static void dcache_drop __ARGS((struct rr *rrp));
  98. static struct rr *dcache_search __ARGS((struct rr *rrlp));
  99. static void dcache_update __ARGS((struct rr *rrlp));
  100.  
  101. static struct rr *get_rr __ARGS((FILE *fp, struct rr *lastrrp));
  102. static void put_rr __ARGS((FILE *fp,struct rr *rrp));
  103. static struct rr *dfile_search __ARGS((struct rr *rrlp));
  104. static void dfile_update __ARGS((int s,void *unused,void *p));
  105.  
  106. static void dumpdomain __ARGS((struct dhdr *dhp,int32 rtt));
  107. static int dns_makequery __ARGS((int16 op,struct rr *rrp,
  108.     char *buffer,int16 buflen));
  109. static void dns_query __ARGS((struct rr *rrlp));
  110.  
  111. static int isaddr __ARGS((char *s));
  112. static char *checksuffix __ARGS((char *dname));
  113. static struct rr *resolver __ARGS((struct rr *rrlp));
  114.  
  115.  
  116. /**
  117.  **    Domain Resolver Commands
  118.  **/
  119.  
  120. static struct cmds Dcmds[] = {
  121.     "addserver",    dodnsadd,    0, 2, "add <hostid>",
  122.     "dropserver",    dodnsdrop,    0, 2, "drop <hostid>",
  123.     "list",        dodnslist,    0, 0, NULLCHAR,
  124.     "query",    dodnsquery,    0, 2, "query <hostid>",
  125.     "retry",    dodnsretry,    0, 0, NULLCHAR,
  126.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  127.     "trace",    dodnstrace,    0, 0, NULLCHAR,
  128.     "cache",    docache,    0, 0, NULLCHAR,
  129.     NULLCHAR,
  130. };
  131.  
  132. static struct cmds Dcachecmds[] = {
  133.     "clean",    docacheclean,    0, 0, NULLCHAR,
  134.     "list",        docachelist,    0, 0, NULLCHAR,
  135.     "size",        docachesize,    0, 0, NULLCHAR,
  136.     "wait",        docachewait,    0, 0, NULLCHAR,
  137.     NULLCHAR,
  138. };
  139.  
  140. int
  141. dodomain(argc,argv,p)
  142. int argc;
  143. char *argv[];
  144. void *p;
  145. {
  146.     return subcmd(Dcmds,argc,argv,p);
  147. }
  148.  
  149. static int
  150. docache(argc,argv,p)
  151. int argc;
  152. char *argv[];
  153. void *p;
  154. {
  155.     return subcmd(Dcachecmds,argc,argv,p);
  156. }
  157.  
  158. static int
  159. dosuffix(argc,argv,p)
  160. int argc;
  161. char *argv[];
  162. void *p;
  163. {
  164.     if(argc < 2){
  165.         if(Dsuffix != NULLCHAR)
  166.             tprintf("%s\n",Dsuffix);
  167.         return 0;
  168.     }
  169.     free(Dsuffix);
  170.     Dsuffix = strdup(argv[1]);
  171.     return 0;
  172. }
  173.  
  174. static int
  175. docacheclean(argc,argv,p)
  176. int argc;
  177. char *argv[];
  178. void *p;
  179. {
  180.     return setbool( &Dfile_clean, "discard expired records", argc,argv );
  181. }
  182.  
  183. static int
  184. docachelist(argc,argv,p)
  185. int argc;
  186. char *argv[];
  187. void *p;
  188. {
  189.     struct rr *rrp;
  190.  
  191.     (void)dcache_search(NULLRR); /* update ttl */
  192.     rflush();
  193.     for(rrp=Dcache;rrp!=NULLRR;rrp=rrp->next)
  194.     {
  195.         put_rr(stdout,rrp);
  196.     }
  197.     fflush(stdout);
  198.     return 0;
  199. }
  200.  
  201. static int
  202. docachesize(argc,argv,p)
  203. int argc;
  204. char *argv[];
  205. void *p;
  206. {
  207.     int newsize;
  208.     int oldsize;
  209.     int result;
  210.  
  211.     newsize = oldsize = Dcache_size;
  212.     result = setint( &newsize, "memory cache size", argc,argv );
  213.  
  214.     if(newsize > 0){
  215.         Dcache_size = newsize;
  216.         if(newsize < oldsize){
  217.             (void)dcache_search(NULLRR); /* update size */
  218.         }
  219.     }
  220.     return result;
  221. }
  222.  
  223. static int
  224. docachewait(argc,argv,p)
  225. int argc;
  226. char *argv[];
  227. void *p;
  228. {
  229.     return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
  230. }
  231.  
  232. static void
  233. dlist_add(dp)
  234. register struct dserver *dp;
  235. {
  236.     dp->prev = NULLDOM;
  237.     dp->next = Dservers;
  238.     if(Dservers != NULLDOM)
  239.         Dservers->prev = dp;
  240.     Dservers = dp;
  241. }
  242.  
  243. static void
  244. dlist_drop(dp)
  245. register struct dserver *dp;
  246. {
  247.     if(dp->prev != NULLDOM)
  248.         dp->prev->next = dp->next;
  249.     else
  250.         Dservers = dp->next;
  251.     if(dp->next != NULLDOM)
  252.         dp->next->prev = dp->prev;
  253. }
  254.  
  255. static int
  256. dodnsadd(argc,argv,p)
  257. int argc;
  258. char *argv[];
  259. void *p;
  260. {
  261.     int32 address;
  262.  
  263.     if((address = resolve(argv[1])) == 0L){
  264.         tprintf("Resolver %s unknown\n",argv[1]);
  265.         return 1;
  266.     }
  267.     return add_nameserver(address);
  268. }
  269. int
  270. add_nameserver(address)
  271. int32 address;
  272. {
  273.     struct dserver *dp;
  274.  
  275.     dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  276.     dp->address = address;
  277.     dp->srtt = 5000L; /* 5 sec */
  278.     dp->mdev = 0;
  279.     dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  280.     dlist_add(dp);
  281.     return 0;
  282. }
  283.  
  284. static int
  285. dodnsdrop(argc,argv,p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289. {
  290.     struct dserver *dp;
  291.     int32 addr;
  292.  
  293.     addr = resolve(argv[1]);
  294.     for(dp = Dservers;dp != NULLDOM;dp = dp->next)
  295.         if(addr == dp->address)
  296.             break;
  297.  
  298.     if(dp == NULLDOM){
  299.         tprintf("Not found\n");
  300.         return 1;
  301.     }
  302.  
  303.     dlist_drop(dp);
  304.     free((char *)dp);
  305.     return 0;
  306. }
  307.  
  308. static int
  309. dodnslist(argc,argv,p)
  310. int argc;
  311. char *argv[];
  312. void *p;
  313. {
  314.     register struct dserver *dp;
  315.  
  316.     tprintf("Server address          srtt    mdev   timeout   queries responses\n");
  317.     for(dp = Dservers;dp != NULLDOM;dp = dp->next){
  318.         tprintf("%-20s%8lu%8lu%10lu%10lu%10lu\n",
  319.          inet_ntoa(dp->address),
  320.          dp->srtt,dp->mdev,dp->timeout,
  321.          dp->queries,dp->responses);
  322.     }
  323.     return 0;
  324. }
  325.  
  326. static int
  327. dodnsquery(argc,argv,p)
  328. int argc;
  329. char *argv[];
  330. void *p;
  331. {
  332.     struct rr *rrp;
  333.     struct rr *result_rrlp;
  334.     char *sname;
  335.  
  336.     if ( isaddr( argv[1] ) ) {
  337.         result_rrlp = inverse_a( aton( argv[1] ) );
  338.     } else {
  339.         sname = checksuffix( argv[1] );
  340.         rrp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_ANY,0,0,NULL);
  341.         free(sname);
  342.  
  343.         dns_query(rrp);
  344.         result_rrlp = dcache_search(rrp);
  345.         free_rr(rrp);
  346.     }
  347.  
  348.     rflush();
  349.     for( rrp=result_rrlp; rrp!=NULLRR; rrp=rrp->next)
  350.     {
  351.         put_rr(stdout,rrp);
  352.     }
  353.     fflush(stdout);
  354.     free_rr(result_rrlp);
  355.     return 0;
  356. }
  357.  
  358. static int
  359. dodnsretry(argc,argv,p)
  360. int argc;
  361. char *argv[];
  362. void *p;
  363. {
  364.     return setint( &Dserver_retries, "server retries", argc,argv );
  365. }
  366.  
  367. static int
  368. dodnstrace(argc,argv,p)
  369. int argc;
  370. char *argv[];
  371. void *p;
  372. {
  373.     return setbool(&Dtrace,"server trace",argc,argv);
  374. }
  375.  
  376.  
  377. /**
  378.  **    Domain Resource Record Utilities
  379.  **/
  380.  
  381. static char *
  382. dtype(value)
  383. int value;
  384. {
  385.     static char buf[10];
  386.  
  387.     if (value < Ndtypes)
  388.         return Dtypes[value];
  389.  
  390.     sprintf( buf, "{%d}", value);
  391.     return buf;
  392. }
  393.  
  394. /* check list of resource records for any expired ones.
  395.  * returns number of expired records.
  396.  */
  397. static int
  398. check_ttl(rrlp)
  399. register struct rr *rrlp;
  400. {
  401.     int count = 0;
  402.  
  403.     while(rrlp != NULLRR){
  404.         if(rrlp->ttl == 0L)
  405.             count++;
  406.         rrlp = rrlp->next;
  407.     }
  408.     return count;
  409. }
  410.  
  411. /* Compare two resource records.
  412.  * returns 0 if match, nonzero otherwise.
  413.  */
  414. static int
  415. compare_rr(search_rrp,target_rrp)
  416. register struct rr *search_rrp,*target_rrp;
  417. {
  418.     int i;
  419.  
  420.     if(search_rrp == NULLRR || target_rrp == NULLRR)
  421.         return -32765;
  422.  
  423.     if(search_rrp->class != target_rrp->class)
  424.         return -32763;
  425.  
  426.     if(search_rrp->type != TYPE_ANY
  427.     && search_rrp->type != target_rrp->type
  428.     && (search_rrp->source != RR_QUERY
  429.      || (target_rrp->type != TYPE_CNAME
  430.       && target_rrp->type != TYPE_PTR)))
  431.         return -32761;
  432.  
  433.     if(search_rrp->source != RR_INQUERY){
  434.         if((i = strlen(search_rrp->name)) != strlen(target_rrp->name))
  435.             return -32759;
  436.         if((i = strnicmp(search_rrp->name,target_rrp->name,i)) != 0)
  437.             return i;
  438.  
  439.         /* match negative records so that they are replaced */
  440.         if(target_rrp->rdlength == 0)
  441.             return 0;
  442.     }
  443.  
  444.     /* if a query has gotten this far, match it */
  445.     if(search_rrp->source == RR_QUERY)
  446.         return 0;
  447.  
  448.     /* ensure negative records don't replace older records */
  449.     if(search_rrp->rdlength == 0)
  450.         return -32757;
  451.  
  452.     /* match expired records so that they are replaced */
  453.     if(search_rrp->source != RR_INQUERY){
  454.         if(target_rrp->ttl == 0L)
  455.             return 0;
  456.     }
  457.  
  458.     /* Note: rdlengths are not compared because they vary depending
  459.      * on the representation (ASCII or encoded) this record was
  460.      * generated from.
  461.      */
  462.  
  463.     switch(search_rrp->type){
  464.     case TYPE_A:
  465.         i = search_rrp->rdata.addr != target_rrp->rdata.addr;
  466.         break;
  467.     case TYPE_CNAME:
  468.     case TYPE_MB:
  469.     case TYPE_MG:
  470.     case TYPE_MR:
  471.     case TYPE_NS:
  472.     case TYPE_PTR:
  473.     case TYPE_TXT:
  474.         i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
  475.         break;
  476.     case TYPE_HINFO:
  477.         i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
  478.             strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
  479.         break;
  480.     case TYPE_MX:
  481.         i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
  482.         break;
  483.     case TYPE_SOA:
  484.         i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
  485.         break;
  486.     default:
  487.         i = -32755;    /* unsupported */
  488.     }
  489.     return i;
  490. }
  491.  
  492. static int
  493. compare_rr_list(rrlp,target_rrp)
  494. register struct rr *rrlp,*target_rrp;
  495. {
  496.     while(rrlp != NULLRR){
  497.         if(compare_rr(rrlp,target_rrp) == 0)
  498.             return 0;
  499. #ifdef DEBUG_PAIN
  500.         if(Dtrace)
  501.             printf("%15d %s\n",
  502.                 compare_rr(rrlp,target_rrp),
  503.                 target_rrp->name);
  504. #endif
  505.         rrlp = rrlp->next;
  506.     }
  507.     return -32767;
  508. }
  509.  
  510. /* Make a new copy of a resource record */
  511. static struct rr *
  512. copy_rr(rrp)
  513. register struct rr *rrp;
  514. {
  515.     register struct rr *newrr;
  516.  
  517.     if(rrp == NULLRR)
  518.         return NULLRR;
  519.  
  520.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  521.     newrr->source =    rrp->source;
  522.     newrr->name =    strdup(rrp->name);
  523.     newrr->type =    rrp->type;
  524.     newrr->class =    rrp->class;
  525.     newrr->ttl =    rrp->ttl;
  526.     if((newrr->rdlength = rrp->rdlength) == 0)
  527.         return newrr;
  528.  
  529.     switch(rrp->type){
  530.     case TYPE_A:
  531.         newrr->rdata.addr = rrp->rdata.addr;
  532.         break;
  533.     case TYPE_CNAME:
  534.     case TYPE_MB:
  535.     case TYPE_MG:
  536.     case TYPE_MR:
  537.     case TYPE_NS:
  538.     case TYPE_PTR:
  539.     case TYPE_TXT:
  540.         newrr->rdata.name = strdup(rrp->rdata.name);
  541.         break;
  542.     case TYPE_HINFO:
  543.         newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
  544.         newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
  545.         break;
  546.     case TYPE_MX:
  547.         newrr->rdata.mx.pref = rrp->rdata.mx.pref;
  548.         newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
  549.         break;
  550.     case TYPE_SOA:
  551.         newrr->rdata.soa.mname =     strdup(rrp->rdata.soa.mname);
  552.         newrr->rdata.soa.rname =     strdup(rrp->rdata.soa.rname);
  553.         newrr->rdata.soa.serial =     rrp->rdata.soa.serial;
  554.         newrr->rdata.soa.refresh =     rrp->rdata.soa.refresh;
  555.         newrr->rdata.soa.retry =     rrp->rdata.soa.retry;
  556.         newrr->rdata.soa.expire =     rrp->rdata.soa.expire;
  557.         newrr->rdata.soa.minimum =     rrp->rdata.soa.minimum;
  558.         break;
  559.     }
  560.     return newrr;
  561. }
  562.  
  563. static struct rr *
  564. copy_rr_list(rrlp)
  565. register struct rr *rrlp;
  566. {
  567.     register struct rr **rrpp;
  568.     struct rr *result_rrlp;
  569.  
  570.     rrpp = &result_rrlp;
  571.     while(rrlp != NULLRR){
  572.         *rrpp = copy_rr(rrlp);
  573.         rrpp = &(*rrpp)->next;
  574.         rrlp = rrlp->next;
  575.     }
  576.     *rrpp = NULLRR;
  577.     return result_rrlp;
  578. }
  579.  
  580. /* Free (list of) resource records */
  581. void
  582. free_rr(rrlp)
  583. register struct rr *rrlp;
  584. {
  585.     register struct rr *rrp;
  586.  
  587.     while((rrp = rrlp) != NULLRR){
  588.         rrlp = rrlp->next;
  589.  
  590.         free(rrp->comment);
  591.         free(rrp->name);
  592.         if(rrp->rdlength > 0){
  593.             switch(rrp->type){
  594.             case TYPE_A:
  595.                 break;    /* Nothing allocated in rdata section */
  596.             case TYPE_CNAME:
  597.             case TYPE_MB:
  598.             case TYPE_MG:
  599.             case TYPE_MR:
  600.             case TYPE_NS:
  601.             case TYPE_PTR:
  602.             case TYPE_TXT:
  603.                 free(rrp->rdata.name);
  604.                 break;
  605.             case TYPE_HINFO:
  606.                 free(rrp->rdata.hinfo.cpu);
  607.                 free(rrp->rdata.hinfo.os);
  608.                 break;
  609.             case TYPE_MX:
  610.                 free(rrp->rdata.mx.exch);
  611.                 break;
  612.             case TYPE_SOA:
  613.                 free(rrp->rdata.soa.mname);
  614.                 free(rrp->rdata.soa.rname);
  615.                 break;
  616.             }
  617.         }
  618.         free((char *)rrp);
  619.     }
  620. }
  621.  
  622. static struct rr *
  623. make_rr(source,dname,dclass,dtype,ttl,rdl,data)
  624. int source;
  625. char *dname;
  626. int16 dclass;
  627. int16 dtype;
  628. int32 ttl;
  629. int16 rdl;
  630. void *data;
  631. {
  632.     register struct rr *newrr;
  633.  
  634.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  635.     newrr->source = source;
  636.     newrr->name = strdup(dname);
  637.     newrr->class = dclass;
  638.     newrr->type = dtype;
  639.     newrr->ttl = ttl;
  640.     if((newrr->rdlength = rdl) == 0)
  641.         return newrr;
  642.  
  643.     switch(dtype){
  644.     case TYPE_A:
  645.       {
  646.         register int32 *ap = (int32 *)data;
  647.         newrr->rdata.addr = *ap;
  648.         break;
  649.       }
  650.     case TYPE_CNAME:
  651.     case TYPE_MB:
  652.     case TYPE_MG:
  653.     case TYPE_MR:
  654.     case TYPE_NS:
  655.     case TYPE_PTR:
  656.     case TYPE_TXT:
  657.       {
  658.         newrr->rdata.name = strdup((char *)data);
  659.         break;
  660.       }
  661.     case TYPE_HINFO:
  662.       {
  663.         register struct hinfo *hinfop = (struct hinfo *)data;
  664.         newrr->rdata.hinfo.cpu = strdup(hinfop->cpu);
  665.         newrr->rdata.hinfo.os = strdup(hinfop->os);
  666.         break;
  667.       }
  668.     case TYPE_MX:
  669.       {
  670.         register struct mx *mxp = (struct mx *)data;
  671.         newrr->rdata.mx.pref = mxp->pref;
  672.         newrr->rdata.mx.exch = strdup(mxp->exch);
  673.         break;
  674.       }
  675.     case TYPE_SOA:
  676.       {
  677.         register struct soa *soap = (struct soa *)data;
  678.         newrr->rdata.soa.mname =     strdup(soap->mname);
  679.         newrr->rdata.soa.rname =     strdup(soap->rname);
  680.         newrr->rdata.soa.serial =     soap->serial;
  681.         newrr->rdata.soa.refresh =     soap->refresh;
  682.         newrr->rdata.soa.retry =     soap->retry;
  683.         newrr->rdata.soa.expire =     soap->expire;
  684.         newrr->rdata.soa.minimum =     soap->minimum;
  685.         break;
  686.       }
  687.     }
  688.     return newrr;
  689. }
  690.  
  691.  
  692. /**
  693.  **    Domain Cache Utilities
  694.  **/
  695.  
  696. static void
  697. dcache_add(rrlp)
  698. register struct rr *rrlp;
  699. {
  700.     register struct rr *last_rrp;
  701.     struct rr *save_rrp;
  702.  
  703.     if(rrlp == NULLRR)
  704.         return;
  705.  
  706.     save_rrp = rrlp;
  707.     last_rrp = NULLRR;
  708.     while(rrlp != NULLRR){
  709.         rrlp->last = last_rrp;
  710.         last_rrp = rrlp;
  711.         rrlp = rrlp->next;
  712.     }
  713.     last_rrp->next = Dcache;
  714.     if(Dcache != NULLRR)
  715.         Dcache->last = last_rrp;
  716.     Dcache = save_rrp;
  717. }
  718.  
  719. static void
  720. dcache_drop(rrp)
  721. register struct rr *rrp;
  722. {
  723.     if(rrp->last != NULLRR)
  724.         rrp->last->next = rrp->next;
  725.     else
  726.         Dcache = rrp->next;
  727.     if(rrp->next != NULLRR)
  728.         rrp->next->last = rrp->last;
  729.     rrp->last =
  730.     rrp->next = NULLRR;
  731. }
  732.  
  733. /* Search cache for resource records, removing them from the cache.
  734.  * Also, timeout cache entries, and trim cache to size.
  735.  * (Calling with NULLRR is legal -- will timeout & trim only.)
  736.  * Note that an answer from the cache cannot be authoritative, because
  737.  * we cannot guarantee that all the entries remain from a previous request.
  738.  * Returns RR list, or NULLRR if no record found.
  739.  */
  740. static struct rr *
  741. dcache_search(rrlp)
  742. struct rr *rrlp;
  743. {
  744.     register struct rr *rrp, *test_rrp;
  745.     struct rr **rrpp, *result_rrlp;
  746.     int32 elapsed;
  747.     time_t now;
  748.     int count = 0;
  749.  
  750. #ifdef DEBUG
  751.     if(Dtrace && rrlp != NULLRR){
  752.         printf("dcache_search: searching for %s\n",rrlp->name);
  753.     }
  754. #endif
  755.  
  756.     elapsed = (int32)(time(&now) - Dcache_time);
  757.     Dcache_time = now;
  758.  
  759.     rrpp = &result_rrlp;
  760.     for(rrp = Dcache; (test_rrp = rrp) != NULLRR;){
  761.         rrp = rrp->next;
  762.                     /* timeout entries */
  763.         if(test_rrp->ttl > 0L
  764.         && (test_rrp->ttl -= elapsed) <= 0L)
  765.             test_rrp->ttl = 0L;
  766.  
  767.         if(compare_rr_list(rrlp,test_rrp) == 0){
  768.             dcache_drop( *rrpp = test_rrp );
  769.             rrpp = &(*rrpp)->next;
  770.         } else if(test_rrp->source == RR_FILE && ++count > Dcache_size){
  771.             dcache_drop(test_rrp);
  772.             free_rr(test_rrp);
  773.         }
  774.     }
  775.     *rrpp = NULLRR;
  776.     return result_rrlp;
  777. }
  778.  
  779. /* Move a list of resource records to the cache, removing duplicates. */
  780. static void
  781. dcache_update(rrlp)
  782. register struct rr *rrlp;
  783. {
  784.     if(rrlp == NULLRR)
  785.         return;
  786.  
  787.     free_rr(dcache_search(rrlp));    /* remove duplicates, first */
  788.     dcache_add(rrlp);
  789. }
  790.  
  791.  
  792. /**
  793.  **    File Utilities
  794.  **/
  795.  
  796. static struct rr *
  797. get_rr(fp,lastrrp)
  798. FILE *fp;
  799. struct rr *lastrrp;
  800. {
  801.     char *line,*lp,*strtok();
  802.     struct rr *rrp;
  803.     char *name,*ttl,*class,*type,*data;
  804.     int i;
  805.  
  806.     line = mallocw(256);
  807.     if(fgets(line,256,fp) == NULL){
  808.         free(line);
  809.         return NULLRR;
  810.     }
  811.  
  812.     rrp = (struct rr *)callocw(1,sizeof(struct rr));
  813.     rrp->source = RR_FILE;
  814.  
  815.     if(line[0] == '\0' || line[0] == '#' || line[0] == ';'){
  816.         rrp->comment = line;
  817.         return rrp;
  818.     }
  819.  
  820.     if(!isspace(line[0]) || lastrrp == NULLRR){
  821.         name = strtok(line,delim);
  822.         lp = NULLCHAR;
  823.     } else {    /* Name field is missing */
  824.         name = lastrrp->name;
  825.         lp = line;
  826.     }
  827.     if(name == NULLCHAR || (i = strlen(name)) == 0){
  828.         rrp->comment = strdup("\n");
  829.         free(line);
  830.         return rrp;
  831.     }
  832.  
  833.     if(name[i-1] != '.'){
  834.         /* Tack on a trailing period if it's not there */
  835.         /* !!! need to implement $ORIGIN suffix here */
  836.         rrp->name = mallocw(i+2);
  837.         strcpy(rrp->name,name);
  838.         strcat(rrp->name,".");
  839.     } else
  840.         rrp->name = strdup(name);
  841.  
  842.     ttl = strtok(lp,delim);
  843.  
  844.     if(ttl == NULLCHAR || (!isdigit(ttl[0]) && ttl[0] != '-')){
  845.         /* Optional ttl field is missing */
  846.         rrp->ttl = TTL_MISSING;
  847.         class = ttl;
  848.     } else {
  849.         rrp->ttl = atol(ttl);
  850.         class = strtok(NULLCHAR,delim);
  851.     }
  852.  
  853.     if(class == NULLCHAR){
  854.         /* we're in trouble, but keep processing */
  855.         rrp->class = CLASS_MISSING;
  856.         type = class;
  857.     } else if(class[0] == '<'){
  858.         rrp->class = atoi(&class[1]);
  859.         type = strtok(NULLCHAR,delim);
  860.     } else if(stricmp(class,"IN") == 0){
  861.         rrp->class = CLASS_IN;
  862.         type = strtok(NULLCHAR,delim);
  863.     } else {
  864.         /* Optional class field is missing; assume IN */
  865.         rrp->class = CLASS_IN;
  866.         type = class;
  867.     }
  868.  
  869.     if(type == NULLCHAR){
  870.         /* we're in trouble, but keep processing */
  871.         rrp->type = TYPE_MISSING;
  872.         data = type;
  873.     } else if(type[0] == '{'){
  874.         rrp->type = atoi(&class[1]);
  875.         data = strtok(NULLCHAR,delim);
  876.     } else {
  877.         rrp->type = TYPE_MISSING;
  878.         for(i=1;i<Ndtypes;i++){
  879.             if(stricmp(type,Dtypes[i]) == 0){
  880.                 rrp->type = i;
  881.                 data = strtok(NULLCHAR,delim);
  882.                 break;
  883.             }
  884.         }
  885.     }
  886.  
  887.     if(rrp->type == TYPE_MISSING){
  888.         data = NULLCHAR;
  889.     }
  890.  
  891.     if(data == NULLCHAR){
  892.         /* Empty record, just return */
  893.         free(line);
  894.         return rrp;
  895.     }
  896.     switch(rrp->type){
  897.     case TYPE_A:
  898.         rrp->rdlength = 4;
  899.         rrp->rdata.addr = aton(data);
  900.         break;
  901.     case TYPE_CNAME:
  902.     case TYPE_MB:
  903.     case TYPE_MG:
  904.     case TYPE_MR:
  905.     case TYPE_NS:
  906.     case TYPE_PTR:
  907.     case TYPE_TXT:
  908.         rrp->rdlength = strlen(data);
  909.         rrp->rdata.name = strdup(data);
  910.         break;
  911.     case TYPE_HINFO:
  912.         rrp->rdlength = strlen(data);
  913.         rrp->rdata.hinfo.cpu = strdup(data);
  914.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  915.             rrp->rdlength += strlen(data);
  916.             rrp->rdata.hinfo.os = strdup(data);
  917.         }
  918.         break;
  919.     case TYPE_MX:
  920.         rrp->rdata.mx.pref = atoi(data);
  921.         rrp->rdlength = 2;
  922.  
  923.         /* Get domain name of exchanger */
  924.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  925.             rrp->rdlength += strlen(data);
  926.             rrp->rdata.mx.exch = strdup(data);
  927.         }
  928.         break;
  929.     case TYPE_SOA:
  930.         /* Get domain name of master name server */
  931.         rrp->rdlength = strlen(data);
  932.         rrp->rdata.soa.mname = strdup(data);
  933.  
  934.         /* Get domain name of irresponsible person */
  935.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  936.             rrp->rdata.soa.rname = strdup(data);
  937.             rrp->rdlength += strlen(data);
  938.         }
  939.         data = strtok(NULLCHAR,delim);
  940.         rrp->rdata.soa.serial = atol(data);
  941.         data = strtok(NULLCHAR,delim);
  942.         rrp->rdata.soa.refresh = atol(data);
  943.         data = strtok(NULLCHAR,delim);
  944.         rrp->rdata.soa.retry = atol(data);
  945.         data = strtok(NULLCHAR,delim);
  946.         rrp->rdata.soa.expire = atol(data);
  947.         data = strtok(NULLCHAR,delim);
  948.         rrp->rdata.soa.minimum = atol(data);
  949.         rrp->rdlength += 20;
  950.         break;
  951.     }
  952.  
  953.     /* !!! need to handle trailing comments */
  954.     free(line);
  955.     return rrp;
  956. }
  957.  
  958. /* Print a resource record */
  959. static void
  960. put_rr(fp,rrp)
  961. FILE *fp;
  962. struct rr *rrp;
  963. {
  964.     char * stuff;
  965.  
  966.     if(fp == NULLFILE || rrp == NULLRR)
  967.         return;
  968.  
  969.     if(rrp->name == NULLCHAR && rrp->comment != NULLCHAR){
  970.         fprintf(fp,"%s",rrp->comment);
  971.         return;
  972.     }
  973.  
  974.     fprintf(fp,"%s",rrp->name);
  975.     if(rrp->ttl != TTL_MISSING)
  976.         fprintf(fp,"\t%ld",rrp->ttl);
  977.     if(rrp->class == CLASS_IN)
  978.         fprintf(fp,"\tIN");
  979.     else
  980.         fprintf(fp,"\t<%u>",rrp->class);
  981.  
  982.     stuff = dtype(rrp->type);
  983.     fprintf(fp,"\t%s",stuff);
  984.     if(rrp->rdlength == 0){
  985.         /* Null data portion, indicates nonexistent record */
  986.         /* or unsupported type.  Hopefully, these will filter */
  987.         /* as time goes by. */
  988.         fprintf(fp,"\n");
  989.         return;
  990.     }
  991.     switch(rrp->type){
  992.     case TYPE_A:
  993.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  994.         break;
  995.     case TYPE_CNAME:
  996.     case TYPE_MB:
  997.     case TYPE_MG:
  998.     case TYPE_MR:
  999.     case TYPE_NS:
  1000.     case TYPE_PTR:
  1001.     case TYPE_TXT:
  1002.         /* These are all printable text strings */
  1003.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  1004.         break;
  1005.     case TYPE_HINFO:
  1006.         fprintf(fp,"\t%s\t%s\n",
  1007.          rrp->rdata.hinfo.cpu,
  1008.          rrp->rdata.hinfo.os);
  1009.         break;
  1010.     case TYPE_MX:
  1011.         fprintf(fp,"\t%u\t%s\n",
  1012.          rrp->rdata.mx.pref,
  1013.          rrp->rdata.mx.exch);
  1014.         break;
  1015.     case TYPE_SOA:
  1016.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  1017.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  1018.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  1019.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  1020.          rrp->rdata.soa.minimum);
  1021.         break;
  1022.     default:
  1023.         fprintf(fp,"\n");
  1024.         break;
  1025.     }
  1026. }
  1027.  
  1028. /* Search local database for resource records.
  1029.  * Returns RR list, or NULLRR if no record found.
  1030.  */
  1031. static struct rr *
  1032. dfile_search(rrlp)
  1033. struct rr *rrlp;
  1034. {
  1035.     register struct rr *frrp;
  1036.     struct rr **rrpp, *result_rrlp, *oldrrp;
  1037.     int32 elapsed;
  1038.     FILE *dbase;
  1039.     struct stat dstat;
  1040.  
  1041. #ifdef DEBUG
  1042.     if(Dtrace){
  1043.         printf("dfile_search: searching for %s\n",rrlp->name);
  1044.     }
  1045. #endif
  1046.  
  1047.     while(Dfile_writing > 0)
  1048.         pwait(&Dfile_reading);
  1049.     Dfile_reading++;
  1050.  
  1051.     if((dbase = fopen(Dfile,READ_TEXT)) == NULLFILE){
  1052.         Dfile_reading--;
  1053.         return NULLRR;
  1054.     }
  1055.     if(fstat(fileno(dbase),&dstat) != 0){
  1056.         tprintf("dfile_search: can't get file status\n");
  1057.         fclose(dbase);
  1058.         Dfile_reading--;
  1059.         return NULLRR;
  1060.     }
  1061.     if((elapsed = (int32)(Dcache_time - (time_t)dstat.st_ctime)) < 0L)
  1062.         elapsed = -elapsed;    /* arbitrary time mismatch */
  1063.  
  1064.     result_rrlp = NULLRR;        /* for contiguous test below */
  1065.     oldrrp = NULLRR;
  1066.     rrpp = &result_rrlp;
  1067.     while((frrp = get_rr(dbase,oldrrp)) != NULLRR){
  1068.         free_rr(oldrrp);
  1069.         if(frrp->type != TYPE_MISSING
  1070.         && frrp->rdlength > 0
  1071.         && compare_rr_list(rrlp,frrp) == 0){
  1072.             if(frrp->ttl > 0L
  1073.             && (frrp->ttl -= elapsed) <= 0L)
  1074.                 frrp->ttl = 0L;
  1075.             *rrpp = frrp;
  1076.             rrpp = &(*rrpp)->next;
  1077.             oldrrp = copy_rr(frrp);
  1078.         } else {
  1079.             oldrrp = frrp;
  1080.             /*
  1081.                 All records of the same name and the same type
  1082.                 are contiguous.  Therefore, for a single query,
  1083.                 we can stop searching.  Multiple queries must
  1084.                 read the whole file.
  1085.             */
  1086.             if(rrlp->type != TYPE_ANY
  1087.             && rrlp->next == NULLRR
  1088.             && result_rrlp != NULLRR)
  1089.                 break;
  1090.         }
  1091.         if(!main_exit)
  1092.             pwait(NULL);    /* run multiple sessions */
  1093.     }
  1094.     free_rr(oldrrp);
  1095.     *rrpp = NULLRR;
  1096.  
  1097.     fclose(dbase);
  1098.  
  1099.     if(--Dfile_reading <= 0){
  1100.         Dfile_reading = 0;
  1101.         psignal(&Dfile_writing,0);
  1102.     }
  1103.  
  1104.     return result_rrlp;
  1105. }
  1106.  
  1107. /* Process which will add new resource records from the cache
  1108.  * to the local file, eliminating duplicates while it goes.
  1109.  */
  1110. static void
  1111. dfile_update(s,unused,p)
  1112. int s;
  1113. void *unused;
  1114. void *p;
  1115. {
  1116.     struct rr **rrpp, *rrlp, *oldrrp;
  1117.     char *newname;
  1118.     FILE *old_fp, *new_fp;
  1119.     struct stat old_stat, new_stat;
  1120.  
  1121.     log(-1,"update Domain.txt initiated");
  1122.  
  1123.     close_s(Curproc->input);
  1124.     usesock(Curproc->input = Cmdpp->input);
  1125.     close_s(Curproc->output);
  1126.     usesock(Curproc->output = Cmdpp->output);
  1127.  
  1128.     newname = strdup(Dfile);
  1129.     strcpy(&newname[strlen(newname)-3],"tmp");
  1130.  
  1131.     while(Dfile_wait_absolute != 0L && !main_exit){
  1132.         register struct rr *frrp;
  1133.         int32 elapsed;
  1134.  
  1135.         while(Dfile_wait_absolute != 0L){
  1136.             elapsed = Dfile_wait_absolute - secclock();
  1137.             Dfile_wait_absolute = 0L;
  1138.             if(elapsed > 0L && !main_exit){
  1139.                 alarm(elapsed*1000L);
  1140.                 pwait(&Dfile_wait_absolute);
  1141.                 alarm(0L);
  1142.             }
  1143.         }
  1144.  
  1145.         log(-1,"update Domain.txt");
  1146.  
  1147.         /* create new file for copy */
  1148.         if((new_fp = fopen(newname,WRITE_TEXT)) == NULLFILE){
  1149.             tprintf("dfile_update: can't create %s!\n",newname);
  1150.             break;
  1151.         }
  1152.         if(fstat(fileno(new_fp),&new_stat) != 0){
  1153.             tprintf("dfile_update: can't get new_file status!\n");
  1154.             fclose(new_fp);
  1155.             break;
  1156.         }
  1157.  
  1158.         pwait(NULL);    /* file operations can be slow */
  1159.  
  1160.         /* timeout the cache one last time before writing */
  1161.         (void)dcache_search(NULLRR);
  1162.  
  1163.         /* copy new RRs out to the new file */
  1164.         /* (can't wait here, the cache might change) */
  1165.         rrpp = &rrlp;
  1166.         for(frrp = Dcache; frrp != NULLRR; frrp = frrp->next ){
  1167.             switch(frrp->source){
  1168.             case RR_QUESTION:
  1169.             case RR_ANSWER:
  1170.             case RR_AUTHORITY:
  1171.             case RR_ADDITIONAL:
  1172.                 *rrpp = copy_rr(frrp);
  1173.                 if(frrp->type != TYPE_MISSING
  1174.                 && frrp->rdlength > 0)
  1175.                     put_rr(new_fp,frrp);
  1176.                 rrpp = &(*rrpp)->next;
  1177.                 frrp->source = RR_FILE;
  1178.                 break;
  1179.             }
  1180.         }
  1181.         *rrpp = NULLRR;
  1182.  
  1183.         /* open up the old file, concurrently with everyone else */
  1184.         if((old_fp = fopen(Dfile,READ_TEXT)) == NULLFILE){
  1185.             /* great! no old file, so we're ready to go. */
  1186.             fclose(new_fp);
  1187.             rename(newname,Dfile);
  1188.             free_rr(rrlp);
  1189.             break;
  1190.         }
  1191.         if(fstat(fileno(old_fp),&old_stat) != 0){
  1192.             tprintf("dfile_update: can't get old_file status!\n");
  1193.             fclose(new_fp);
  1194.             fclose(old_fp);
  1195.             free_rr(rrlp);
  1196.             break;
  1197.         }
  1198.         if((elapsed = (int32)(new_stat.st_ctime - old_stat.st_ctime)) < 0L)
  1199.             elapsed = -elapsed;    /* file times are inconsistant */
  1200.  
  1201.         /* Now append any non-duplicate records */
  1202.         oldrrp = NULLRR;
  1203.         while((frrp = get_rr(old_fp,oldrrp)) != NULLRR){
  1204.             free_rr(oldrrp);
  1205.             if(frrp->name == NULLCHAR
  1206.             && frrp->comment != NULLCHAR)
  1207.                 put_rr(new_fp,frrp);
  1208.             if(frrp->type != TYPE_MISSING
  1209.             && frrp->rdlength > 0
  1210.             && compare_rr_list(rrlp,frrp) != 0){
  1211.                 if(frrp->ttl > 0L
  1212.                 && (frrp->ttl -= elapsed) <= 0L)
  1213.                     frrp->ttl = 0L;
  1214.                 if(frrp->ttl != 0 || !Dfile_clean)
  1215.                     put_rr(new_fp,frrp);
  1216.             }
  1217.             oldrrp = frrp;
  1218.             if(!main_exit)
  1219.                 pwait(NULL);    /* run in background */
  1220.         }
  1221.         free_rr(oldrrp);
  1222.         fclose(new_fp);
  1223.         fclose(old_fp);
  1224.         free_rr(rrlp);
  1225.  
  1226.         /* wait for everyone else to finish reading */
  1227.         Dfile_writing++;
  1228.         while(Dfile_reading > 0)
  1229.             pwait(&Dfile_writing);
  1230.  
  1231.         unlink(Dfile);
  1232.         rename(newname,Dfile);
  1233.  
  1234.         Dfile_writing = 0;
  1235.         psignal(&Dfile_reading,0);
  1236.     }
  1237.     free(newname);
  1238.  
  1239.     log(-1,"update Domain.txt finished");
  1240.     Dfile_updater = NULLPROC;
  1241. }
  1242.  
  1243.  
  1244. /**
  1245.  **    Domain Server Utilities
  1246.  **/
  1247.  
  1248. static void
  1249. dumpdomain(dhp,rtt)
  1250. struct dhdr *dhp;
  1251. int32 rtt;
  1252. {
  1253.     struct rr *rrp;
  1254.     char * stuff;
  1255.  
  1256.     printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  1257.      dhp->id,(long)rtt / 1000L,
  1258.      dhp->qr,dhp->opcode,dhp->aa,dhp->tc,dhp->rd,
  1259.      dhp->ra,dhp->rcode);
  1260.     printf("%u questions:\n",dhp->qdcount);
  1261.     for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next){
  1262.         stuff = dtype(rrp->type);
  1263.         printf("%s type %s class %u\n",rrp->name,
  1264.          stuff,rrp->class);
  1265.     }
  1266.     printf("%u answers:\n",dhp->ancount);
  1267.     for(rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next){
  1268.         put_rr(stdout,rrp);
  1269.     }
  1270.     printf("%u authority:\n",dhp->nscount);
  1271.     for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1272.         put_rr(stdout,rrp);
  1273.     }
  1274.     printf("%u additional:\n",dhp->arcount);
  1275.     for(rrp = dhp->additional; rrp != NULLRR; rrp = rrp->next){
  1276.         put_rr(stdout,rrp);
  1277.     }
  1278.     fflush(stdout);
  1279. }
  1280.  
  1281. static int
  1282. dns_makequery(op,srrp,buffer,buflen)
  1283. int16 op;    /* operation */
  1284. struct rr *srrp;/* Search RR */
  1285. char *buffer;    /* Area for query */
  1286. int16 buflen;    /* Length of same */
  1287. {
  1288.     char *cp,*cp1;
  1289.     char *dname, *sname;
  1290.     int16 parameter;
  1291.     int16 dlen,len;
  1292.  
  1293.     cp = buffer;
  1294.     /* Use millisecond clock for timestamping */
  1295.     cp = put16(cp,(int16)msclock());
  1296.     parameter = (op << 11)
  1297.             | 0x0100;    /* Recursion desired */
  1298.     cp = put16(cp,parameter);
  1299.     cp = put16(cp,1);
  1300.     cp = put16(cp,0);
  1301.     cp = put16(cp,0);
  1302.     cp = put16(cp,0);
  1303.  
  1304.     sname = strdup(srrp->name);
  1305.     dname = sname;
  1306.     dlen = strlen(dname);
  1307.     for(;;){
  1308.         /* Look for next dot */
  1309.         cp1 = strchr(dname,'.');
  1310.         if(cp1 != NULLCHAR)
  1311.             len = cp1-dname;    /* More to come */
  1312.         else
  1313.             len = dlen;    /* Last component */
  1314.         *cp++ = len;        /* Write length of component */
  1315.         if(len == 0)
  1316.             break;
  1317.         /* Copy component up to (but not including) dot */
  1318.         strncpy(cp,dname,len);
  1319.         cp += len;
  1320.         if(cp1 == NULLCHAR){
  1321.             *cp++ = 0;    /* Last one; write null and finish */
  1322.             break;
  1323.         }
  1324.         dname += len+1;
  1325.         dlen -= len+1;
  1326.     }
  1327.     free(sname);
  1328.     cp = put16(cp,srrp->type);
  1329.     cp = put16(cp,srrp->class);
  1330.     return cp - buffer;
  1331. }
  1332.  
  1333. /* domain server resolution loop
  1334.  * returns: any answers in cache.
  1335.  *    (future features)
  1336.  *    multiple queries.
  1337.  *    inverse queries.
  1338.  */
  1339. static void
  1340. dns_query(rrlp)
  1341. struct rr *rrlp;
  1342. {
  1343.     struct mbuf *bp;
  1344.     struct dhdr *dhp;
  1345.     struct dserver *dp;    /* server list */
  1346.     int32 rtt,abserr;
  1347.     int tried = 0;        /* server list has been retried (count) */
  1348.  
  1349.     if((dp = Dservers) == NULLDOM){
  1350.         return;
  1351.     }
  1352.  
  1353.     for(;;){
  1354.         char *buf;
  1355.         int len;
  1356.         struct sockaddr_in server_in;
  1357.         int s;
  1358.         int rval;
  1359.  
  1360.         dp->queries++;
  1361.  
  1362.         s = socket(AF_INET,SOCK_DGRAM,0);
  1363.         server_in.sin_family = AF_INET;
  1364.         server_in.sin_port = IPPORT_DOMAIN;
  1365.         server_in.sin_addr.s_addr = dp->address;
  1366.  
  1367.         if(Dtrace){
  1368.             printf("dns_query: querying server %s for %s\n",
  1369.              inet_ntoa(dp->address),rrlp->name);
  1370.         }
  1371.  
  1372.         buf = mallocw(512);
  1373.         len = dns_makequery(0,rrlp,buf,512);
  1374.         sendto(s,buf,len,0,(char *)&server_in,sizeof(server_in));
  1375.         free(buf);
  1376.         alarm(max(dp->timeout,100));
  1377.         /* Wait for something to happen */
  1378.         rval = recv_mbuf(s,&bp,0,NULLCHAR,0);
  1379.         alarm(0L);
  1380.         close_s(s);
  1381.  
  1382.         if(Dtrace){
  1383.             printf("dns_query: received message length %d, errno %d\n", rval, errno );
  1384.         }
  1385.  
  1386.         if(rval > 0)
  1387.             break;
  1388.  
  1389.         if(errno == EABORT){
  1390.             return;        /* Killed by "reset" command */
  1391.         }
  1392.  
  1393.         /* Timeout; back off this one and try another server */
  1394.         dp->timeout <<= 1;
  1395.         if((dp = dp->next) == NULLDOM){
  1396.             dp = Dservers;
  1397.             if(Dserver_retries > 0 && ++tried > Dserver_retries)
  1398.                 return;
  1399.         }
  1400.     }
  1401.  
  1402.     /* got a response */
  1403.     dp->responses++;
  1404.     dhp = (struct dhdr *) mallocw(sizeof(struct dhdr));
  1405.     ntohdomain(dhp,&bp);    /* Convert to local format */
  1406.  
  1407.     /* Compute and update the round trip time */
  1408.     rtt = (int32) ((int16)msclock() - dhp->id);
  1409.     abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  1410.     dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  1411.     dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  1412.     dp->timeout = 4 * dp->mdev + dp->srtt;
  1413.  
  1414.     /* move to top of list for next time */
  1415.     if(dp->prev != NULLDOM){
  1416.         dlist_drop(dp);
  1417.         dlist_add(dp);
  1418.     }
  1419.  
  1420.     if(Dtrace)
  1421.         dumpdomain(dhp,rtt);
  1422.  
  1423.     /* Add negative reply to answers.  This assumes that there was
  1424.      * only one question, which is true for all questions we send.
  1425.      */
  1426.     if(dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)){
  1427.         register struct rr *rrp;
  1428.         long ttl = 600L; /* Default TTL for negative records */
  1429.  
  1430.         /* look for SOA ttl */
  1431.         for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1432.             if(rrp->type == TYPE_SOA)
  1433.                 ttl = rrp->ttl;
  1434.         }
  1435.  
  1436.         /* make the questions the negative answers */
  1437.         for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
  1438.             rrp->ttl = ttl;
  1439.     } else {
  1440.         free_rr(dhp->questions);
  1441.         dhp->questions = NULLRR;
  1442.     }
  1443.  
  1444.     /* post in reverse order to maintain original order */
  1445.     dcache_update(dhp->additional);
  1446.     dcache_update(dhp->authority);
  1447.     dcache_update(dhp->answers);
  1448.     dcache_update(dhp->questions);
  1449.  
  1450.     Dfile_wait_absolute = secclock() + Dfile_wait_relative;
  1451.     if(Dfile_updater == NULLPROC){
  1452.         Dfile_updater = newproc("domain update",
  1453.             512,dfile_update,0,NULL,NULL,0);
  1454.     }
  1455.  
  1456. #ifdef DEBUG
  1457.     if(Dtrace)
  1458.         keywait(NULLCHAR,1);    /* so we can look around */
  1459. #endif
  1460.     free((char *)dhp);
  1461.     return;
  1462. }
  1463.  
  1464.  
  1465. /**
  1466.  **    Resolver Utilities
  1467.  **/
  1468.  
  1469. /* Return TRUE if string appears to be an IP address in dotted decimal;
  1470.  * return FALSE otherwise (i.e., if string is a domain name)
  1471.  */
  1472. static int
  1473. isaddr(s)
  1474. register char *s;
  1475. {
  1476.     char c;
  1477.  
  1478.     if(s == NULLCHAR)
  1479.         return TRUE;    /* Can't happen */
  1480.  
  1481.     while((c = *s++) != '\0'){
  1482.         if(c != '[' && c != ']' && !isdigit(c) && c != '.')
  1483.             return FALSE;
  1484.     }
  1485.     return TRUE;
  1486. }
  1487.  
  1488. /* Return "normalized" domain name, with default suffix and trailing '.'
  1489.  */
  1490. static char *
  1491. checksuffix(dname)
  1492. char *dname;
  1493. {
  1494.     char *sname, *tname;
  1495.  
  1496.     sname = strdup(dname);
  1497.     if(strchr(sname,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  1498.         /* Append default suffix */
  1499.         tname = mallocw(strlen(sname)+strlen(Dsuffix)+2);
  1500.         sprintf(tname,"%s.%s",sname,Dsuffix);
  1501.         free(sname);
  1502.         sname = tname;
  1503.     }
  1504.     if(sname[strlen(sname)-1] != '.'){
  1505.         /* Append trailing dot */
  1506.         tname = mallocw(strlen(sname)+2);
  1507.         sprintf(tname,"%s.",sname);
  1508.         free(sname);
  1509.         sname = tname;
  1510.     }
  1511.     return sname;
  1512. }
  1513.  
  1514. /* Search for resource records.
  1515.  * Returns RR list, or NULLRR if no record found.
  1516.  */
  1517. static struct rr *
  1518. resolver(rrlp)
  1519. register struct rr *rrlp;
  1520. {
  1521.     register struct rr *result_rrlp;
  1522.  
  1523.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  1524.         result_rrlp = dfile_search(rrlp);
  1525.     }
  1526.     if(result_rrlp == NULLRR || check_ttl(result_rrlp) != 0){
  1527.         dcache_add(result_rrlp);     /* save any expired RRs */
  1528.         dns_query(rrlp);
  1529.         result_rrlp = dcache_search(rrlp);
  1530.     }
  1531.     dcache_add(copy_rr_list(result_rrlp));
  1532.     return result_rrlp;
  1533. }
  1534.  
  1535. /* general entry point for address -> domain name resolution.
  1536.  * Returns RR list, or NULLRR if no record found.
  1537.  */
  1538. struct rr *
  1539. inverse_a(ip_address)
  1540. int32 ip_address;
  1541. {
  1542.     struct rr *prrp;
  1543.     struct rr *result_rrlp;
  1544.     char pname[30];
  1545.  
  1546.     if(ip_address == 0L)
  1547.         return NULLRR;
  1548.  
  1549.     sprintf( pname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
  1550.             lobyte(loword(ip_address)),
  1551.             hibyte(loword(ip_address)),
  1552.             lobyte(hiword(ip_address)),
  1553.             hibyte(hiword(ip_address)) );
  1554.  
  1555.     prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);
  1556.  
  1557.     prrp->next =         /* make list to speed search */
  1558.         make_rr(RR_INQUERY,NULLCHAR,CLASS_IN,TYPE_A,0,4,&ip_address);
  1559.  
  1560.     result_rrlp = resolver(prrp);
  1561.  
  1562.     free_rr(prrp);
  1563.     return result_rrlp;
  1564. }
  1565.  
  1566. /* general entry point for domain name -> resource resolution.
  1567.  * Returns RR list, or NULLRR if no record found.
  1568.  */
  1569. struct rr *
  1570. resolve_rr(dname,dtype)
  1571. char *dname;
  1572. int16 dtype;
  1573. {
  1574.     struct rr *qrrp;
  1575.     struct rr *result_rrlp;
  1576.     char *sname;
  1577.     int looping = MAXCNAME;
  1578.  
  1579.     if(dname == NULLCHAR)
  1580.         return NULLRR;
  1581.  
  1582.     sname = checksuffix(dname);
  1583.     qrrp = make_rr(RR_QUERY,sname,CLASS_IN,dtype,0,0,NULL);
  1584.     free(sname);
  1585.  
  1586.     while(looping > 0){
  1587.         if((result_rrlp=resolver(qrrp)) == NULLRR
  1588.         || result_rrlp->type == dtype)
  1589.             break;
  1590. #ifdef DEBUG
  1591.         if(Dtrace)
  1592.             put_rr(stdout,result_rrlp);
  1593. #endif
  1594.         /* Should be CNAME or PTR record */
  1595.         /* Replace name and try again */
  1596.         free(qrrp->name);
  1597.         qrrp->name = strdup(result_rrlp->rdata.name);
  1598.         free_rr(result_rrlp);
  1599.         result_rrlp = NULLRR;
  1600.         looping--;
  1601.     }
  1602.     free_rr(qrrp);
  1603.     return result_rrlp;
  1604. }
  1605.  
  1606. /* main entry point for address -> domain name resolution.
  1607.  * Returns string, or NULLCHAR if no name found.
  1608.  */
  1609. char *
  1610. resolve_a(ip_address,shorten)
  1611. int32 ip_address;        /* search address */
  1612. int shorten;            /* return only first part of name (flag)*/
  1613. {
  1614.     struct rr *save_rrlp, *rrlp;
  1615.     char *result = NULLCHAR;
  1616.  
  1617.     for( rrlp = save_rrlp = inverse_a(ip_address);
  1618.          rrlp != NULLRR && result == NULLCHAR;
  1619.          rrlp = rrlp->next ){
  1620.         if(rrlp->rdlength > 0){
  1621.             switch(rrlp->type){
  1622.             case TYPE_PTR:
  1623.                 result = strdup(rrlp->rdata.name);
  1624.                 break;
  1625.             case TYPE_A:
  1626.                 result = strdup(rrlp->name);
  1627.                 break;
  1628.             }
  1629.         }
  1630.     }
  1631.     free_rr(save_rrlp);
  1632.  
  1633.     if(result != NULLCHAR && shorten){
  1634.         int dot;
  1635.         char *shortened;
  1636.  
  1637.         if((dot = strcspn(result, ".")) == 0){
  1638.             shortened = mallocw(dot+1);
  1639.             strncpy(shortened, result, dot);
  1640.             shortened[dot] = '\0';
  1641.             free(result);
  1642.             result = shortened;
  1643.         }
  1644.     }
  1645.     return result;
  1646. }
  1647.  
  1648. /* Main entry point for domain name -> address resolution.
  1649.  * Returns 0 if name is currently unresolvable.
  1650.  */
  1651. int32
  1652. resolve(name)
  1653. char *name;
  1654. {
  1655.     register struct rr *rrlp;
  1656.     int32 ip_address = 0;
  1657.  
  1658.     if(name == NULLCHAR)
  1659.         return 0;
  1660.  
  1661.     if(isaddr(name))
  1662.         return aton(name);
  1663.  
  1664.     if((rrlp = resolve_rr(name,TYPE_A)) != NULLRR
  1665.      && rrlp->rdlength > 0)
  1666.         ip_address = rrlp->rdata.addr;
  1667.  
  1668.     /* multi-homed hosts are handled here */
  1669.     if(rrlp != NULLRR && rrlp->next != NULLRR) {
  1670.         register struct rr *rrp;
  1671.         register struct route *rp;
  1672.         int16 cost = MAXINT16;
  1673.         rrp = rrlp;
  1674.         /* choose the best of a set of routes */
  1675.         while(rrp != NULLRR) {
  1676.             if(rrp->rdlength > 0
  1677.              && (rp = rt_lookup(rrp->rdata.addr)) != NULLROUTE
  1678.              && rp->metric <= cost) {
  1679.                 ip_address = rrp->rdata.addr;
  1680.                 cost = rp->metric;
  1681.             }
  1682.             rrp = rrp->next;
  1683.         }
  1684.     }
  1685.  
  1686.     free_rr(rrlp);
  1687.     return ip_address;
  1688. }
  1689.  
  1690.  
  1691. /* Main entry point for MX record lookup.
  1692.  * Returns 0 if name is currently unresolvable.
  1693.  */
  1694. int32
  1695. resolve_mx(name)
  1696. char *name;
  1697. {
  1698.     register struct rr *rrp, *arrp;
  1699.     char *sname, *tmp, *cp;
  1700.     int32 addr, ip_address = 0;
  1701.     int16 pref = MAXINT16;
  1702.  
  1703.     if(name == NULLCHAR)
  1704.         return 0;
  1705.  
  1706.     if(isaddr(name)){
  1707.         if((sname = resolve_a(aton(name),FALSE)) == NULLCHAR)
  1708.             return 0;
  1709.     }
  1710.     else
  1711.         sname = strdup(name);
  1712.  
  1713.     cp = sname;
  1714.     while(1){
  1715.         rrp = arrp = resolve_rr(sname,TYPE_MX);
  1716.         /* Search this list of rr's for an MX record */
  1717.         while(rrp != NULLRR){
  1718.             if(rrp->rdlength > 0 && rrp->rdata.mx.pref <= pref &&
  1719.                (addr = resolve(rrp->rdata.mx.exch)) != 0L){
  1720.                 pref = rrp->rdata.mx.pref;
  1721.                 ip_address = addr;
  1722.             }
  1723.             rrp = rrp->next;
  1724.         }
  1725.         free_rr(arrp);
  1726.         if(ip_address != 0)
  1727.             break;
  1728.         /* Compose wild card one level up */
  1729.         if((cp = strchr(cp,'.')) == NULLCHAR)
  1730.             break;
  1731.         tmp = mallocw(strlen(cp)+2);
  1732.         sprintf(tmp,"*%s",cp);        /* wildcard expansion */
  1733.         free(sname);
  1734.         sname = tmp;
  1735.         cp = sname + 2;
  1736.     }
  1737.     free(sname);
  1738.     return ip_address;
  1739. }
  1740.  
  1741. /* Search for local records of the MB, MG and MR type. Returns list of
  1742.  * matching records.
  1743.  */
  1744. struct rr *
  1745. resolve_mailb(name)
  1746. char *name;        /* local username, without trailing dot */
  1747. {
  1748.     register struct rr *result_rrlp;
  1749.     struct rr *rrlp;
  1750.     char *sname;
  1751.  
  1752.     /* Append trailing dot */
  1753.     sname = mallocw(strlen(name)+2);
  1754.     sprintf(sname,"%s.",name);
  1755.     rrlp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MB,0,0,NULL);
  1756.     rrlp->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MG,0,0,NULL);
  1757.     rrlp->next->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MR,0,0,NULL);
  1758.     free(sname);
  1759.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  1760.         result_rrlp = dfile_search(rrlp);
  1761.     }
  1762.     free_rr(rrlp);
  1763.     if(Dsuffix != NULLCHAR){
  1764.         rrlp = result_rrlp;
  1765.         while(rrlp != NULLRR){    /* add domain suffix to data */
  1766.             if(rrlp->rdlength > 0 &&
  1767.                rrlp->rdata.name[rrlp->rdlength-1] != '.'){
  1768.                 sname = mallocw(rrlp->rdlength +
  1769.                     strlen(Dsuffix)+2);
  1770.                 sprintf(sname,"%s.%s",rrlp->rdata.name,Dsuffix);
  1771.                 free(rrlp->rdata.name);
  1772.                 rrlp->rdata.name = sname;
  1773.                 rrlp->rdlength = strlen(sname);
  1774.             }
  1775.             rrlp = rrlp->next;
  1776.         }
  1777.     }
  1778.     dcache_add(copy_rr_list(result_rrlp));
  1779.     return result_rrlp;
  1780. }
  1781.