home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / DOMAIN.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  59KB  |  2,514 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.  *      Jul 91  Bill Simpson added "more" sessions for query and cache list.
  11.  */
  12.  
  13. /****************************************************************************
  14. *       $Id: domain.c 1.4 93/07/16 11:43:46 ROOT_DOS Exp $
  15. *       07 Jun 92       1.2             GT      Reset DNS timeout on DNS failure.                               *
  16. *       Oct 92 - mt@kram.demon.co.uk (G7LEU) merged NOS WG7J104 DNS code.               *
  17. *       Feb 93 - lonewolf@sphere.demon.co.uk fixed DNS reply to TYPE_ANY query.
  18. *                added domain qtype <n> to set the query type used by
  19. *                domain query. Useful if your server doesn't understand TYPE_ANY
  20. *                changed all remaining printf to tprintf.
  21. *    17 May 93    1.4        GT    Fix warnings.                                    *
  22. ****************************************************************************/
  23.  
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <time.h>
  27. #include <sys/stat.h>
  28. #include <dir.h>
  29. #include <dos.h>
  30. #include <string.h>
  31. #include <stdarg.h>
  32. #include "global.h"
  33. #include "config.h"
  34. #include "mbuf.h"
  35. #include "proc.h"
  36. #include "ip.h"
  37. #include "netuser.h"
  38. #include "session.h"
  39. #include "socket.h"
  40. #include "cmdparse.h"
  41. #include "commands.h"
  42. #include "files.h"
  43. #include "main.h"
  44. #include "domain.h"
  45.  
  46. #undef  DEBUG                           /* for certain trace messages */
  47. #undef  DEBUG_PAIN                      /* for painful debugging */
  48.  
  49. static struct rr *Dcache = NULLRR;      /* Cache of resource records */
  50. static int Dcache_size = 20;            /* size limit */
  51. static time_t Dcache_time = 0L;         /* timestamp */
  52.  
  53. static int Dfile_clean = FALSE;         /* discard expired records (flag) */
  54. static int Dfile_reading = 0;           /* read interlock (count) */
  55. static int Dfile_writing = 0;           /* write interlock (count) */
  56.  
  57. struct proc *Dfile_updater = NULLPROC;
  58. static int32 Dfile_wait_absolute = 0L;  /* timeout Clock time */
  59. static int Dfile_wait_relative = 300;   /* timeout file activity (seconds) */
  60.  
  61. static struct dserver *Dservers = NULLDOM; /* List of potential servers */
  62. static int Dserver_retries = 2;         /* Attempts to reach servers */
  63. static int32 Dserver_maxwait = 0L;      /* maximum server timeout limit (seconds) */
  64.  
  65. static char *Dsuffix = NULLCHAR;        /* Default suffix for names without periods */
  66. static int Dtrace = FALSE;
  67. static int qtype = 255;
  68.  
  69. static char *Dtypes[] = {
  70.     "",
  71.     "A",
  72.     "NS",
  73.     "MD",
  74.     "MF",
  75.     "CNAME",
  76.     "SOA",
  77.     "MB",
  78.     "MG",
  79.     "MR",
  80.     "NULL",
  81.     "WKS",
  82.     "PTR",
  83.     "HINFO",
  84.     "MINFO",
  85.     "MX",
  86.     "TXT"
  87. };
  88. static int Ndtypes = 17;
  89. static char delim[] = " \t\r\n";
  90.  
  91. #ifdef DSERVER
  92. static struct DOM_FILE {
  93.     struct DOM_FILE *next;
  94.     char type;
  95.     char *filename;
  96.     char *domain;
  97.     int32 source;
  98.     struct soa dom_soa;
  99.     } *dom_file = NULL;
  100. struct proc *Drx;
  101. int Dsocket;
  102. extern char *Dzones;
  103. extern char *Dboot;
  104. #endif
  105.  
  106. extern int are_we_an_mx;
  107.  
  108. static int docache __ARGS((int argc,char *argv[],void *p));
  109. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  110.  
  111. static int docacheclean __ARGS((int argc,char *argv[],void *p));
  112. static int docachelist __ARGS((int argc,char *argv[],void *p));
  113. static int docachesize __ARGS((int argc,char *argv[],void *p));
  114. static int docachewait __ARGS((int argc,char *argv[],void *p));
  115.  
  116. static void dlist_add __ARGS((struct dserver *dp));
  117. static void dlist_drop __ARGS((struct dserver *dp));
  118. static int dodnsadd __ARGS((int argc,char *argv[],void *p));
  119. static int dodnsdrop __ARGS((int argc,char *argv[],void *p));
  120. static int dodnslist __ARGS((int argc,char *argv[],void *p));
  121. static int dodnsmaxw __ARGS((int argc,char *argv[],void *p));
  122. static int dodnsquery __ARGS((int argc,char *argv[],void *p));
  123. static int dodnsretry __ARGS((int argc,char *argv[],void *p));
  124. static int dodnstrace __ARGS((int argc,char *argv[],void *p));
  125. static int dodnsserver __ARGS((int argc,char *argv[],void *p));
  126. static int doqtype __ARGS((int argc,char *argv[],void *p));
  127. static int dostopdnsserver __ARGS((int argc,char *argv[],void *p));
  128.  
  129.  
  130. static char * dtype __ARGS((int value));
  131. static int check_ttl __ARGS((struct rr *rrlp));
  132. static int compare_rr __ARGS((struct rr *search_rrp,struct rr *target_rrp));
  133. static int compare_rr_list __ARGS((struct rr *rrlp,struct rr *target_rrp));
  134. static struct rr *copy_rr __ARGS((struct rr *rrp));
  135. static struct rr *copy_rr_list __ARGS((struct rr *rrlp));
  136. static struct rr *make_rr __ARGS((int source, char *dname,int16 class,int16 type,int32 ttl,int16 rdl,void *data));
  137.  
  138. static void dcache_add __ARGS((struct rr *rrlp));
  139. static void dcache_drop __ARGS((struct rr *rrp));
  140. static struct rr *dcache_search __ARGS((struct rr *rrlp));
  141. static void dcache_update __ARGS((struct rr *rrlp));
  142.  
  143. static struct rr *get_rr __ARGS((FILE *fp, struct rr *lastrrp));
  144. static void put_rr __ARGS((FILE *fp,struct rr *rrp));
  145. static struct rr *dfile_search __ARGS((struct rr *rrlp, char *filename));
  146. static void dfile_update __ARGS((int s,void *unused,void *p));
  147.  
  148. static void dumpdomain __ARGS((struct dhdr *dhp,int32 rtt));
  149. static int dns_makequery __ARGS((int16 op,struct rr *rrp, char *buffer,int16 buflen));
  150. static void dns_query __ARGS((struct rr *rrlp));
  151.  
  152. static int isaddr __ARGS((char *s));
  153. static char *checksuffix __ARGS((char *dname));
  154. static struct rr *resolver __ARGS((struct rr *rrlp));
  155.  
  156. static void free_dhdr __ARGS((struct dhdr *));
  157. static void proc_query __ARGS((int,void *,void *));
  158. static void drx __ARGS((int,void *,void *));
  159.  
  160. /**
  161.  **     Domain Resolver Commands
  162.  **/
  163.  
  164. static struct cmds Dcmds[] = {
  165.     { "addserver",    dodnsadd,       0, 2, "add <hostid>" },
  166.     { "dropserver",   dodnsdrop,      0, 2, "drop <hostid>" },
  167.     { "list",         dodnslist,      0, 0, NULLCHAR },
  168.     { "maxwait",      dodnsmaxw,      0, 0, NULLCHAR },
  169.     { "query",        dodnsquery,   512, 2, "query <hostid>" },
  170.     { "qtype",        doqtype,        0, 0, NULLCHAR },
  171.     { "retry",        dodnsretry,     0, 0, NULLCHAR },
  172.     { "suffix",       dosuffix,       0, 0, NULLCHAR },
  173. #ifdef DSERVER
  174.     { "startdns", dodnsserver,0, 0, NULLCHAR },
  175.     { "stopdns", dostopdnsserver,0, 0, NULLCHAR },
  176. #endif
  177.     { "trace",        dodnstrace,     0, 0, NULLCHAR },
  178.     { "cache",        docache,        0, 0, NULLCHAR },
  179.     { NULLCHAR },
  180. };
  181.  
  182. static struct cmds Dcachecmds[] = {
  183.     { "clean",        docacheclean,   0, 0, NULLCHAR },
  184.     { "list",         docachelist,  512, 0, NULLCHAR },
  185.     { "size",         docachesize,    0, 0, NULLCHAR },
  186.     { "wait",         docachewait,    0, 0, NULLCHAR },
  187.     { NULLCHAR },
  188. };
  189.  
  190. int
  191. dodomain(argc,argv,p)
  192. int argc;
  193. char *argv[];
  194. void *p;
  195. {
  196.     return subcmd(Dcmds,argc,argv,p);
  197. }
  198.  
  199. static int
  200. docache(argc,argv,p)
  201. int argc;
  202. char *argv[];
  203. void *p;
  204. {
  205.     return subcmd(Dcachecmds,argc,argv,p);
  206. }
  207.  
  208. static int
  209. dosuffix(argc,argv,p)
  210. int argc;
  211. char *argv[];
  212. void *p;
  213. {
  214.     if(argc < 2){
  215.         if(Dsuffix != NULLCHAR)
  216.             tprintf("%s\n",Dsuffix);
  217.         return 0;
  218.     }
  219.     free(Dsuffix);
  220.     Dsuffix = strdup(argv[1]);
  221.     return 0;
  222. }
  223.  
  224. static
  225. dodnsmaxw(argc,argv,p)
  226. int argc;
  227. char *argv[];
  228. void *p;
  229. {
  230.     return setlong(&Dserver_maxwait,"Server response timeout limit (sec)",argc,argv);
  231. }
  232.  
  233. static int
  234. docacheclean(argc,argv,p)
  235. int argc;
  236. char *argv[];
  237. void *p;
  238. {
  239.     return setbool( &Dfile_clean, "discard expired records", argc,argv );
  240. }
  241.  
  242. static int
  243. docachelist(argc,argv,p)
  244. int argc;
  245. char *argv[];
  246. void *p;
  247. {
  248.     struct rr *rrp;
  249.     struct session *sp;
  250.     int row = MOREROWS;
  251.  
  252.     if((sp = newsession(argv[1],DCLIST)) == NULLSESSION){
  253.         return -1;
  254.     }
  255.  
  256.     (void)dcache_search(NULLRR); /* update ttl */
  257.  
  258.     /* Put tty into raw mode so single-char responses will work */
  259.     sp->ttystate.echo = sp->ttystate.edit = 0;
  260.  
  261.     for(rrp=Dcache;rrp!=NULLRR;rrp=rrp->next)
  262.     {
  263.         put_rr(stdout,rrp);
  264.         if(--row == 0){
  265.             row = keywait("--More--",0);
  266.             switch(row){
  267.             case -1:
  268.             case 'q':
  269.             case 'Q':
  270.                 rrp = NULLRR;
  271.                 break;
  272.             case '\n':
  273.             case '\r':
  274.                 row = 1;
  275.                 break;
  276.             case ' ':
  277.             default:
  278.                 row = MOREROWS;
  279.             };
  280.         }
  281.     }
  282.     fflush(stdout);
  283.     keywait(NULLCHAR,1);
  284.     freesession(sp);
  285.     return 0;
  286. }
  287.  
  288. static int
  289. docachesize(argc,argv,p)
  290. int argc;
  291. char *argv[];
  292. void *p;
  293. {
  294.     int newsize;
  295.     int oldsize;
  296.     int result;
  297.  
  298.     newsize = oldsize = Dcache_size;
  299.     result = setint( &newsize, "memory cache size", argc,argv );
  300.  
  301.     if(newsize > 0){
  302.         Dcache_size = newsize;
  303.         if(newsize < oldsize){
  304.             (void)dcache_search(NULLRR); /* update size */
  305.         }
  306.     }
  307.     return result;
  308. }
  309.  
  310. static int
  311. docachewait(argc,argv,p)
  312. int argc;
  313. char *argv[];
  314. void *p;
  315. {
  316.     return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
  317. }
  318.  
  319. static void
  320. dlist_add(dp)
  321. register struct dserver *dp;
  322. {
  323.     dp->prev = NULLDOM;
  324.     dp->next = Dservers;
  325.     if(Dservers != NULLDOM)
  326.         Dservers->prev = dp;
  327.     Dservers = dp;
  328. }
  329.  
  330. static void
  331. dlist_drop(dp)
  332. register struct dserver *dp;
  333. {
  334.     if(dp->prev != NULLDOM)
  335.         dp->prev->next = dp->next;
  336.     else
  337.         Dservers = dp->next;
  338.     if(dp->next != NULLDOM)
  339.         dp->next->prev = dp->prev;
  340. }
  341.  
  342. static int
  343. dodnsadd(argc,argv,p)
  344. int argc;
  345. char *argv[];
  346. void *p;
  347. {
  348.     int32 address;
  349.  
  350.     if((address = resolve(argv[1])) == 0L){
  351.         tprintf("Resolver %s unknown\n",argv[1]);
  352.         return 1;
  353.     }
  354.     return add_nameserver(address);
  355. }
  356. int
  357. add_nameserver(address)
  358. int32 address;
  359. {
  360.     struct dserver *dp;
  361.  
  362.     dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  363.     dp->address = address;
  364.     dp->srtt = 5000L; /* 5 sec */
  365.     dp->mdev = 0;
  366.     dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  367.     dlist_add(dp);
  368.     return 0;
  369. }
  370.  
  371. static int
  372. dodnsdrop(argc,argv,p)
  373. int argc;
  374. char *argv[];
  375. void *p;
  376. {
  377.     struct dserver *dp;
  378.     int32 addr;
  379.  
  380.     addr = resolve(argv[1]);
  381.     for(dp = Dservers;dp != NULLDOM;dp = dp->next)
  382.         if(addr == dp->address)
  383.             break;
  384.  
  385.     if(dp == NULLDOM){
  386.         tprintf("Not found\n");
  387.         return 1;
  388.     }
  389.  
  390.     dlist_drop(dp);
  391.     free((char *)dp);
  392.     return 0;
  393. }
  394.  
  395. static int
  396. dodnslist(argc,argv,p)
  397. int argc;
  398. char *argv[];
  399. void *p;
  400. {
  401. #ifdef DSERVER
  402.     struct DOM_FILE *t_dom_file;
  403. #endif
  404.     register struct dserver *dp;
  405.  
  406.     tprintf("Server address          srtt    mdev    timeout  queries responses timeouts\n");
  407.     for(dp = Dservers;dp != NULLDOM;dp = dp->next){
  408.         tprintf("%-20s%8lu%8lu%10lu%10lu%10lu%10lu\n",
  409.          inet_ntoa(dp->address),
  410.          dp->srtt,dp->mdev,dp->timeout,
  411.          dp->queries,dp->responses,dp->timeouts);
  412.     }
  413. #ifdef DSERVER
  414.     if (Drx == NULLPROC)
  415.         tprintf("Domain Name Server not running.\n");
  416.     else tprintf("Domain Name Server running.\n");
  417.     t_dom_file = dom_file;
  418.     while(Drx != NULLPROC && t_dom_file)
  419.         {
  420.         if (t_dom_file->type == '1')
  421.             tprintf("We are primary for %s\n", t_dom_file->domain);
  422.         else if (t_dom_file->type == '2')
  423.             tprintf("We are secondary for %s (from %s)\n",
  424.                             t_dom_file->domain, inet_ntoa(t_dom_file->source));
  425.         t_dom_file = t_dom_file->next;
  426.         }
  427. #endif
  428.     return 0;
  429. }
  430.  
  431. static int
  432. doqtype(argc,argv,p)
  433. int argc;
  434. char *argv[];
  435. void *p;
  436. {
  437.     return setint(&qtype,"Query type",argc,argv);
  438. }
  439.  
  440. static int
  441. dodnsquery(argc,argv,p)
  442. int argc;
  443. char *argv[];
  444. void *p;
  445. {
  446.     struct rr *rrp;
  447.     struct rr *result_rrlp;
  448.     char *sname;
  449.     struct session *sp;
  450.     int row = MOREROWS;
  451.  
  452.     if((sp = newsession(argv[1],DQUERY)) == NULLSESSION){
  453.         return -1;
  454.     }
  455.  
  456.     if ( isaddr( argv[1] ) ) {
  457.         result_rrlp = inverse_a( aton( argv[1] ) );
  458.     } else {
  459.         sname = checksuffix( argv[1] );
  460.         rrp = make_rr(RR_QUERY,sname,CLASS_IN,qtype,0,0,NULL);
  461.         free(sname);
  462.  
  463.         dns_query(rrp);
  464.         result_rrlp = dcache_search(rrp);
  465.         free_rr(rrp);
  466.     }
  467.  
  468.     /* Put tty into raw mode so single-char responses will work */
  469.     sp->ttystate.echo = sp->ttystate.edit = 0;
  470.  
  471.     for( rrp=result_rrlp; rrp!=NULLRR; rrp=rrp->next)
  472.     {
  473.         put_rr(stdout,rrp);
  474.         if(--row == 0){
  475.             row = keywait("--More--",0);
  476.             switch(row){
  477.             case -1:
  478.             case 'q':
  479.             case 'Q':
  480.                 rrp = NULLRR;
  481.                 break;
  482.             case '\n':
  483.             case '\r':
  484.                 row = 1;
  485.                 break;
  486.             case ' ':
  487.             default:
  488.                 row = MOREROWS;
  489.             };
  490.         }
  491.     }
  492.     fflush(stdout);
  493.     free_rr(result_rrlp);
  494.     keywait(NULLCHAR,1);
  495.     freesession(sp);
  496.     return 0;
  497. }
  498.  
  499. static int
  500. dodnsretry(argc,argv,p)
  501. int argc;
  502. char *argv[];
  503. void *p;
  504. {
  505.     return setint( &Dserver_retries, "server retries", argc,argv );
  506. }
  507.  
  508. static int
  509. dodnstrace(argc,argv,p)
  510. int argc;
  511. char *argv[];
  512. void *p;
  513. {
  514.     return setbool(&Dtrace,"server trace",argc,argv);
  515. }
  516.  
  517.  
  518. /**
  519.  **     Domain Resource Record Utilities
  520.  **/
  521.  
  522. static char *
  523. dtype(value)
  524. int value;
  525. {
  526.     static char buf[10];
  527.  
  528.     if (value < Ndtypes)
  529.         return Dtypes[value];
  530.  
  531.     sprintf( buf, "{%d}", value);
  532.     return buf;
  533. }
  534.  
  535. /* check list of resource records for any expired ones.
  536.  * returns number of expired records.
  537.  */
  538. static int
  539. check_ttl(rrlp)
  540. register struct rr *rrlp;
  541. {
  542.     int count = 0;
  543.  
  544.     while(rrlp != NULLRR){
  545.         if(rrlp->ttl == 0L)
  546.             count++;
  547.         rrlp = rrlp->next;
  548.     }
  549.     return count;
  550. }
  551.  
  552. /* Compare two resource records.
  553.  * returns 0 if match, nonzero otherwise.
  554.  */
  555. static int
  556. compare_rr(search_rrp,target_rrp)
  557. register struct rr *search_rrp,*target_rrp;
  558. {
  559.     int i;
  560.  
  561.     if(search_rrp == NULLRR || target_rrp == NULLRR)
  562.         return -32765;
  563.  
  564.     if(search_rrp->class != target_rrp->class)
  565.         return -32763;
  566.  
  567.     if(search_rrp->type != TYPE_ANY
  568.     && search_rrp->type != target_rrp->type
  569.     && (search_rrp->source != RR_QUERY
  570.      || (target_rrp->type != TYPE_CNAME
  571.       && target_rrp->type != TYPE_PTR)))
  572.         return -32761;
  573.  
  574.     if(search_rrp->source != RR_INQUERY){
  575. /*
  576.         if((i = strlen(search_rrp->name)) != strlen(target_rrp->name))
  577.             return -32759;
  578. */
  579.         i = strlen(target_rrp->name);
  580.         if((i = strnicmp(search_rrp->name,target_rrp->name,i)) != 0)
  581.             return i;
  582.  
  583.         /* match negative records so that they are replaced */
  584.         if(target_rrp->rdlength == 0)
  585.             return 0;
  586.     }
  587.  
  588.     /* if a query has gotten this far, match it */
  589.     if(search_rrp->source == RR_QUERY)
  590.         return 0;
  591.  
  592.     /* ensure negative records don't replace older records */
  593.     if(search_rrp->rdlength == 0)
  594.         return -32757;
  595.  
  596.     /* match expired records so that they are replaced */
  597.     if(search_rrp->source != RR_INQUERY){
  598.         if(target_rrp->ttl == 0L)
  599.             return 0;
  600.     }
  601.  
  602.     /* Note: rdlengths are not compared because they vary depending
  603.      * on the representation (ASCII or encoded) this record was
  604.      * generated from.
  605.      */
  606.  
  607.     switch(search_rrp->type){
  608.     case TYPE_A:
  609.         i = search_rrp->rdata.addr != target_rrp->rdata.addr;
  610.         break;
  611.     case TYPE_CNAME:
  612.     case TYPE_MB:
  613.     case TYPE_MG:
  614.     case TYPE_MR:
  615.     case TYPE_NS:
  616.     case TYPE_PTR:
  617.     case TYPE_TXT:
  618.         i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
  619.         break;
  620.     case TYPE_HINFO:
  621.         i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
  622.             strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
  623.         break;
  624.     case TYPE_MX:
  625.         i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
  626.         break;
  627.     case TYPE_SOA:
  628.         i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
  629.         break;
  630.     default:
  631.         i = -32755;     /* unsupported */
  632.     }
  633.     return i;
  634. }
  635.  
  636. static int
  637. compare_rr_list(rrlp,target_rrp)
  638. register struct rr *rrlp,*target_rrp;
  639. {
  640.     while(rrlp != NULLRR){
  641.         if(compare_rr(rrlp,target_rrp) == 0)
  642.             return 0;
  643. #ifdef DEBUG_PAIN
  644.         if(Dtrace)
  645.             tprintf("%15d %s\n",
  646.                 compare_rr(rrlp,target_rrp),
  647.                 target_rrp->name);
  648. #endif
  649.         rrlp = rrlp->next;
  650.     }
  651.     return -32767;
  652. }
  653.  
  654. /* Make a new copy of a resource record */
  655. static struct rr *
  656. copy_rr(rrp)
  657. register struct rr *rrp;
  658. {
  659.     register struct rr *newrr;
  660.  
  661.     if(rrp == NULLRR)
  662.         return NULLRR;
  663.  
  664.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  665.     newrr->source = rrp->source;
  666.     newrr->name =   strdup(rrp->name);
  667.     newrr->type =   rrp->type;
  668.     newrr->class =  rrp->class;
  669.     newrr->ttl =    rrp->ttl;
  670.     if((newrr->rdlength = rrp->rdlength) == 0)
  671.         return newrr;
  672.  
  673.     switch(rrp->type){
  674.     case TYPE_A:
  675.         newrr->rdata.addr = rrp->rdata.addr;
  676.         break;
  677.     case TYPE_CNAME:
  678.     case TYPE_MB:
  679.     case TYPE_MG:
  680.     case TYPE_MR:
  681.     case TYPE_NS:
  682.     case TYPE_PTR:
  683.     case TYPE_TXT:
  684.         newrr->rdata.name = strdup(rrp->rdata.name);
  685.         break;
  686.     case TYPE_HINFO:
  687.         newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
  688.         newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
  689.         break;
  690.     case TYPE_MX:
  691.         newrr->rdata.mx.pref = rrp->rdata.mx.pref;
  692.         newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
  693.         break;
  694.     case TYPE_SOA:
  695.         newrr->rdata.soa.mname =        strdup(rrp->rdata.soa.mname);
  696.         newrr->rdata.soa.rname =        strdup(rrp->rdata.soa.rname);
  697.         newrr->rdata.soa.serial =       rrp->rdata.soa.serial;
  698.         newrr->rdata.soa.refresh =      rrp->rdata.soa.refresh;
  699.         newrr->rdata.soa.retry =        rrp->rdata.soa.retry;
  700.         newrr->rdata.soa.expire =       rrp->rdata.soa.expire;
  701.         newrr->rdata.soa.minimum =      rrp->rdata.soa.minimum;
  702.         break;
  703.     }
  704.     return newrr;
  705. }
  706.  
  707. static struct rr *
  708. copy_rr_list(rrlp)
  709. register struct rr *rrlp;
  710. {
  711.     register struct rr **rrpp;
  712.     struct rr *result_rrlp;
  713.  
  714.     rrpp = &result_rrlp;
  715.     while(rrlp != NULLRR){
  716.         *rrpp = copy_rr(rrlp);
  717.         rrpp = &(*rrpp)->next;
  718.         rrlp = rrlp->next;
  719.     }
  720.     *rrpp = NULLRR;
  721.     return result_rrlp;
  722. }
  723.  
  724. /* Free (list of) resource records */
  725. void
  726. free_rr(rrlp)
  727. register struct rr *rrlp;
  728. {
  729.     register struct rr *rrp;
  730.  
  731.     while((rrp = rrlp) != NULLRR){
  732.         rrlp = rrlp->next;
  733.  
  734.         free(rrp->comment);
  735.         free(rrp->name);
  736.         if(rrp->rdlength > 0){
  737.             switch(rrp->type){
  738.             case TYPE_A:
  739.                 break;  /* Nothing allocated in rdata section */
  740.             case TYPE_CNAME:
  741.             case TYPE_MB:
  742.             case TYPE_MG:
  743.             case TYPE_MR:
  744.             case TYPE_NS:
  745.             case TYPE_PTR:
  746.             case TYPE_TXT:
  747.                 free(rrp->rdata.name);
  748.                 break;
  749.             case TYPE_HINFO:
  750.                 free(rrp->rdata.hinfo.cpu);
  751.                 free(rrp->rdata.hinfo.os);
  752.                 break;
  753.             case TYPE_MX:
  754.                 free(rrp->rdata.mx.exch);
  755.                 break;
  756.             case TYPE_SOA:
  757.                 free(rrp->rdata.soa.mname);
  758.                 free(rrp->rdata.soa.rname);
  759.                 break;
  760.             }
  761.         }
  762.         free((char *)rrp);
  763.     }
  764. }
  765.  
  766. static struct rr *
  767. make_rr(source,dname,dclass,dtype,ttl,rdl,data)
  768. int source;
  769. char *dname;
  770. int16 dclass;
  771. int16 dtype;
  772. int32 ttl;
  773. int16 rdl;
  774. void *data;
  775. {
  776.     register struct rr *newrr;
  777.  
  778.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  779.     newrr->source = source;
  780.     newrr->name = strdup(dname);
  781.     newrr->class = dclass;
  782.     newrr->type = dtype;
  783.     newrr->ttl = ttl;
  784.     if((newrr->rdlength = rdl) == 0)
  785.         return newrr;
  786.  
  787.     switch(dtype){
  788.     case TYPE_A:
  789.       {
  790.         register int32 *ap = (int32 *)data;
  791.         newrr->rdata.addr = *ap;
  792.         break;
  793.       }
  794.     case TYPE_CNAME:
  795.     case TYPE_MB:
  796.     case TYPE_MG:
  797.     case TYPE_MR:
  798.     case TYPE_NS:
  799.     case TYPE_PTR:
  800.     case TYPE_TXT:
  801.     case TYPE_AXFR: /*##*/
  802.       {
  803.         newrr->rdata.name = strdup((char *)data);
  804.         break;
  805.       }
  806.     case TYPE_HINFO:
  807.       {
  808.         register struct hinfo *hinfop = (struct hinfo *)data;
  809.         newrr->rdata.hinfo.cpu = strdup(hinfop->cpu);
  810.         newrr->rdata.hinfo.os = strdup(hinfop->os);
  811.         break;
  812.       }
  813.     case TYPE_MX:
  814.       {
  815.         register struct mx *mxp = (struct mx *)data;
  816.         newrr->rdata.mx.pref = mxp->pref;
  817.         newrr->rdata.mx.exch = strdup(mxp->exch);
  818.         break;
  819.       }
  820.     case TYPE_SOA:
  821.       {
  822.         register struct soa *soap = (struct soa *)data;
  823.         newrr->rdata.soa.mname =        strdup(soap->mname);
  824.         newrr->rdata.soa.rname =        strdup(soap->rname);
  825.         newrr->rdata.soa.serial =       soap->serial;
  826.         newrr->rdata.soa.refresh =      soap->refresh;
  827.         newrr->rdata.soa.retry =        soap->retry;
  828.         newrr->rdata.soa.expire =       soap->expire;
  829.         newrr->rdata.soa.minimum =      soap->minimum;
  830.         break;
  831.       }
  832.     }
  833.     return newrr;
  834. }
  835.  
  836.  
  837. /**
  838.  **     Domain Cache Utilities
  839.  **/
  840.  
  841. static void
  842. dcache_add(rrlp)
  843. register struct rr *rrlp;
  844. {
  845.     register struct rr *last_rrp;
  846.     struct rr *save_rrp;
  847.  
  848.     if(rrlp == NULLRR)
  849.         return;
  850.  
  851.     save_rrp = rrlp;
  852.     last_rrp = NULLRR;
  853.     while(rrlp != NULLRR){
  854.         rrlp->last = last_rrp;
  855.         last_rrp = rrlp;
  856.         rrlp = rrlp->next;
  857.     }
  858.     last_rrp->next = Dcache;
  859.     if(Dcache != NULLRR)
  860.         Dcache->last = last_rrp;
  861.     Dcache = save_rrp;
  862. }
  863.  
  864. static void
  865. dcache_drop(rrp)
  866. register struct rr *rrp;
  867. {
  868.     if(rrp->last != NULLRR)
  869.         rrp->last->next = rrp->next;
  870.     else
  871.         Dcache = rrp->next;
  872.     if(rrp->next != NULLRR)
  873.         rrp->next->last = rrp->last;
  874.     rrp->last =
  875.     rrp->next = NULLRR;
  876. }
  877.  
  878. /* Search cache for resource records, removing them from the cache.
  879.  * Also, timeout cache entries, and trim cache to size.
  880.  * (Calling with NULLRR is legal -- will timeout & trim only.)
  881.  * Note that an answer from the cache cannot be authoritative, because
  882.  * we cannot guarantee that all the entries remain from a previous request.
  883.  * Returns RR list, or NULLRR if no record found.
  884.  */
  885. static struct rr *
  886. dcache_search(rrlp)
  887. struct rr *rrlp;
  888. {
  889.     register struct rr *rrp, *test_rrp;
  890.     struct rr **rrpp, *result_rrlp;
  891.     int32 elapsed;
  892.     time_t now;
  893.     int count = 0;
  894.  
  895. #ifdef DEBUG
  896.     if(Dtrace && rrlp != NULLRR){
  897.         tprintf("dcache_search: searching for %s\n",rrlp->name);
  898.     }
  899. #endif
  900.  
  901.     elapsed = (int32)(time(&now) - Dcache_time);
  902.     Dcache_time = now;
  903.  
  904.     rrpp = &result_rrlp;
  905.     for(rrp = Dcache; (test_rrp = rrp) != NULLRR;){
  906.         rrp = rrp->next;
  907.                     /* timeout entries */
  908.         if(test_rrp->ttl > 0L
  909.         && (test_rrp->ttl -= elapsed) <= 0L)
  910.             test_rrp->ttl = 0L;
  911.  
  912.         if(compare_rr_list(rrlp,test_rrp) == 0){
  913.             dcache_drop( *rrpp = test_rrp );
  914.             rrpp = &(*rrpp)->next;
  915.         } else if(test_rrp->source == RR_FILE && ++count > Dcache_size){
  916.             dcache_drop(test_rrp);
  917.             free_rr(test_rrp);
  918.         }
  919.     }
  920.     *rrpp = NULLRR;
  921.     return result_rrlp;
  922. }
  923.  
  924. /* Move a list of resource records to the cache, removing duplicates. */
  925. static void
  926. dcache_update(rrlp)
  927. register struct rr *rrlp;
  928. {
  929.     if(rrlp == NULLRR)
  930.         return;
  931.  
  932.     free_rr(dcache_search(rrlp));   /* remove duplicates, first */
  933.     dcache_add(rrlp);
  934. }
  935.  
  936.  
  937. /**
  938.  **     File Utilities
  939.  **/
  940.  
  941. static struct rr *
  942. get_rr(fp,lastrrp)
  943. FILE *fp;
  944. struct rr *lastrrp;
  945. {
  946.     char *line,*lp,*strtok();
  947.     struct rr *rrp;
  948.     char *name,*ttl,*class,*type,*data;
  949.     int i;
  950.  
  951.     line = mallocw(500);
  952.     if(fgets(line,500,fp) == NULL){
  953.         free(line);
  954.         return NULLRR;
  955.         }
  956.  
  957.     if (strchr(line, '('))
  958.         {
  959.         int done;
  960.         char *big_line, *p;
  961.         p = line;
  962.         while (*p && *p != '(')
  963.             p++;
  964.         *p = '\0';
  965.         big_line = mallocw(500);
  966.         if (big_line == NULL)
  967.             {
  968.             free(line);
  969.             return NULLRR;
  970.             }
  971.         strcpy(big_line, line);
  972.         done = FALSE;
  973.         while (fgets(line, 500, fp) && !done)
  974.             {
  975.             if (strchr(line, ')'))
  976.                 done = TRUE;
  977.             p = line;
  978.             while (*p && *p != ')' && *p != ';')
  979.                 p++;
  980.             *p = '\0';
  981.             p = line;
  982.             while (*p && (*p == ' ' || *p == '\t'))
  983.                 p++;
  984.             strcat(big_line, " ");
  985.             strcat(big_line, p);
  986.             }
  987.         strcpy(line, big_line);
  988.         free(big_line);
  989.         }
  990.  
  991.     rrp = (struct rr *)callocw(1,sizeof(struct rr));
  992.     rrp->source = RR_FILE;
  993.  
  994.     if(line[0] == '\0' || line[0] == '#' || line[0] == ';'){
  995.         rrp->comment = line;
  996.         return rrp;
  997.     }
  998.  
  999.     if(!isspace(line[0]) || lastrrp == NULLRR){
  1000.         name = strtok(line,delim);
  1001.         lp = NULLCHAR;
  1002.     } else {        /* Name field is missing */
  1003.         name = lastrrp->name;
  1004.         lp = line;
  1005.     }
  1006.     if(name == NULLCHAR || (i = strlen(name)) == 0){
  1007.         rrp->comment = strdup("\n");
  1008.         free(line);
  1009.         return rrp;
  1010.     }
  1011.  
  1012.     if(name[i-1] != '.'){
  1013.         /* Tack on a trailing period if it's not there */
  1014.         /* !!! need to implement $ORIGIN suffix here */
  1015.         rrp->name = mallocw(i+2);
  1016.         strcpy(rrp->name,name);
  1017.         strcat(rrp->name,".");
  1018.     } else
  1019.         rrp->name = strdup(name);
  1020.  
  1021.     ttl = strtok(lp,delim);
  1022.  
  1023.     if(ttl == NULLCHAR || (!isdigit(ttl[0]) && ttl[0] != '-')){
  1024.         /* Optional ttl field is missing */
  1025.         rrp->ttl = TTL_MISSING;
  1026.         class = ttl;
  1027.     } else {
  1028.         rrp->ttl = atol(ttl);
  1029.         class = strtok(NULLCHAR,delim);
  1030.     }
  1031.  
  1032.     if(class == NULLCHAR){
  1033.         /* we're in trouble, but keep processing */
  1034.         rrp->class = CLASS_MISSING;
  1035.         type = class;
  1036.     } else if(class[0] == '<'){
  1037.         rrp->class = atoi(&class[1]);
  1038.         type = strtok(NULLCHAR,delim);
  1039.     } else if(stricmp(class,"IN") == 0){
  1040.         rrp->class = CLASS_IN;
  1041.         type = strtok(NULLCHAR,delim);
  1042.     } else {
  1043.         /* Optional class field is missing; assume IN */
  1044.         rrp->class = CLASS_IN;
  1045.         type = class;
  1046.     }
  1047.  
  1048.     if(type == NULLCHAR){
  1049.         /* we're in trouble, but keep processing */
  1050.         rrp->type = TYPE_MISSING;
  1051.         data = type;
  1052.     } else if(type[0] == '{'){
  1053.         rrp->type = atoi(&class[1]);
  1054.         data = strtok(NULLCHAR,delim);
  1055.     } else {
  1056.         rrp->type = TYPE_MISSING;
  1057.         for(i=1;i<Ndtypes;i++){
  1058.             if(stricmp(type,Dtypes[i]) == 0){
  1059.                 rrp->type = i;
  1060.                 data = strtok(NULLCHAR,delim);
  1061.                 break;
  1062.             }
  1063.         }
  1064.     }
  1065.  
  1066.     if(rrp->type == TYPE_MISSING){
  1067.         data = NULLCHAR;
  1068.     }
  1069.  
  1070.     if(data == NULLCHAR){
  1071.         /* Empty record, just return */
  1072.         free(line);
  1073.         return rrp;
  1074.     }
  1075.     switch(rrp->type){
  1076.     case TYPE_A:
  1077.         rrp->rdlength = 4;
  1078.         rrp->rdata.addr = aton(data);
  1079.         break;
  1080.     case TYPE_CNAME:
  1081.     case TYPE_MB:
  1082.     case TYPE_MG:
  1083.     case TYPE_MR:
  1084.     case TYPE_NS:
  1085.     case TYPE_PTR:
  1086.     case TYPE_TXT:
  1087.         rrp->rdlength = strlen(data);
  1088.         rrp->rdata.name = strdup(data);
  1089.         break;
  1090.     case TYPE_HINFO:
  1091.         rrp->rdlength = strlen(data);
  1092.         rrp->rdata.hinfo.cpu = strdup(data);
  1093.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1094.             rrp->rdlength += strlen(data);
  1095.             rrp->rdata.hinfo.os = strdup(data);
  1096.         }
  1097.         break;
  1098.     case TYPE_MX:
  1099.         rrp->rdata.mx.pref = atoi(data);
  1100.         rrp->rdlength = 2;
  1101.  
  1102.         /* Get domain name of exchanger */
  1103.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1104.             rrp->rdlength += strlen(data);
  1105.             rrp->rdata.mx.exch = strdup(data);
  1106.         }
  1107.         break;
  1108.     case TYPE_SOA:
  1109.         /* Get domain name of master name server */
  1110.         rrp->rdlength = strlen(data);
  1111.         rrp->rdata.soa.mname = strdup(data);
  1112.  
  1113.         /* Get domain name of irresponsible person */
  1114.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1115.             rrp->rdata.soa.rname = strdup(data);
  1116.             rrp->rdlength += strlen(data);
  1117.         }
  1118.         data = strtok(NULLCHAR,delim);
  1119.         rrp->rdata.soa.serial = atol(data);
  1120.         data = strtok(NULLCHAR,delim);
  1121.         rrp->rdata.soa.refresh = atol(data);
  1122.         data = strtok(NULLCHAR,delim);
  1123.         rrp->rdata.soa.retry = atol(data);
  1124.         data = strtok(NULLCHAR,delim);
  1125.         rrp->rdata.soa.expire = atol(data);
  1126.         data = strtok(NULLCHAR,delim);
  1127.         rrp->rdata.soa.minimum = atol(data);
  1128.         rrp->rdlength += 20;
  1129.         break;
  1130.     }
  1131.  
  1132.     /* !!! need to handle trailing comments */
  1133.     free(line);
  1134.     return rrp;
  1135. }
  1136.  
  1137. static void sofprintf(FILE *fp, char * fmt, ...)
  1138.  /*
  1139.     This routine behaves like the standard fprintf() except
  1140.     for when the destination is stdout. In this case write
  1141.     to the current process' output socket.
  1142.  */
  1143.  char * buf;
  1144.  va_list args;
  1145.  buf = mallocw(1024); /* Big enough for most strings... (cf sockuser.c) */
  1146.  va_start(args, fmt);
  1147.  vsprintf(buf, fmt, args);
  1148.  va_end(args);
  1149.  if (fp == stdout)
  1150.     usputs(Curproc->output, buf);
  1151.  else fputs(buf, fp);
  1152.  free(buf);
  1153. }
  1154.  
  1155. /* Print a resource record */
  1156. static void
  1157. put_rr(fp,rrp)
  1158. FILE *fp;
  1159. struct rr *rrp;
  1160. {
  1161.     char * stuff;
  1162.  
  1163.     if(fp == NULLFILE || rrp == NULLRR)
  1164.         return;
  1165.  
  1166.     if(rrp->name == NULLCHAR && rrp->comment != NULLCHAR){
  1167.         sofprintf(fp,"%s",rrp->comment);
  1168.         return;
  1169.     }
  1170.  
  1171.     sofprintf(fp,"%s",rrp->name);
  1172.     if(rrp->ttl != TTL_MISSING)
  1173.         sofprintf(fp,"\t%ld",rrp->ttl);
  1174.     if(rrp->class == CLASS_IN)
  1175.         sofprintf(fp,"\tIN");
  1176.     else
  1177.         sofprintf(fp,"\t<%u>",rrp->class);
  1178.  
  1179.     stuff = dtype(rrp->type);
  1180.     sofprintf(fp,"\t%s",stuff);
  1181.     if(rrp->rdlength == 0){
  1182.         /* Null data portion, indicates nonexistent record */
  1183.         /* or unsupported type.  Hopefully, these will filter */
  1184.         /* as time goes by. */
  1185.         sofprintf(fp,"\n");
  1186.         return;
  1187.     }
  1188.     switch(rrp->type){
  1189.     case TYPE_A:
  1190.         sofprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  1191.         break;
  1192.     case TYPE_CNAME:
  1193.     case TYPE_MB:
  1194.     case TYPE_MG:
  1195.     case TYPE_MR:
  1196.     case TYPE_NS:
  1197.     case TYPE_PTR:
  1198.     case TYPE_TXT:
  1199.         /* These are all printable text strings */
  1200.         sofprintf(fp,"\t%s\n",rrp->rdata.data);
  1201.         break;
  1202.     case TYPE_HINFO:
  1203.         sofprintf(fp,"\t%s\t%s\n",
  1204.          rrp->rdata.hinfo.cpu,
  1205.          rrp->rdata.hinfo.os);
  1206.         break;
  1207.     case TYPE_MX:
  1208.         sofprintf(fp,"\t%u\t%s\n",
  1209.          rrp->rdata.mx.pref,
  1210.          rrp->rdata.mx.exch);
  1211.         break;
  1212.     case TYPE_SOA:
  1213.         sofprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  1214.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  1215.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  1216.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  1217.          rrp->rdata.soa.minimum);
  1218.         break;
  1219.     default:
  1220.         sofprintf(fp,"\n");
  1221.         break;
  1222.     }
  1223. }
  1224.  
  1225. /* Search local database for resource records.
  1226.  * Returns RR list, or NULLRR if no record found.
  1227.  */
  1228. static struct rr *
  1229. dfile_search(rrlp, filename)
  1230. struct rr *rrlp;
  1231. char *filename;
  1232. {
  1233.     int counter;
  1234.     register struct rr *frrp;
  1235.     struct rr **rrpp, *result_rrlp, *oldrrp;
  1236.     int32 elapsed;
  1237.     FILE *dbase;
  1238.     struct stat dstat;
  1239.     char *this_dfile;
  1240.  
  1241. #ifdef DEBUG
  1242.     if(Dtrace){
  1243.         tprintf("dfile_search: searching for %s\n",rrlp->name);
  1244.     }
  1245. #endif
  1246.  
  1247. #ifdef DSERVER
  1248.     if (filename)
  1249.         {
  1250.         if(Dtrace) {
  1251.             tprintf("dfile_search: searching local zone file %s\n", filename);
  1252.             }
  1253.         this_dfile = mallocw(strlen(Dzones) + 15);
  1254.         sprintf(this_dfile, "%s/%s", Dzones, filename);
  1255.         }
  1256.     else
  1257. #endif
  1258.         this_dfile = Dfile;
  1259.  
  1260.     while(Dfile_writing > 0)
  1261.         pwait(&Dfile_reading);
  1262.     Dfile_reading++;
  1263.  
  1264.     if((dbase = fopen(this_dfile,READ_TEXT)) == NULLFILE){
  1265.         Dfile_reading--;
  1266.         return NULLRR;
  1267.     }
  1268.     if(fstat(fileno(dbase),&dstat) != 0){
  1269.         tprintf("dfile_search: can't get file status\n");
  1270.         fclose(dbase);
  1271.         Dfile_reading--;
  1272.         return NULLRR;
  1273.     }
  1274.     if((elapsed = (int32)(Dcache_time - (time_t)dstat.st_ctime)) < 0L)
  1275.         elapsed = -elapsed;     /* arbitrary time mismatch */
  1276.  
  1277.     result_rrlp = NULLRR;           /* for contiguous test below */
  1278.     oldrrp = NULLRR;
  1279.     rrpp = &result_rrlp;
  1280.     counter = 0;
  1281.     while((frrp = get_rr(dbase,oldrrp)) != NULLRR){
  1282.         if (++counter == 100)
  1283.             {
  1284.             pwait(NULL);
  1285.             counter = 0;
  1286.             }
  1287.         free_rr(oldrrp);
  1288.         if(frrp->type != TYPE_MISSING
  1289.         && frrp->rdlength > 0
  1290.         && compare_rr_list(rrlp,frrp) == 0){
  1291.             if(frrp->ttl > 0L
  1292.             && (frrp->ttl -= elapsed) <= 0L)
  1293.                 frrp->ttl = 0L;
  1294.             *rrpp = frrp;
  1295.             rrpp = &(*rrpp)->next;
  1296.             oldrrp = copy_rr(frrp);
  1297.         } else {
  1298.             oldrrp = frrp;
  1299.             /*
  1300.                 All records of the same name and the same type
  1301.                 are contiguous.  Therefore, for a single query,
  1302.                 we can stop searching.  Multiple queries must
  1303.                 read the whole file.
  1304.  
  1305.                 Unless we're primary!
  1306.             */
  1307.             if(rrlp->type != TYPE_ANY
  1308.             && rrlp->next == NULLRR
  1309.             && result_rrlp != NULLRR
  1310. #ifdef DSERVER
  1311.             && filename == NULL
  1312. #endif
  1313.             )
  1314.                 break;
  1315.         }
  1316.         if(!main_exit)
  1317.             pwait(NULL);    /* run multiple sessions */
  1318.     }
  1319.     free_rr(oldrrp);
  1320.     *rrpp = NULLRR;
  1321.  
  1322.     fclose(dbase);
  1323.  
  1324.     if(--Dfile_reading <= 0){
  1325.         Dfile_reading = 0;
  1326.         psignal(&Dfile_writing,0);
  1327.     }
  1328.  
  1329. #ifdef DSERVER
  1330.     if (filename)
  1331.         free(this_dfile);
  1332. #endif
  1333.  
  1334.     return result_rrlp;
  1335. }
  1336.  
  1337. /* Process which will add new resource records from the cache
  1338.  * to the local file, eliminating duplicates while it goes.
  1339.  */
  1340. static void
  1341. dfile_update(s,unused,p)
  1342. int s;
  1343. void *unused;
  1344. void *p;
  1345. {
  1346.     struct rr **rrpp, *rrlp, *oldrrp;
  1347.     char *newname;
  1348.     FILE *old_fp, *new_fp;
  1349.     struct stat old_stat, new_stat;
  1350.  
  1351.     log(-1,"update Domain.txt initiated");
  1352.  
  1353.     close_s(Curproc->input);
  1354.     usesock(Curproc->input = Cmdpp->input);
  1355.     close_s(Curproc->output);
  1356.     usesock(Curproc->output = Cmdpp->output);
  1357.  
  1358.     newname = strdup(Dfile);
  1359.     strcpy(&newname[strlen(newname)-3],"tmp");
  1360.  
  1361.     while(Dfile_wait_absolute != 0L && !main_exit){
  1362.         register struct rr *frrp;
  1363.         int32 elapsed;
  1364.  
  1365.         while(Dfile_wait_absolute != 0L){
  1366.             elapsed = Dfile_wait_absolute - secclock();
  1367.             Dfile_wait_absolute = 0L;
  1368.             if(elapsed > 0L && !main_exit){
  1369.                 alarm(elapsed*1000L);
  1370.                 pwait(&Dfile_wait_absolute);
  1371.                 alarm(0L);
  1372.             }
  1373.         }
  1374.  
  1375.         log(-1,"update Domain.txt");
  1376.  
  1377.         /* create new file for copy */
  1378.         if((new_fp = fopen(newname,WRITE_TEXT)) == NULLFILE){
  1379.             tprintf("dfile_update: can't create %s!\n",newname);
  1380.             break;
  1381.         }
  1382.         if(fstat(fileno(new_fp),&new_stat) != 0){
  1383.             tprintf("dfile_update: can't get new_file status!\n");
  1384.             fclose(new_fp);
  1385.             break;
  1386.         }
  1387.  
  1388.         pwait(NULL);    /* file operations can be slow */
  1389.  
  1390.         /* timeout the cache one last time before writing */
  1391.         (void)dcache_search(NULLRR);
  1392.  
  1393.         /* copy new RRs out to the new file */
  1394.         /* (can't wait here, the cache might change) */
  1395.         rrpp = &rrlp;
  1396.         for(frrp = Dcache; frrp != NULLRR; frrp = frrp->next ){
  1397.             switch(frrp->source){
  1398.             case RR_QUESTION:
  1399.             case RR_ANSWER:
  1400.             case RR_AUTHORITY:
  1401.             case RR_ADDITIONAL:
  1402.                 *rrpp = copy_rr(frrp);
  1403.                 if(frrp->type != TYPE_MISSING
  1404.                 && frrp->rdlength > 0)
  1405.                     put_rr(new_fp,frrp);
  1406.                 rrpp = &(*rrpp)->next;
  1407.                 frrp->source = RR_FILE;
  1408.                 break;
  1409.             }
  1410.         }
  1411.         *rrpp = NULLRR;
  1412.  
  1413.         /* open up the old file, concurrently with everyone else */
  1414.         if((old_fp = fopen(Dfile,READ_TEXT)) == NULLFILE){
  1415.             /* great! no old file, so we're ready to go. */
  1416.             fclose(new_fp);
  1417.             rename(newname,Dfile);
  1418.             free_rr(rrlp);
  1419.             break;
  1420.         }
  1421.         if(fstat(fileno(old_fp),&old_stat) != 0){
  1422.             tprintf("dfile_update: can't get old_file status!\n");
  1423.             fclose(new_fp);
  1424.             fclose(old_fp);
  1425.             free_rr(rrlp);
  1426.             break;
  1427.         }
  1428.         if((elapsed = (int32)(new_stat.st_ctime - old_stat.st_ctime)) < 0L)
  1429.             elapsed = -elapsed;     /* file times are inconsistant */
  1430.  
  1431.         /* Now append any non-duplicate records */
  1432.         oldrrp = NULLRR;
  1433.         while((frrp = get_rr(old_fp,oldrrp)) != NULLRR){
  1434.             free_rr(oldrrp);
  1435.             if(frrp->name == NULLCHAR
  1436.             && frrp->comment != NULLCHAR)
  1437.                 put_rr(new_fp,frrp);
  1438.             if(frrp->type != TYPE_MISSING
  1439.             && frrp->rdlength > 0
  1440.             && compare_rr_list(rrlp,frrp) != 0){
  1441.                 if(frrp->ttl > 0L
  1442.                 && (frrp->ttl -= elapsed) <= 0L)
  1443.                     frrp->ttl = 0L;
  1444.                 if(frrp->ttl != 0 || !Dfile_clean)
  1445.                     put_rr(new_fp,frrp);
  1446.             }
  1447.             oldrrp = frrp;
  1448.             if(!main_exit)
  1449.                 pwait(NULL);    /* run in background */
  1450.         }
  1451.         free_rr(oldrrp);
  1452.         fclose(new_fp);
  1453.         fclose(old_fp);
  1454.         free_rr(rrlp);
  1455.  
  1456.         /* wait for everyone else to finish reading */
  1457.         Dfile_writing++;
  1458.         while(Dfile_reading > 0)
  1459.             pwait(&Dfile_writing);
  1460.  
  1461.         unlink(Dfile);
  1462.         rename(newname,Dfile);
  1463.  
  1464.         Dfile_writing = 0;
  1465.         psignal(&Dfile_reading,0);
  1466.     }
  1467.     free(newname);
  1468.  
  1469.     log(-1,"update Domain.txt finished");
  1470.     Dfile_updater = NULLPROC;
  1471. }
  1472.  
  1473.  
  1474. /**
  1475.  **     Domain Server Utilities
  1476.  **/
  1477.  
  1478. static void
  1479. dumpdomain(dhp,rtt)
  1480. struct dhdr *dhp;
  1481. int32 rtt;
  1482. {
  1483.     struct rr *rrp;
  1484.     char * stuff;
  1485.  
  1486.     tprintf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  1487.      dhp->id,(long)rtt / 1000L,
  1488.      dhp->qr,dhp->opcode,dhp->aa,dhp->tc,dhp->rd,
  1489.      dhp->ra,dhp->rcode);
  1490.     tprintf("%u questions:\n",dhp->qdcount);
  1491.     for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next){
  1492.         stuff = dtype(rrp->type);
  1493.         tprintf("%s type %s class %u\n",rrp->name,
  1494.          stuff,rrp->class);
  1495.     }
  1496.     tprintf("%u answers:\n",dhp->ancount);
  1497.     for(rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next){
  1498.         put_rr(stdout,rrp);
  1499.     }
  1500.     tprintf("%u authority:\n",dhp->nscount);
  1501.     for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1502.         put_rr(stdout,rrp);
  1503.     }
  1504.     tprintf("%u additional:\n",dhp->arcount);
  1505.     for(rrp = dhp->additional; rrp != NULLRR; rrp = rrp->next){
  1506.         put_rr(stdout,rrp);
  1507.     }
  1508.     fflush(stdout);
  1509. }
  1510.  
  1511. static int
  1512. dns_makequery(op,srrp,buffer,buflen)
  1513. int16 op;       /* operation */
  1514. struct rr *srrp;/* Search RR */
  1515. char *buffer;   /* Area for query */
  1516. int16 buflen;   /* Length of same */
  1517. {
  1518.     char *cp,*cp1;
  1519.     char *dname, *sname;
  1520.     int16 parameter;
  1521.     int16 dlen,len;
  1522.  
  1523.     cp = buffer;
  1524.     /* Use millisecond clock for timestamping */
  1525.     cp = put16(cp,(int16)msclock());
  1526.     parameter = (op << 11)
  1527.             | 0x0100;       /* Recursion desired */
  1528.     cp = put16(cp,parameter);
  1529.     cp = put16(cp,1);
  1530.     cp = put16(cp,0);
  1531.     cp = put16(cp,0);
  1532.     cp = put16(cp,0);
  1533.  
  1534.     sname = strdup(srrp->name);
  1535.     dname = sname;
  1536.     dlen = strlen(dname);
  1537.     for(;;){
  1538.         /* Look for next dot */
  1539.         cp1 = strchr(dname,'.');
  1540.         if(cp1 != NULLCHAR)
  1541.             len = cp1-dname;        /* More to come */
  1542.         else
  1543.             len = dlen;     /* Last component */
  1544.         *cp++ = len;            /* Write length of component */
  1545.         if(len == 0)
  1546.             break;
  1547.         /* Copy component up to (but not including) dot */
  1548.         strncpy(cp,dname,len);
  1549.         cp += len;
  1550.         if(cp1 == NULLCHAR){
  1551.             *cp++ = 0;      /* Last one; write null and finish */
  1552.             break;
  1553.         }
  1554.         dname += len+1;
  1555.         dlen -= len+1;
  1556.     }
  1557.     free(sname);
  1558.     cp = put16(cp,srrp->type);
  1559.     cp = put16(cp,srrp->class);
  1560.     return (int) (cp - buffer);
  1561. }
  1562.  
  1563. /* domain server resolution loop
  1564.  * returns: any answers in cache.
  1565.  *      (future features)
  1566.  *      multiple queries.
  1567.  *      inverse queries.
  1568.  */
  1569. static void
  1570. dns_query(rrlp)
  1571. struct rr *rrlp;
  1572. {
  1573.     struct mbuf *bp;
  1574.     struct dhdr *dhp;
  1575.     struct dserver *dp;     /* server list */
  1576.     int32 rtt,abserr;
  1577.     int tried = 0;          /* server list has been retried (count) */
  1578.  
  1579.     if((dp = Dservers) == NULLDOM){
  1580.         return;
  1581.     }
  1582.  
  1583.     for(;;){
  1584.         char *buf;
  1585.         int len;
  1586.         struct sockaddr_in server_in;
  1587.         int s;
  1588.         int rval;
  1589.  
  1590.         dp->queries++;
  1591.  
  1592.         s = socket(AF_INET,SOCK_DGRAM,0);
  1593.         server_in.sin_family = AF_INET;
  1594.         server_in.sin_port = IPPORT_DOMAIN;
  1595.         server_in.sin_addr.s_addr = dp->address;
  1596.  
  1597.         if(Dtrace){
  1598.             tprintf("dns_query: querying server %s for %s\n",
  1599.              inet_ntoa(dp->address),rrlp->name);
  1600.         }
  1601.  
  1602.         buf = mallocw(512);
  1603.         len = dns_makequery(0,rrlp,buf,512);
  1604.         sendto(s,buf,len,0,(char *)&server_in,sizeof(server_in));
  1605.         free(buf);
  1606.         alarm(max(dp->timeout,100));
  1607.         /* Wait for something to happen */
  1608.         rval = recv_mbuf(s,&bp,0,NULLCHAR,0);
  1609.         alarm(0L);
  1610.         close_s(s);
  1611.  
  1612.         if(Dtrace){
  1613.             tprintf("dns_query: received message length %d, errno %d\n", rval, errno );
  1614.         }
  1615.  
  1616.         if(rval > 0)
  1617.             break;
  1618.  
  1619.         if(errno == EABORT){
  1620.             return;         /* Killed by "reset" command */
  1621.         }
  1622.  
  1623.         /* Timeout; back off this one and try another server */
  1624.         dp->timeouts++;
  1625.         dp->timeout <<= 1;
  1626.         /* There may be a limit to how long we will wait */
  1627.         if(Dserver_maxwait && dp->timeout > (Dserver_maxwait * 1000L))
  1628.                                         dp->timeout = Dserver_maxwait * 1000L;
  1629.  
  1630.         if((dp = dp->next) == NULLDOM){
  1631.             dp = Dservers;
  1632.             if(Dserver_retries > 0 && ++tried > Dserver_retries)
  1633.                 {
  1634.                 if (Dserver_maxwait == 0)
  1635.                     /* Only if not specified the maximum wait - MT Oct 92 */
  1636.                     {
  1637.                     /* Reset timeouts  - GT 07 Jun 92. */
  1638.                     while (dp != NULLDOM)
  1639.                         {
  1640.                         dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  1641.                         dp = dp->next;
  1642.                         }
  1643.                     }       
  1644.                 dp = Dservers;
  1645.                 return;
  1646.                 }
  1647.         }
  1648.     }
  1649.  
  1650.     /* got a response */
  1651.     dp->responses++;
  1652.     dhp = (struct dhdr *) mallocw(sizeof(struct dhdr));
  1653.     ntohdomain(dhp,&bp);    /* Convert to local format */
  1654.  
  1655.     /* Compute and update the round trip time */
  1656.     rtt = (int32) ((int16)msclock() - dhp->id);
  1657.     abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  1658.     dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  1659.     dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  1660.     dp->timeout = 4 * dp->mdev + dp->srtt;
  1661.  
  1662.     /* move to top of list for next time */
  1663.     if(dp->prev != NULLDOM){
  1664.         dlist_drop(dp);
  1665.         dlist_add(dp);
  1666.     }
  1667.  
  1668.     if(Dtrace)
  1669.         dumpdomain(dhp,rtt);
  1670.  
  1671.     /* Add negative reply to answers.  This assumes that there was
  1672.      * only one question, which is true for all questions we send.
  1673.      */
  1674.     if(dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)){
  1675.         register struct rr *rrp;
  1676.         long ttl = 600L; /* Default TTL for negative records */
  1677.  
  1678.         /* look for SOA ttl */
  1679.         for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1680.             if(rrp->type == TYPE_SOA)
  1681.                 ttl = rrp->ttl;
  1682.         }
  1683.  
  1684.         /* make the questions the negative answers */
  1685.         for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
  1686.             rrp->ttl = ttl;
  1687.     } else {
  1688.         free_rr(dhp->questions);
  1689.         dhp->questions = NULLRR;
  1690.     }
  1691.  
  1692.     /* post in reverse order to maintain original order */
  1693.     dcache_update(dhp->additional);
  1694.     dcache_update(dhp->authority);
  1695.     dcache_update(dhp->answers);
  1696.     dcache_update(dhp->questions);
  1697.  
  1698.     Dfile_wait_absolute = secclock() + Dfile_wait_relative;
  1699.     if(Dfile_updater == NULLPROC){
  1700.         Dfile_updater = newproc("domain update",
  1701.             512,dfile_update,0,NULL,NULL,0);
  1702.     }
  1703.  
  1704. #ifdef DEBUG
  1705.     if(Dtrace)
  1706.         keywait(NULLCHAR,1);    /* so we can look around */
  1707. #endif
  1708.     free((char *)dhp);
  1709.     return;
  1710. }
  1711.  
  1712.  
  1713. /**
  1714.  **     Resolver Utilities
  1715.  **/
  1716.  
  1717. /* Return TRUE if string appears to be an IP address in dotted decimal;
  1718.  * return FALSE otherwise (i.e., if string is a domain name)
  1719.  */
  1720. static int
  1721. isaddr(s)
  1722. register char *s;
  1723. {
  1724.     char c;
  1725.  
  1726.     if(s == NULLCHAR)
  1727.         return TRUE;    /* Can't happen */
  1728.  
  1729.     while((c = *s++) != '\0'){
  1730.         if(c != '[' && c != ']' && !isdigit(c) && c != '.')
  1731.             return FALSE;
  1732.     }
  1733.     return TRUE;
  1734. }
  1735.  
  1736. /* Return "normalized" domain name, with default suffix and trailing '.'
  1737.  */
  1738. static char *
  1739. checksuffix(dname)
  1740. char *dname;
  1741. {
  1742.     char *sname, *tname;
  1743.  
  1744.     sname = strdup(dname);
  1745.     if(strchr(sname,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  1746.         /* Append default suffix */
  1747.         tname = mallocw(strlen(sname)+strlen(Dsuffix)+2);
  1748.         sprintf(tname,"%s.%s",sname,Dsuffix);
  1749.         free(sname);
  1750.         sname = tname;
  1751.     }
  1752.     if(sname[strlen(sname)-1] != '.'){
  1753.         /* Append trailing dot */
  1754.         tname = mallocw(strlen(sname)+2);
  1755.         sprintf(tname,"%s.",sname);
  1756.         free(sname);
  1757.         sname = tname;
  1758.     }
  1759.     return sname;
  1760. }
  1761.  
  1762. char *
  1763. zone_filename(domain, expire)
  1764. char *domain;
  1765. int32 *expire;
  1766. {
  1767.     struct DOM_FILE *t_dom_file;
  1768.     char *name;
  1769.     int len;
  1770.     len = strlen(domain);
  1771.     name = mallocw(len + 2);
  1772.     strcpy(name, domain);
  1773.     if (name[len - 1] != '.')
  1774.         {
  1775.         strcat(name, ".");
  1776.         len++;
  1777.         }
  1778.     t_dom_file = dom_file;
  1779.     while (Drx != NULLPROC && t_dom_file)
  1780.         {
  1781.         if (stricmp(t_dom_file->domain, name + len
  1782.                                         - strlen(t_dom_file->domain)) == NULL)
  1783.             {
  1784.             if (expire)
  1785.                 *expire = t_dom_file->dom_soa.expire;
  1786.             if (Dtrace)
  1787.                 tprintf("DNS: Using file %s\n", t_dom_file->filename);
  1788.             free(name);
  1789.             return t_dom_file->filename;
  1790.             }
  1791.         t_dom_file = t_dom_file->next;
  1792.         }
  1793.     free(name);
  1794.     return NULL;
  1795. }
  1796.  
  1797. /* Search for resource records.
  1798.  * Returns RR list, or NULLRR if no record found.
  1799.  */
  1800. static struct rr *
  1801. resolver(rrlp)
  1802. register struct rr *rrlp;
  1803. {
  1804.     register struct rr *result_rrlp;
  1805.     char *t;
  1806. #ifdef DSERVER
  1807.     int32 expire;
  1808.     struct rr *t_rr;
  1809. #endif
  1810.  
  1811. #ifdef DSERVER
  1812.     /*
  1813.     Are we primary for the domain? If so, we must answer from the
  1814.     file cos we can't guarantee that a full set of records for a
  1815.     particular query will be in the cache.
  1816.     */
  1817.     if ((t = zone_filename(rrlp->name, &expire)) != NULL)
  1818.         {
  1819.         result_rrlp = dfile_search(rrlp, t);
  1820.         if (result_rrlp != NULLRR)
  1821.             {
  1822.             t_rr = result_rrlp;
  1823.             while (t_rr)
  1824.                 {
  1825.                 t_rr->ttl = expire;
  1826.                 t_rr = t_rr->next;
  1827.                 }
  1828. /*
  1829. If we never use the cache to answer things we're primary for then there's
  1830. no point in caching the results! MT - G7LEU
  1831.             dcache_add(copy_rr_list(result_rrlp));
  1832. */
  1833.             }
  1834.         return result_rrlp;
  1835.         }
  1836. #endif
  1837.  
  1838.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  1839.         result_rrlp = dfile_search(rrlp, NULL);
  1840.     }
  1841.     if(result_rrlp == NULLRR || check_ttl(result_rrlp) != 0){
  1842.         dcache_add(result_rrlp);        /* save any expired RRs */
  1843.         dns_query(rrlp);
  1844.         result_rrlp = dcache_search(rrlp);
  1845.     }
  1846.     dcache_add(copy_rr_list(result_rrlp));
  1847.     return result_rrlp;
  1848. }
  1849.  
  1850. /* general entry point for address -> domain name resolution.
  1851.  * Returns RR list, or NULLRR if no record found.
  1852.  */
  1853. struct rr *
  1854. inverse_a(ip_address)
  1855. int32 ip_address;
  1856. {
  1857.     struct rr *prrp;
  1858.     struct rr *result_rrlp;
  1859.     char pname[30];
  1860.  
  1861.     if(ip_address == 0L)
  1862.         return NULLRR;
  1863.  
  1864.     sprintf( pname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
  1865.             lobyte(loword(ip_address)),
  1866.             hibyte(loword(ip_address)),
  1867.             lobyte(hiword(ip_address)),
  1868.             hibyte(hiword(ip_address)) );
  1869.  
  1870.     prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);
  1871.  
  1872.     prrp->next =            /* make list to speed search */
  1873.         make_rr(RR_INQUERY,NULLCHAR,CLASS_IN,TYPE_A,0,4,&ip_address);
  1874.  
  1875.     result_rrlp = resolver(prrp);
  1876.  
  1877.     free_rr(prrp);
  1878.     return result_rrlp;
  1879. }
  1880.  
  1881. /* general entry point for domain name -> resource resolution.
  1882.  * Returns RR list, or NULLRR if no record found.
  1883.  */
  1884. struct rr *
  1885. resolve_rr(dname,dtype)
  1886. char *dname;
  1887. int16 dtype;
  1888. {
  1889.     struct rr *qrrp;
  1890.     struct rr *result_rrlp;
  1891.     char *sname;
  1892.     int looping = MAXCNAME;
  1893.  
  1894.     if(dname == NULLCHAR)
  1895.         return NULLRR;
  1896.  
  1897.     sname = checksuffix(dname);
  1898.     qrrp = make_rr(RR_QUERY,sname,CLASS_IN,dtype,0,0,NULL);
  1899.     free(sname);
  1900.  
  1901.     while(looping > 0){
  1902.  
  1903.         /* Change this condition to include TYPE_ANY. ILP 17/2/93 */
  1904.  
  1905.         if((result_rrlp=resolver(qrrp)) == NULLRR
  1906.         || result_rrlp->type == dtype
  1907.         || dtype == TYPE_ANY)
  1908.             break;
  1909. #ifdef DEBUG
  1910.         if(Dtrace)
  1911.             put_rr(stdout,result_rrlp);
  1912. #endif
  1913.         /* Should be CNAME or PTR record */
  1914.         /* Replace name and try again */
  1915.         free(qrrp->name);
  1916.         qrrp->name = strdup(result_rrlp->rdata.name);
  1917.         free_rr(result_rrlp);
  1918.         result_rrlp = NULLRR;
  1919.         looping--;
  1920.     }
  1921.     free_rr(qrrp);
  1922.     return result_rrlp;
  1923. }
  1924.  
  1925. /* main entry point for address -> domain name resolution.
  1926.  * Returns string, or NULLCHAR if no name found.
  1927.  */
  1928. char *
  1929. resolve_a(ip_address,shorten)
  1930. int32 ip_address;               /* search address */
  1931. int shorten;                    /* return only first part of name (flag)*/
  1932. {
  1933.     struct rr *save_rrlp, *rrlp;
  1934.     char *result = NULLCHAR;
  1935.  
  1936.     for( rrlp = save_rrlp = inverse_a(ip_address);
  1937.          rrlp != NULLRR && result == NULLCHAR;
  1938.          rrlp = rrlp->next ){
  1939.         if(rrlp->rdlength > 0){
  1940.             switch(rrlp->type){
  1941.             case TYPE_PTR:
  1942.                 result = strdup(rrlp->rdata.name);
  1943.                 break;
  1944.             case TYPE_A:
  1945.                 result = strdup(rrlp->name);
  1946.                 break;
  1947.             }
  1948.         }
  1949.     }
  1950.     free_rr(save_rrlp);
  1951.  
  1952.     if(result != NULLCHAR && shorten){
  1953.         int dot;
  1954.         char *shortened;
  1955.  
  1956.         if((dot = strcspn(result, ".")) == 0){
  1957.             shortened = mallocw(dot+1);
  1958.             strncpy(shortened, result, dot);
  1959.             shortened[dot] = '\0';
  1960.             free(result);
  1961.             result = shortened;
  1962.         }
  1963.     }
  1964.     return result;
  1965. }
  1966.  
  1967. /* Main entry point for domain name -> address resolution.
  1968.  * Returns 0 if name is currently unresolvable.
  1969.  */
  1970. int32
  1971. resolve(name)
  1972. char *name;
  1973. {
  1974.     register struct rr *rrlp;
  1975.     int32 ip_address = 0;
  1976.  
  1977.     if(name == NULLCHAR)
  1978.         return 0;
  1979.  
  1980.     if(isaddr(name))
  1981.         return aton(name);
  1982.  
  1983.     if((rrlp = resolve_rr(name,TYPE_A)) != NULLRR
  1984.      && rrlp->rdlength > 0)
  1985.         ip_address = rrlp->rdata.addr;
  1986.  
  1987.     /* multi-homed hosts are handled here */
  1988.     if(rrlp != NULLRR && rrlp->next != NULLRR) {
  1989.         register struct rr *rrp;
  1990.         register struct route *rp;
  1991.         int16 cost = MAXINT16;
  1992.         rrp = rrlp;
  1993.         /* choose the best of a set of routes */
  1994.         while(rrp != NULLRR) {
  1995.             if(rrp->rdlength > 0
  1996.              && (rp = rt_lookup(rrp->rdata.addr)) != NULLROUTE
  1997. #if    0
  1998.              && rp->metric <= cost) {
  1999. #endif
  2000.              && rp->metric < cost) {
  2001.                 ip_address = rrp->rdata.addr;
  2002.                 cost = rp->metric;
  2003.             }
  2004.             rrp = rrp->next;
  2005.         }
  2006.     }
  2007.  
  2008.     free_rr(rrlp);
  2009.     return ip_address;
  2010. }
  2011.  
  2012.  
  2013. /* Main entry point for MX record lookup.
  2014.  * Returns 0 if name is currently unresolvable.
  2015.  */
  2016. int32
  2017. resolve_mx(name)
  2018. char *name;
  2019. {
  2020.     register struct rr *rrp, *arrp;
  2021.     char *sname, *tmp, *cp;
  2022.     int32 addr, ip_address = 0;
  2023.     int16 pref = MAXINT16;
  2024.     int our_domain = 0;
  2025.  
  2026.     are_we_an_mx = 0;
  2027.     if (zone_filename(name, NULL))
  2028.         our_domain = 1;
  2029.  
  2030.     if(name == NULLCHAR)
  2031.         return 0;
  2032.  
  2033.     if(isaddr(name)){
  2034.         if((sname = resolve_a(aton(name),FALSE)) == NULLCHAR)
  2035.             return 0;
  2036.     }
  2037.     else
  2038.         sname = strdup(name);
  2039.  
  2040.     cp = sname;
  2041.     while(1){
  2042.         rrp = arrp = resolve_rr(sname,TYPE_MX);
  2043.         /* Search this list of rr's for an MX record */
  2044.         while(rrp != NULLRR){
  2045.             if(rrp->rdlength > 0 && (addr = resolve(rrp->rdata.mx.exch)) != 0L)
  2046.                 {
  2047.                 if (addr == Ip_addr)
  2048.                     are_we_an_mx = 1;
  2049.                 if (rrp->rdata.mx.pref <= pref)
  2050.                     {
  2051.                     pref = rrp->rdata.mx.pref;
  2052.                     ip_address = addr;
  2053.                     }
  2054.                 }
  2055.             rrp = rrp->next;
  2056.         }
  2057.         free_rr(arrp);
  2058.         if(ip_address != 0)
  2059.             break;
  2060.         /* If this is our domain we can say no at this point */
  2061.         if (our_domain)
  2062.             break;
  2063.         /* Compose wild card one level up */
  2064.         if((cp = strchr(cp,'.')) == NULLCHAR)
  2065.             break;
  2066.         tmp = mallocw(strlen(cp)+2);
  2067.         sprintf(tmp,"*%s",cp);          /* wildcard expansion */
  2068.         free(sname);
  2069.         sname = tmp;
  2070.         cp = sname + 2;
  2071.     }
  2072.     free(sname);
  2073.     if (Dtrace)
  2074.         tprintf("resolve_mx %s returns %s\n", name, inet_ntoa(ip_address));
  2075.     return ip_address;
  2076. }
  2077.  
  2078. /* Search for local records of the MB, MG and MR type. Returns list of
  2079.  * matching records.
  2080.  */
  2081. struct rr *
  2082. resolve_mailb(name)
  2083. char *name;             /* local username, without trailing dot */
  2084. {
  2085.     register struct rr *result_rrlp;
  2086.     struct rr *rrlp;
  2087.     char *sname;
  2088.  
  2089.     /* Append trailing dot */
  2090.     sname = mallocw(strlen(name)+2);
  2091.     sprintf(sname,"%s.",name);
  2092.     rrlp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MB,0,0,NULL);
  2093.     rrlp->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MG,0,0,NULL);
  2094.     rrlp->next->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MR,0,0,NULL);
  2095.     free(sname);
  2096.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  2097.         result_rrlp = dfile_search(rrlp, NULL);
  2098.     }
  2099.     free_rr(rrlp);
  2100.     if(Dsuffix != NULLCHAR){
  2101.         rrlp = result_rrlp;
  2102.         while(rrlp != NULLRR){  /* add domain suffix to data */
  2103.             if(rrlp->rdlength > 0 &&
  2104.                rrlp->rdata.name[rrlp->rdlength-1] != '.'){
  2105.                 sname = mallocw(rrlp->rdlength +
  2106.                     strlen(Dsuffix)+2);
  2107.                 sprintf(sname,"%s.%s",rrlp->rdata.name,Dsuffix);
  2108.                 free(rrlp->rdata.name);
  2109.                 rrlp->rdata.name = sname;
  2110.                 rrlp->rdlength = strlen(sname);
  2111.             }
  2112.             rrlp = rrlp->next;
  2113.         }
  2114.     }
  2115.     dcache_add(copy_rr_list(result_rrlp));
  2116.     return result_rrlp;
  2117. }
  2118.  
  2119. #ifdef DSERVER
  2120.  
  2121. /* Domain Name Server - based on the server in GRI-Nos 910828
  2122.  * ported to current NOS code by Johan. K. Reinalda, WG7J/PA3DIS
  2123.  * Merged into Demon Internet Services version - MT (g7leu) Sept 1992.
  2124.  * Added primary nameserver - MT (g7leu) October 1992.
  2125.  */
  2126.  
  2127. /* Process a query received by the DNS server */
  2128. static void
  2129. proc_query(unused,d,b)
  2130. int unused;
  2131. void *d;
  2132. void *b;
  2133. {
  2134.     struct dserver *dp;
  2135.     struct dhdr *dhdr;
  2136.     int i,len;
  2137.     char *buf;
  2138.     struct sockaddr_in server;
  2139.     struct rr *rrp, *rrans, *rrtmp;
  2140. #ifdef    notdef
  2141.     struct rr *rrns, *rradd, *ap;
  2142. #endif
  2143.     struct rr *qp;
  2144.     int32 expire;
  2145.  
  2146.     dp = (struct dserver *) d;      /* The query address */
  2147.     dhdr = (struct dhdr *) b;       /* The query in host format */
  2148.  
  2149.     rrans = NULLRR;
  2150. #ifdef notdef
  2151.     rrns = rradd = NULLRR;
  2152. #endif
  2153.     qp = dhdr->questions;
  2154.  
  2155.     /* This loop does NOT support multiple questions yet */
  2156. #ifdef notdef
  2157.     for(i=0;i<dhdr->qdcount;i++){
  2158. #endif
  2159.  
  2160.     if(zone_filename(qp->name, &expire))
  2161.         dhdr->aa = 1;
  2162.     else dhdr->aa = 0;
  2163.  
  2164.     switch(qp->type) {
  2165.     case TYPE_A:
  2166.     case TYPE_MX:
  2167.     case TYPE_CNAME:
  2168.     case TYPE_HINFO:
  2169.     case TYPE_PTR:
  2170.     case TYPE_NS:
  2171.     case TYPE_SOA:
  2172.  
  2173.         /* So we can do a dom q <dom.name> from another ka9q ILP 17/2/93 */
  2174.     case TYPE_ANY:
  2175.  
  2176.       /* Not all of the below types are implemented in resolve_rr() */
  2177. #ifdef notdef
  2178.     case TYPE_TXT:
  2179. #endif
  2180.         if((rrp = resolve_rr(qp->name,qp->type)) != NULLRR) {
  2181.         /* we found an entry, go tell him */
  2182.         dhdr->rcode = NO_ERROR;
  2183.         dhdr->qr = RESPONSE;
  2184.                 rrp->ttl = expire;
  2185.         } else {
  2186.         /* we did not find an entry, go tell him */
  2187.         rrp = (struct rr *)callocw(1,sizeof(struct rr));
  2188.         rrp->name = strdup(qp->name);
  2189.         rrp->type = qp->type;
  2190.         rrp->class = qp->class;
  2191.         rrp->ttl = 500L;
  2192.         rrp->rdata.addr = 0L;
  2193.         rrp->rdlength = 4;  /* size of addr data */
  2194.         dhdr->rcode = NAME_ERROR;
  2195.         dhdr->qr = RESPONSE;
  2196.         }
  2197.         rrans = rrp;
  2198.         break;
  2199.     /* Search only the local cache and domain file for these next few */
  2200.     /* Is this a good idea ??? */
  2201.     case TYPE_MB:
  2202.     case TYPE_MG:
  2203.     case TYPE_MR:
  2204.         rrp = make_rr(RR_QUERY,qp->name,CLASS_IN,qp->type,0,0,NULL);
  2205.         if((rrans = dcache_search(rrp)) == NULLRR){
  2206.         rrans = dfile_search(rrp, NULL);
  2207.         }
  2208.         free_rr(rrp);
  2209.         break;
  2210. #ifdef notdef
  2211.     /* Not implemented, yet (?) */
  2212.     case TYPE_MD:
  2213.     case TYPE_MF:
  2214.     case TYPE_WKS:
  2215.     case TYPE_NULL:
  2216.     case TYPE_MINFO:
  2217. #endif
  2218.     default:
  2219.         dhdr->rcode = NOT_IMPL;
  2220.         dhdr->qr = RESPONSE;
  2221.     }
  2222.     /* This loop does NOT support multiple questions yet */
  2223. #ifdef notdef
  2224.     qp = qp->next;  /* next question */
  2225.     }
  2226. #endif
  2227.  
  2228.     /* Find the number of answer records */
  2229.     i = 0;
  2230.     rrtmp = rrans;
  2231.     while(rrtmp != NULLRR) {
  2232.     i++;
  2233.     rrtmp = rrtmp->next;
  2234.     }
  2235.     dhdr->ancount = i;
  2236.     dhdr->answers = rrans;
  2237.  
  2238.     /* Authority & Additional RR's not implemented yet. */
  2239.     dhdr->authority = NULLRR;
  2240.     dhdr->nscount = 0;
  2241.     dhdr->arcount = 0;
  2242.     dhdr->additional = NULLRR;
  2243.  
  2244. #ifdef notdef
  2245.     /* Find the number of authority records */
  2246.     i = 0;
  2247.     rrtmp = rrns;
  2248.     while(rrtmp != NULLRR) {
  2249.     i++;
  2250.     rrtmp = rrtmp->next;
  2251.     }
  2252.     dhdr->nscount = i;
  2253.     dhdr->authority = rrns;
  2254.  
  2255.     /* Find the number of additional records */
  2256.     i = 0;
  2257.     rrtmp = rradd;
  2258.     while(rrtmp != NULLRR) {
  2259.     i++;
  2260.     rrtmp = rrtmp->next;
  2261.     }
  2262.     dhdr->arcount = i;
  2263.     dhdr->additional = rradd;
  2264. #endif
  2265.  
  2266.     if(Dtrace) {
  2267.     tputs("DNS: replying");
  2268.     dumpdomain(dhdr,0);
  2269.     }
  2270.  
  2271.     /* Maximum reply size is 512, see rfc1034/1035 */
  2272.     buf = mallocw(512);
  2273.     len = htondomain(dhdr,buf,512);
  2274.     free_dhdr(dhdr);
  2275.  
  2276.     server.sin_family = AF_INET;
  2277.     server.sin_port = dp->port;
  2278.     server.sin_addr.s_addr = dp->address;
  2279.     sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
  2280.     free(buf);
  2281.     free((char *)dp);
  2282. }
  2283.  
  2284.  
  2285. /* Process to receive all domain server related messages */
  2286. static void
  2287. drx(unused,u,p)
  2288. int unused;
  2289. void *u;
  2290. void *p;
  2291. {
  2292.     struct sockaddr_in sock,from;
  2293.     int fromlen;
  2294.     struct mbuf *bp;
  2295.     struct dhdr *dhdr;
  2296.     struct dserver *dp;
  2297.     int foo;
  2298.  
  2299.     Dsocket = socket(AF_INET,SOCK_DGRAM,0);
  2300.     sock.sin_family = AF_INET;
  2301.     sock.sin_addr.s_addr = INADDR_ANY;
  2302.     sock.sin_port = IPPORT_DOMAIN;
  2303.     if(bind(Dsocket,(char *)&sock,sizeof(sock)) == -1) {
  2304.     tputs("DNS: can't bind\n");
  2305.         Drx = NULLPROC;
  2306.         return;
  2307.     }
  2308.     /* Now loop forever, processing queries */
  2309.     for(;;){
  2310.         fromlen = sizeof(from);
  2311.     if((foo = recv_mbuf(Dsocket,&bp,0,(char *)&from,&fromlen)) == -1)
  2312.         break;  /* Server closing */
  2313.         if(foo == 0)
  2314.             continue;
  2315.         dhdr = mallocw(sizeof(struct dhdr));
  2316.         ntohdomain(dhdr,&bp);
  2317.     if(Dtrace) {
  2318.         tprintf("DNS: %u bytes from %s\n",foo,
  2319.         psocket((struct sockaddr *)&from));
  2320.         dumpdomain(dhdr,0);
  2321.     }
  2322.     /* Process queries only */
  2323.     if(dhdr->qr == QUERY) {
  2324.         /* Queries from ourself will cause a loop ! */
  2325.         if(ismyaddr(from.sin_addr.s_addr) != NULLIF) {
  2326.         if(Dtrace)
  2327.             tputs("DNS: question from myself ignored\n");
  2328.         free_dhdr(dhdr);
  2329.         continue;
  2330.         } else {
  2331.         dp=(struct dserver *)callocw(1,sizeof(struct dserver));
  2332.         dp->address = from.sin_addr.s_addr;
  2333.         dp->srtt = (Dserver_maxwait * 1000L) / MSPTICK;
  2334.         dp->timeout = dp->srtt * 2;
  2335.         dp->port = from.sin_port;
  2336.         if(dhdr->opcode == ZONEINIT) {
  2337.             /* ZONEINIT not implemented */
  2338.             free_dhdr(dhdr);
  2339.             free(dp);
  2340.          } else
  2341.             newproc("Domain server",1024,proc_query
  2342.                 ,0,(void *)dp,(void *)dhdr,0);
  2343.             }
  2344.         }
  2345.     }
  2346. }
  2347.                 
  2348. static int
  2349. dodnsserver(argc,argv,p)
  2350. int argc;
  2351. char *argv[];
  2352. void *p;
  2353. {
  2354.     struct DOM_FILE *t_dom_file;
  2355.     FILE *fp, *bfp;
  2356.     char *t, *t1, *t2,*t3, *t4;
  2357.     int done;
  2358.     int32 source;
  2359.     struct rr *frrp, *oldrrp;
  2360. #if    0
  2361.     struct soa *soap;
  2362. #endif
  2363.     char type, *delim = " \t";
  2364.     if(Drx == NULLPROC)
  2365.         {
  2366.         /* Get rid of any old data */
  2367.         t_dom_file = dom_file;
  2368.         while (t_dom_file)
  2369.             {
  2370.             free(t_dom_file->filename);
  2371.             free(t_dom_file->domain);
  2372.             free(t_dom_file);
  2373.             t_dom_file = t_dom_file->next;
  2374.             }
  2375.         dom_file = NULL;
  2376.         /*
  2377.         Find out where we're primary for (if anywhere)
  2378.         */
  2379.         t = mallocw(200);
  2380.         t2 = mallocw(200);
  2381.         t4 = mallocw(13);
  2382.         bfp = fopen(Dboot, READ_TEXT);
  2383.         if (bfp)
  2384.             while (1)
  2385.                 {
  2386.                 if (feof(bfp) || !fgets(t, 199, bfp))
  2387.                     {
  2388.                     fclose(bfp);
  2389.                     break;
  2390.                     }
  2391.                 t1 = strtok(t, delim);
  2392.                 if (!t1)
  2393.                     continue;
  2394.                 source = 0;
  2395.                 type = '0';
  2396.                 if (stricmp(t1, "primary") == 0)
  2397.                     type = '1';
  2398.                 if (stricmp(t1, "secondary") == 0)
  2399.                     type = '2';
  2400.                 if (type == '0')
  2401.                     continue;
  2402.                 t1 = strtok(NULL, delim);
  2403.                 if (!t1)
  2404.                     continue;
  2405.                 strlwr(t1);
  2406.                 strcpy(t2, t1);
  2407.                 t1 = strtok(NULL, delim);
  2408.                 if (!t1)
  2409.                     continue;
  2410.                 if (type == '2')
  2411.                     {
  2412.                     source = resolve(t1);
  2413.                     t1 = strtok(NULL, delim);
  2414.                     if (!t1)
  2415.                         continue;
  2416.                     }
  2417.                 rip(t1);
  2418.                 strcpy(t4, t1);
  2419.                 sprintf(t, "%s/%s", Dzones, t1);
  2420.                 t3 = t - 1;
  2421.                 while (*++t3)
  2422.                     if (*t3 == '\\')
  2423.                         *t3 = '/';
  2424.                 if (Dtrace)
  2425.                     tprintf("DNS: Looking for SOA record in %s\n", t);
  2426.                 fp = fopen(t, READ_TEXT);
  2427.                 if (fp)
  2428.                     {
  2429.                     done = 0;
  2430.                     oldrrp = NULLRR;
  2431.                     while(done == 0
  2432.                         && (frrp = get_rr(fp,oldrrp)) != NULLRR)
  2433.                         {
  2434.                         oldrrp = frrp;
  2435.                         if (frrp->type == TYPE_SOA)
  2436.                             {
  2437.                             done = 1;
  2438.                             if (dom_file == NULL)
  2439.                                 {
  2440.                                 dom_file = mallocw(sizeof(struct DOM_FILE));
  2441.                                 dom_file->next = NULL;
  2442.                                 }
  2443.                             else {
  2444.                                 t_dom_file = mallocw(sizeof(struct DOM_FILE));
  2445.                                 t_dom_file->next = dom_file;
  2446.                                 dom_file = t_dom_file;
  2447.                                 }
  2448.                             dom_file->filename = mallocw(13);
  2449.                             strcpy(dom_file->filename, t4);
  2450.                             dom_file->domain = mallocw(strlen(t2) + 2);
  2451.                             sprintf(dom_file->domain, "%s.", t2);
  2452.                             dom_file->dom_soa = frrp->rdata.soa;
  2453.                             dom_file->type = type;
  2454.                             dom_file->source = source;
  2455.                             if (Dtrace)
  2456.                                 {
  2457.                                 tprintf(" filename %s\n", dom_file->filename);
  2458.                                 tprintf(" mname %s\n", dom_file->dom_soa.mname);
  2459.                                 tprintf(" rname %s\n", dom_file->dom_soa.rname);
  2460.                                 tprintf(" serial %lu\n", dom_file->dom_soa.serial);
  2461.                                 tprintf(" refresh %lu\n", dom_file->dom_soa.refresh);
  2462.                                 tprintf(" retry %lu\n", dom_file->dom_soa.retry);
  2463.                                 tprintf(" expire %lu\n", dom_file->dom_soa.expire);
  2464.                                 tprintf(" minimum %lu\n", dom_file->dom_soa.minimum);
  2465.                                 }
  2466.                             }
  2467.                         }
  2468.                     fclose(fp);
  2469.                     }
  2470.                 else tprintf("failed to open\n");
  2471.                 }
  2472.     /* Start domain server task */
  2473.         free(t4);
  2474.         free(t2);
  2475.         free(t);
  2476.     Drx = newproc("Domain listener",1024,drx,0,NULL,NULL,0);
  2477.         }
  2478.     else tputs("DNS already running\n");
  2479.     return 0;
  2480. }
  2481.  
  2482. static int
  2483. dostopdnsserver(argc,argv,p)
  2484. int argc;
  2485. char *argv[];
  2486. void *p;
  2487. {
  2488.     if(Drx == NULLPROC)
  2489.     /* Start domain server task */
  2490.     tprintf("DNS not running\n");
  2491.     killproc(Drx);
  2492.     Drx = NULLPROC;
  2493.     return 0;
  2494. }
  2495.  
  2496. /* Free a domain message */
  2497. static void
  2498. free_dhdr(dp)
  2499. struct dhdr *dp;
  2500. {
  2501.     if(dp->qdcount != 0)
  2502.     free_rr(dp->questions);
  2503.     if(dp->ancount != 0)
  2504.     free_rr(dp->answers);
  2505.     if(dp->nscount != 0)
  2506.     free_rr(dp->authority);
  2507.     if(dp->arcount != 0)
  2508.     free_rr(dp->additional);
  2509.     free((char *)dp);
  2510. }
  2511.  
  2512. #endif
  2513.