home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / packet / n17jsrc / domain.c < prev    next >
C/C++ Source or Header  |  1991-06-02  |  44KB  |  1,892 lines

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