home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / telecomm / nhclb120 / domain.c < prev    next >
C/C++ Source or Header  |  1993-09-26  |  24KB  |  1,122 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <time.h>
  4. #if defined(UNIX) || defined(GNUC)
  5. #include <string.h>
  6. #endif
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "netuser.h"
  10. #include "timer.h"
  11. #include "udp.h"
  12. #include "cmdparse.h"
  13. #include "domain.h"
  14.  
  15.  
  16. #ifndef _STRING_H
  17. char *strchr(), strrchr(), *strdup();
  18. #endif
  19.  
  20. void drx(),drx_init();
  21. extern int errno;
  22. extern int32 Ip_addr;
  23.  
  24. struct rr *Rrlist[NRLIST];
  25. struct dserver *Dlist;        /* List of potential servers */
  26. struct dserver *Dserver;    /* Current one being used */
  27. char *Dsuffix;            /* Default suffix for names without periods */
  28. struct socket Dsocket;        /* Socket to use for domain queries */
  29. int Dsignal;
  30. int Drx;            /* Drx started? */
  31. int Ddebug = 0;
  32. char *Dtypes[] = {
  33.     "",
  34.     "A",
  35.     "NS",
  36.     "MD",
  37.     "MF",
  38.     "CNAME",
  39.     "SOA",
  40.     "MB",
  41.     "MG",
  42.     "MR",
  43.     "NULL",
  44.     "WKS",
  45.     "PTR",
  46.     "HINFO",
  47.     "MINFO",
  48.     "MX",
  49.     "TXT"
  50. };
  51. int Ndtypes = 17;
  52. static char delim[] = " \t\r\n";
  53. static struct {
  54.     char *name;
  55.     int32 address;
  56. } cache;
  57.  
  58. struct cmds Dcmds[] = {
  59.     "addserver",    doadds,        0, 0, NULLCHAR,
  60.     "dropserver",    dodropds,    0, 0, NULLCHAR,
  61.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  62.     "trace",    dodtrace,    0, 0, NULLCHAR,
  63.     NULLCHAR,    NULLFP,        0, 0, "domain subcommands: addserver dropserver suffix trace",
  64. };
  65. int
  66. dodtrace(argc,argv)
  67. int argc;
  68. char *argv[];
  69. {
  70.     if(argc < 2){
  71.         printf("Domain trace: %s\n",Ddebug ? "On" : "Off");
  72.     } else {
  73.         if(strcmp(argv[1],"on") == 0)
  74.             Ddebug = 1;
  75.         else
  76.             Ddebug = 0;
  77.     }
  78.     return 0;
  79. }
  80. int
  81. dodomain(argc,argv,envp)
  82. int argc;
  83. char *argv[];
  84. char *envp;
  85. {
  86.     return subcmd(Dcmds,argc,argv,envp);    
  87. }
  88. int
  89. dosuffix(argc,argv)
  90. int argc;
  91. char *argv[];
  92. {
  93.     if(argc < 2){
  94.         if(Dsuffix != NULLCHAR)
  95.             printf("%s\n",Dsuffix);
  96.         return 0;
  97.     }
  98.     free(Dsuffix);
  99.     Dsuffix = strdup(argv[1]);
  100.     return 0;
  101. }
  102. int
  103. doadds(argc,argv)
  104. int argc;
  105. char *argv[];
  106. {
  107.     struct dserver *dp;
  108.     int32 address;
  109.  
  110.     if((address = resolve(argv[1])) == 0){
  111.         printf("Resolver %s unknown\n",argv[1]);
  112.         return 1;
  113.     }
  114.     dp = (struct dserver *)calloc(1,sizeof(struct dserver));
  115.     dp->address = address;
  116.     dp->srtt = 5L;
  117.     dp->timeout = dp->srtt * 2;
  118.     dp->mdev = 0;
  119.     dp->next = Dlist;
  120.     if(dp->next != NULLDOM)
  121.         dp->next->prev = dp;
  122.     Dlist = dp;
  123.     Dserver = dp;    /* Make this the first one we try next */
  124.     if(Drx == 0){
  125.         /* Start domain task upon first addserver */
  126.         drx_init();
  127.         Drx = 1;
  128.     }
  129.     return 0;
  130. }
  131. int
  132. dodropds(argc,argv)
  133. int argc;
  134. char *argv[];
  135. {
  136.     struct dserver *dp;
  137.     int32 addr;
  138.  
  139.     addr = resolve(argv[1]);
  140.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  141.         if(addr == dp->address)
  142.             break;
  143.  
  144.     if(dp == NULLDOM){
  145.         printf("Not found\n");
  146.         return 1;
  147.     }
  148.     if(dp->prev != NULLDOM)
  149.         dp->prev->next = dp->next;
  150.     else
  151.         Dlist = dp->next;
  152.     if(dp->next != NULLDOM)
  153.         dp->next->prev = dp->prev;
  154.  
  155.     if(Dserver == dp)
  156.         Dserver = Dlist;
  157.     free((char *)dp);
  158.     return 0;
  159. }
  160.  
  161. /* Search local domain file for resource record of specified type.
  162.  * If a record is found, the domain file pointer is left just after it. If
  163.  * not, the file is rewound.
  164.  */
  165. static struct rr *
  166. dfind(dbase,name,type)
  167. FILE *dbase;
  168. char *name;
  169. int type;
  170. {
  171.     struct rr *rrp;
  172.     int nlen;
  173.  
  174.     /* Search file */
  175.     while((rrp = getrr(dbase)) != NULLRR){
  176.         if((nlen = strlen(name)) == strlen(rrp->name)
  177.          && strncasecmp(name,rrp->name,nlen) == 0
  178.          && rrp->class == CLASS_IN
  179.          && rrp->type == type)
  180.             break;
  181.         free_rr(rrp);
  182. /*        pwait(NULL);    /* Give up CPU for a while, this is slow */
  183.     }
  184.     if(rrp == NULLRR)
  185.         rewind(dbase);
  186.     return rrp;
  187. }
  188. static struct rr *
  189. getrr(fp)
  190. FILE *fp;
  191. {
  192.     char *line,*strtok();
  193.     struct rr *rrp;
  194.     char *name,*ttl,*class,*type,*data;
  195.     int i;
  196.  
  197.     line = malloc(256);
  198.     /* Search file */
  199.     while(fgets(line,256,fp),!feof(fp)){
  200.         if(line[0] != '#')
  201.             break;
  202.     }
  203.     if(feof(fp) || (rrp = (struct rr *)calloc(1,sizeof(struct rr))) == NULLRR){
  204.         free(line);
  205.         return NULLRR;
  206.     }
  207.     name = strtok(line,delim);
  208.     ttl = strtok(NULLCHAR,delim);
  209.     class = strtok(NULLCHAR,delim);
  210.     type = strtok(NULLCHAR,delim);
  211.     data = strtok(NULLCHAR,delim);
  212.     
  213.     rrp->name = strdup(name);
  214.     if(!isdigit(ttl[0])){
  215.       /* Optional ttl field is missing; slide the other fields over */
  216.       data = type;
  217.       type = class;
  218.       class = ttl;
  219.       ttl = NULLCHAR;
  220.     } else {
  221.         rrp->ttl = atol(ttl);
  222.     }
  223.     for(i=0;i<NRLIST;i++){
  224.         if(strcmp(type,Dtypes[i]) == 0){
  225.             rrp->type = i;
  226.             break;
  227.         }
  228.     }
  229.     if(strcmp(class,"IN") == 0)
  230.         rrp->class = CLASS_IN;
  231.  
  232.     if(data == NULLCHAR){
  233.         /* Empty record, just return */
  234.         free(line);
  235.         return rrp;
  236.     }
  237.     switch(rrp->type){
  238.     case TYPE_CNAME:
  239.     case TYPE_MB:
  240.     case TYPE_MG:
  241.     case TYPE_MR:
  242.     case TYPE_NS:
  243.     case TYPE_PTR:
  244.     case TYPE_TXT:
  245.         rrp->rdlength = strlen(data);
  246.         rrp->rdata.name = strdup(data);
  247.         break;
  248.     case TYPE_A:
  249.         rrp->rdlength = 4;
  250.         rrp->rdata.addr = aton(data);
  251.         break;
  252.     case TYPE_HINFO:
  253.         rrp->rdlength = strlen(data);
  254.         rrp->rdata.hinfo.cpu = strdup(data);
  255.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  256.             rrp->rdlength += strlen(data);
  257.             rrp->rdata.hinfo.os = strdup(data);
  258.         }
  259.         break;
  260.     case TYPE_MX:
  261.         rrp->rdata.mx.pref = atoi(data);
  262.         rrp->rdlength = 2;
  263.  
  264.         /* Get domain name of exchanger */
  265.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  266.             rrp->rdlength += strlen(data);
  267.             rrp->rdata.mx.exch = strdup(data);
  268.         }
  269.         break;
  270.     case TYPE_SOA:
  271.         /* Get domain name of master name server */
  272.         rrp->rdlength = strlen(data);
  273.         rrp->rdata.soa.mname = strdup(data);
  274.  
  275.         /* Get domain name of irresponsible person */
  276.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  277.             rrp->rdata.soa.rname = strdup(data);
  278.             rrp->rdlength += strlen(data);
  279.         }
  280.         data = strtok(NULLCHAR,delim);
  281.         rrp->rdata.soa.serial = atol(data);
  282.         data = strtok(NULLCHAR,delim);
  283.         rrp->rdata.soa.refresh = atol(data);
  284.         data = strtok(NULLCHAR,delim);
  285.         rrp->rdata.soa.retry = atol(data);
  286.         data = strtok(NULLCHAR,delim);
  287.         rrp->rdata.soa.expire = atol(data);
  288.         data = strtok(NULLCHAR,delim);
  289.         rrp->rdata.soa.minimum = atol(data);
  290.         rrp->rdlength += 20;
  291.         break;
  292.     }
  293.     free(line);
  294.     return rrp;
  295. }
  296. /* Search for address record in local database, looking first for PTR
  297.  * and CNAME records. Return values:
  298.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  299.  *  0        Domain name definitely doesn't exist (we have a null record)
  300.  */
  301. int32
  302. dresolve(name)
  303. char *name;
  304. {
  305.     register struct rr *rrp;
  306.     char *pname = NULLCHAR;
  307.     char *cname = NULLCHAR;
  308.     int32 result;
  309.     FILE *dbase;
  310.  
  311.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  312.         return cache.address;
  313.  
  314.     if((dbase = fopen(Dfile,"r")) == NULLFILE)
  315.         return 0xffffffff;
  316.  
  317.     /* This code can handle a few weird cases. It works when there's
  318.      * a PTR to a CNAME to an A record, as well as when there's a
  319.      * a CNAME to a PTR to an A. But it allows only one of each kind
  320.      * of indirection to prevent infinite loops.
  321.      */
  322.     while((rrp = dfind(dbase,name,TYPE_A)) == NULLRR){
  323.         /* An address record didn't exist, let's see if it's an alias */
  324.         if(cname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_CNAME)) != NULLRR){
  325.             if((cname = strdup(rrp->rdata.name)) == NULLCHAR)
  326.                 break;
  327.             name = cname;
  328.             rewind(dbase);
  329.             free_rr(rrp);
  330.             continue;    /* Try again */
  331.         }
  332.         /* Lacking that, try a pointer entry... */
  333.         if(pname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_PTR)) != NULLRR){
  334.             if((pname = strdup(rrp->rdata.name)) == NULLCHAR)
  335.                 break;
  336.             name = pname;
  337.             rewind(dbase);
  338.             free_rr(rrp);
  339.             continue;
  340.         }
  341.         /* Nope, nothing. Give up */
  342.         break;
  343.     }
  344.     fclose(dbase);
  345.     free(pname);
  346.     free(cname);    
  347.  
  348.     if(rrp == NULLRR){
  349.         result = 0xffffffff;        /* No record in database */
  350.     } else {
  351.         if(rrp->rdlength == 0)
  352.             result = 0;        /* Negative response record */
  353.         else
  354.             result = rrp->rdata.addr;    /* Normal return */
  355.         free(cache.name);
  356.         cache.name = strdup(name);
  357.         cache.address = result;
  358.         free_rr(rrp);
  359.     }
  360.     return result;
  361. }
  362. static int numeric_only(char *name)
  363. {
  364.   /* return true if name in in form nnn.nnn.nnn.nnn, where n is 0-9 */
  365.  if(name == (char *) 0  || *name =='\0' ) return(0);
  366.   while( *name ){
  367.     if(*name == '.' || isdigit(*name))  { name++; continue; } 
  368.     return(0);
  369.   }
  370.   return (-1);
  371. }
  372.  
  373. /* Main entry point for domain name -> address resolution. Returns 0 if
  374.  * name is definitely not valid.
  375.  */
  376. int32
  377. resolve(name)
  378. char *name;
  379. {
  380.     char *buf;
  381.     int32 addr;
  382.     struct dserver *dp;
  383.     struct mbuf *bp;
  384.     int len;
  385.     struct socket server;
  386.     char *tname = NULLCHAR;
  387.     char *pname = NULLCHAR;
  388.     time_t now, starttime, mainstart;
  389.     if(name == NULLCHAR)
  390.         return 0;
  391.  
  392.     if(*name == '[')
  393.         return aton(name + 1);
  394.     if(numeric_only(name))  return(aton(name));
  395.     if(strchr(name,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  396.         /* Append default suffix */
  397.         tname = malloc(strlen(name)+strlen(Dsuffix)+2);
  398.         sprintf(tname,"%s.%s",name,Dsuffix);
  399.         name = tname;
  400.     }
  401.     if(name[strlen(name)-1] != '.'){
  402.         /* Append trailing dot */
  403.         pname = malloc(strlen(name)+2);
  404.         sprintf(pname,"%s.",name);
  405.         name = pname;
  406.     }
  407.     dp = Dserver;
  408.     time(&mainstart);
  409.     while((addr = dresolve(name)) == 0xffffffff){
  410.         if(dp == NULLDOM){
  411.             addr = 0;    /* Unknown, and no servers */
  412.             break;
  413.         }
  414.         /* Not in file, send query */
  415.  
  416.         if ((bp = alloc_mbuf(512)) == NULL) {
  417.             addr = 0;    /* Unknown, and no servers */
  418.             break;
  419.         }
  420.         len = res_mkquery(0,name,CLASS_IN,TYPE_A,NULLCHAR,
  421.                   0,0,bp->data,512);
  422.         bp->cnt = len;
  423.         server.port = IPPORT_DOMAIN;
  424.         server.address = dp->address;
  425.         Dsignal = 0;
  426.         send_udp(&Dsocket,&server,0,0,bp,len,0,0);
  427.  
  428.         time(&starttime);
  429.         /* Wait for something to happen */
  430.         for (;;) {
  431.             keep_things_going();
  432.             if (Dsignal)
  433.                 break;
  434.             time(&now);
  435.             if (now - starttime >= dp->timeout)
  436.                 break;
  437.         }
  438.         if (! Dsignal) {
  439.             if (now - mainstart > 30) {
  440.                 addr = 0;
  441.                 break;
  442.             } else {
  443.             /* Timeout; back off this one and try another server */
  444.                 dp->timeout <<= 1;
  445.                 if((dp = dp->next) == NULLDOM)
  446.                     dp = Dlist;
  447.             }
  448.         } 
  449.     }
  450. quit:    free(tname);
  451.     free(pname);
  452.     return addr;
  453. }
  454. static int
  455. res_mkquery(op,dname,class,type,data,datalen,newrr,buffer,buflen)
  456. int op;    /* operation */
  457. char *dname;    /* Domain name */
  458. int class;    /* Class of inquiry (IN, etc) */
  459. int type;    /* Type of inquiry (A, MX, etc) */
  460. char *data;
  461. int datalen;
  462. int newrr;
  463. char *buffer;    /* Area for query */
  464. int buflen;    /* Length of same */
  465. {
  466.     char *cp,*cp1;
  467.     int16 parameter;
  468.     int16 dlen,len;
  469.     time_t now;
  470.  
  471.     cp = buffer;
  472.     time(&now);
  473.     cp = put16(cp,now);    /* Use clock for timestamping */
  474.     parameter = 0x100;    /* Recursion desired */
  475.     cp = put16(cp,parameter);
  476.     cp = put16(cp,1);
  477.     cp = put16(cp,0);
  478.     cp = put16(cp,0);
  479.     cp = put16(cp,0);
  480.     dlen = strlen(dname);
  481.     for(;;){
  482.         /* Look for next dot */
  483.         cp1 = strchr(dname,'.');
  484.         if(cp1 != NULLCHAR)
  485.             len = cp1-dname;    /* More to come */
  486.         else
  487.             len = dlen;    /* Last component */
  488.         *cp++ = len;        /* Write length of component */
  489.         if(len == 0)
  490.             break;
  491.         /* Copy component up to (but not including) dot */
  492.         strncpy(cp,dname,len);
  493.         cp += len;
  494.         if(cp1 == NULLCHAR){
  495.             *cp++ = 0;    /* Last one; write null and finish */
  496.             break;
  497.         }
  498.         dname += len+1;
  499.         dlen -= len+1;
  500.     }
  501.     cp = put16(cp,type);
  502.     cp = put16(cp,class);
  503.     return cp - buffer;
  504. }
  505. /* Convert a compressed domain name to the human-readable form */
  506. static int
  507. dn_expand(msg,eom,compressed,full,fullen)
  508. char *msg;        /* Complete domain message */
  509. char *eom;
  510. char *compressed;    /* Pointer to compressed name */
  511. char *full;        /* Pointer to result buffer */
  512. int fullen;        /* Length of same */
  513. {
  514.     unsigned int slen;    /* Length of current segment */
  515.     register char *cp;
  516.     unsigned int clen = 0;    /* Total length of compressed name */
  517.     int indirect = 0;    /* Set if indirection encountered */
  518.     int nseg = 0;        /* Total number of segments in name */
  519.  
  520.     cp = compressed;
  521.     for(;;){
  522.         slen = uchar(*cp++);    /* Length of this segment */
  523.         if(!indirect)
  524.             clen++;
  525.         if((slen & 0xc0) == 0xc0){
  526.             if(!indirect)
  527.                 clen++;
  528.             indirect = 1;
  529.             /* Follow indirection */
  530.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  531.             slen = uchar(*cp++);
  532.         }
  533.         if(slen == 0)    /* zero length == all done */
  534.             break;
  535.         fullen -= slen + 1;
  536.         if(fullen < 0)
  537.             return -1;
  538.         if(!indirect)
  539.             clen += slen;
  540.         while(slen-- != 0)
  541.             *full++ = *cp++;
  542.         *full++ = '.';
  543.         nseg++;
  544.     }
  545.     if(nseg == 0){
  546.         /* Root name; represent as single dot */
  547.         *full++ = '.';
  548.         fullen--;
  549.     }
  550.     *full++ = '\0';
  551.     fullen--;
  552.     return clen;    /* Length of compressed message */
  553. }
  554.  
  555. void
  556. drx_init()
  557. {
  558.     Dsocket.address = ip_addr;
  559.     Dsocket.port = IPPORT_DOMAIN;
  560.     open_udp(&Dsocket, drx);
  561. }
  562.  
  563. /* Process to receive all domain server replies */
  564. void
  565. drx(sock,cnt)
  566. struct socket *sock;
  567. int16 cnt;
  568. {
  569.     struct mbuf *bp;
  570.     struct socket fsock;
  571.     struct dserver *dp,*dslookup();
  572.     int foo;
  573.  
  574.     recv_udp(sock,&fsock,&bp);
  575.     if(Ddebug)
  576.     printf("domain: from %s\n", psocket(&fsock));
  577.     if((dp = dslookup(fsock.address)) == NULLDOM){
  578.         /* Unknown server */
  579.         if(Ddebug)
  580.             printf("Unknown domain server!\n");
  581.         return;
  582.     }
  583.     Dserver = dp;    /* We know this one is good */
  584.     proc_answer(dp,bp);
  585. }
  586.  
  587. static void
  588. proc_answer(dp,bp)
  589. struct dserver *dp;
  590. struct mbuf *bp;
  591. {
  592.     FILE *fp;
  593.     struct dhdr dhdr;
  594.     int i;
  595.     int16 rtt;
  596.     long ttl = 500;    /* Default TTL for negative records without SOA */
  597.     struct rr *rrp;
  598.     struct quest *qp;
  599.     time_t now;
  600.  
  601.     ntohdomain(&dhdr,&bp);
  602.  
  603.     /* Compute and update the round trip time */
  604.     time(&now);
  605.     rtt = now - dhdr.id;
  606.     dp->srtt = (7 * dp->srtt + rtt) >> 3;
  607.     dp->timeout = 2*dp->srtt;
  608.  
  609.     if(Ddebug){
  610.         printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  611.          dhdr.id,((long)rtt * MSPTICK)/1000,
  612.          dhdr.qr,dhdr.opcode,dhdr.aa,dhdr.tc,dhdr.rd,
  613.          dhdr.ra,dhdr.rcode);
  614.         printf("%u questions:\n",dhdr.qdcount);
  615.         for(i=0;i< dhdr.qdcount;i++){
  616.             qp = dhdr.qlist[i];
  617.             printf("%s type %u class %u\n",qp->qname,
  618.              qp->qtype,qp->qclass);
  619.         }
  620.     }
  621.     if(dhdr.qr == QUERY){
  622.         /* A server will eventually go here. */
  623.         free_dhdr(&dhdr);
  624.         return;
  625.     }
  626.     fp = fopen(Dfile,"r+");
  627.     if (fp == NULLFILE)
  628.         fp = fopen(Dfile,"w+");
  629.     if(fp == NULLFILE){
  630.         printf("Can't write %s!!\n",Dfile);
  631.         free_dhdr(&dhdr);
  632.         return;
  633.     }
  634.     if(Ddebug)
  635.         printf("%u answers:\n",dhdr.ancount);
  636.     for(i=0;i< dhdr.ancount;i++){
  637.         rrp = dhdr.ans[i];
  638.         if(Ddebug)
  639.             putrr(stdout,rrp);
  640.         if(rrp->type == TYPE_SOA)
  641.             ttl = rrp->ttl;
  642.         addit(fp,rrp);
  643.     }
  644.     if(Ddebug)
  645.         printf("%u authority:\n",dhdr.nscount);
  646.     for(i=0;i< dhdr.nscount;i++){
  647.         rrp = dhdr.ns[i];
  648.         if(Ddebug){
  649.             putrr(stdout,rrp);
  650.             fflush(stdout);
  651.         }
  652.         if(rrp->type == TYPE_SOA)
  653.             ttl = rrp->ttl;
  654.         addit(fp,rrp);
  655.     }
  656.     if(Ddebug)
  657.         printf("%u additional:\n",dhdr.arcount);
  658.     for(i=0;i< dhdr.arcount;i++){
  659.         rrp = dhdr.add[i];
  660.         if(Ddebug){
  661.             putrr(stdout,rrp);
  662.             fflush(stdout);
  663.         }
  664.         if(rrp->type == TYPE_SOA)
  665.             ttl = rrp->ttl;
  666.         addit(fp,rrp);
  667.     }
  668.     if(dhdr.aa && (dhdr.rcode == NAME_ERROR || dhdr.ancount == 0)){
  669.         /* Add negative reply to file. This assumes that there was
  670.          * only one question, which is true for all questions we send.
  671.          */
  672.         qp = dhdr.qlist[0];
  673.         rrp = (struct rr *)calloc(1,sizeof(struct rr));
  674.         rrp->name = strdup(qp->qname);
  675.         rrp->type = qp->qtype;
  676.         rrp->class = qp->qclass;
  677.         rrp->ttl = ttl;
  678.         rrp->rdlength = 0;    /* no data */
  679.         addit(fp,rrp);
  680.         free_rr(rrp);
  681.     }
  682.     fclose(fp);
  683.     free_dhdr(&dhdr);
  684.     Dsignal = 1;    /* Alert anyone waiting for results */
  685. }
  686. static int
  687. ntohdomain(dhdr,bpp)
  688. struct dhdr *dhdr;
  689. struct mbuf **bpp;
  690. {
  691.     int16 tmp,len,i;
  692.     char *msg,*cp;
  693.  
  694.     len = len_mbuf(*bpp);
  695.     msg = malloc(len);
  696.     pullup(bpp,msg,len);
  697.     memset((char *)dhdr,0,sizeof(*dhdr));
  698.  
  699.         dhdr->id = get16(&msg[0]);
  700.     tmp = get16(&msg[2]);
  701.     if(tmp & 0x8000)
  702.         dhdr->qr = 1;
  703.     dhdr->opcode = (tmp >> 11) & 0xf;
  704.     if(tmp & 0x0400)
  705.         dhdr->aa = 1;
  706.     if(tmp & 0x0200)
  707.         dhdr->tc = 1;
  708.     if(tmp & 0x0100)
  709.         dhdr->rd = 1;
  710.     if(tmp & 0x0080)
  711.         dhdr->ra = 1;
  712.     dhdr->rcode = tmp & 0xf;
  713.     dhdr->qdcount = get16(&msg[4]);
  714.     dhdr->ancount = get16(&msg[6]);
  715.     dhdr->nscount = get16(&msg[8]);
  716.     dhdr->arcount = get16(&msg[10]);
  717.  
  718.     /* Now parse the variable length sections */
  719.     cp = &msg[12];
  720.  
  721.     /* Question section */
  722.     if(dhdr->qdcount != 0)
  723.         dhdr->qlist = (struct quest **)malloc(dhdr->qdcount *
  724.          sizeof(struct quest *));
  725.     for(i=0;i<dhdr->qdcount;i++){
  726.         dhdr->qlist[i] = (struct quest *)malloc(sizeof(struct quest));
  727.         if((cp = getq(dhdr->qlist[i],msg,cp)) == NULLCHAR){
  728.             free(msg);
  729.             return -1;
  730.         }
  731.     }
  732.     /* Answer section */
  733.     if(dhdr->ancount != 0)
  734.         dhdr->ans = (struct rr **)malloc(dhdr->ancount *
  735.          sizeof(struct rr *));
  736.     for(i=0;i<dhdr->ancount;i++){
  737.         dhdr->ans[i] = (struct rr *)malloc(sizeof(struct rr));
  738.         if((cp = ntohrr(dhdr->ans[i],msg,cp)) == NULLCHAR){
  739.             free(msg);
  740.             return -1;
  741.         }
  742.     }        
  743.     /* Name server (authority) section */
  744.     if(dhdr->nscount != 0)
  745.         dhdr->ns = (struct rr **)malloc(dhdr->nscount *
  746.          sizeof(struct rr *));
  747.     for(i=0;i<dhdr->nscount;i++){
  748.         dhdr->ns[i] = (struct rr *)malloc(sizeof(struct rr));
  749.         if((cp = ntohrr(dhdr->ns[i],msg,cp)) == NULLCHAR){
  750.             free(msg);
  751.             return -1;
  752.         }
  753.     }
  754.     /* Additional section */
  755.     if(dhdr->arcount != 0)
  756.         dhdr->add = (struct rr **)malloc(dhdr->arcount *
  757.          sizeof(struct rr *));
  758.     for(i=0;i<dhdr->arcount;i++){
  759.         dhdr->add[i] = (struct rr *)malloc(sizeof(struct rr));
  760.         if((cp = ntohrr(dhdr->add[i],msg,cp)) == NULLCHAR){
  761.             free(msg);
  762.             return -1;
  763.         }
  764.     }
  765.     free(msg);
  766. }
  767. static char *
  768. getq(qp,msg,cp)
  769. struct quest *qp;
  770. char *msg;
  771. char *cp;
  772. {
  773.     int len;
  774.     char *name;
  775.  
  776.     name = malloc(512);
  777.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  778.     if(len == -1){
  779.         free(name);
  780.         return NULLCHAR;
  781.     }
  782.     cp += len;
  783.     qp->qname = strdup(name);
  784.     qp->qtype = get16(cp);
  785.     cp += 2;
  786.     qp->qclass = get16(cp);
  787.     cp += 2;
  788.     free(name);
  789.     return cp;
  790. }
  791. /* Read a resource record from a domain message into a host structure */
  792. static char *
  793. ntohrr(rrp,msg,cp)
  794. struct rr *rrp;    /* Pointer to allocated resource record structure */
  795. char *msg;    /* Pointer to beginning of domain message */
  796. char *cp;    /* Pointer to start of encoded RR record */
  797. {
  798.     int len;
  799.     char *name;
  800.  
  801.     if((name = malloc(512)) == NULLCHAR)
  802.         return NULLCHAR;
  803.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  804.         free(name);
  805.         return NULLCHAR;
  806.     }
  807.     cp += len;
  808.     rrp->name = strdup(name);
  809.     rrp->type = get16(cp);
  810.     cp += 2;
  811.     rrp->class = get16(cp);
  812.     cp+= 2;
  813.     rrp->ttl = get32(cp);
  814.     cp += 4;
  815.     rrp->rdlength = get16(cp);
  816.     cp += 2;
  817.     switch(rrp->type){
  818.     case TYPE_CNAME:
  819.     case TYPE_MB:
  820.     case TYPE_MG:
  821.     case TYPE_MR:
  822.     case TYPE_NS:
  823.     case TYPE_PTR:
  824.         /* These types all consist of a single domain name;
  825.          * convert it to ascii format
  826.          */
  827.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  828.         if(len == -1){
  829.             free(name);
  830.             return NULLCHAR;
  831.         }
  832.         rrp->rdata.name = strdup(name);
  833.         cp += len;
  834.         break;
  835.     case TYPE_A:
  836.         /* Just read the address directly into the structure */
  837.         rrp->rdata.addr = get32(cp);
  838.         cp += 4;
  839.         break;
  840.     case TYPE_HINFO:
  841.         rrp->rdata.hinfo.cpu = strdup(cp);
  842.         cp += strlen(cp) + 1;
  843.  
  844.         rrp->rdata.hinfo.os = strdup(cp);
  845.         cp += strlen(cp) + 1;
  846.         break;
  847.     case TYPE_MX:
  848.         rrp->rdata.mx.pref = get16(cp);
  849.         cp += 2;
  850.         /* Get domain name of exchanger */
  851.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  852.         if(len == -1){
  853.             free(name);
  854.             return NULLCHAR;
  855.         }
  856.         rrp->rdata.mx.exch = strdup(name);
  857.         cp += len;
  858.         break;
  859.     case TYPE_SOA:
  860.         /* Get domain name of name server */
  861.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  862.         if(len == -1){
  863.             free(name);
  864.             return NULLCHAR;
  865.         }
  866.         rrp->rdata.soa.mname = strdup(name);
  867.         cp += len;
  868.  
  869.         /* Get domain name of responsible person */
  870.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  871.         if(len == -1){
  872.             free(name);
  873.             return NULLCHAR;
  874.         }
  875.         rrp->rdata.soa.rname = strdup(name);
  876.         cp += len;
  877.  
  878.         rrp->rdata.soa.serial = get32(cp);
  879.         cp += 4;
  880.         rrp->rdata.soa.refresh = get32(cp);
  881.         cp += 4;
  882.         rrp->rdata.soa.retry = get32(cp);
  883.         cp += 4;
  884.         rrp->rdata.soa.expire = get32(cp);
  885.         cp += 4;
  886.         rrp->rdata.soa.minimum = get32(cp);
  887.         cp += 4;
  888.         break;
  889.     case TYPE_TXT:
  890.         /* Just stash */
  891.         rrp->rdata.data = malloc(rrp->rdlength);
  892.         memcpy(rrp->rdata.data,cp,rrp->rdlength);
  893.         cp += rrp->rdlength;
  894.         break;
  895.     default:
  896.         /* Ignore */
  897.         cp += rrp->rdlength;
  898.         break;
  899.     }
  900.     free(name);
  901.     return cp;
  902. }
  903. /* Print a resource record */
  904. static void
  905. putrr(fp,rrp)
  906. FILE *fp;
  907. struct rr *rrp;
  908. {
  909.     if(fp == NULLFILE || rrp == NULLRR)
  910.         return;
  911.  
  912.     fprintf(fp,"%s\t%lu",rrp->name,rrp->ttl);
  913.     if(rrp->class == CLASS_IN)
  914.         fprintf(fp,"\tIN");
  915.     else
  916.         fprintf(fp,"\t%u",rrp->class);
  917.     if(rrp->type < Ndtypes)
  918.         fprintf(fp,"\t%s",Dtypes[rrp->type]);
  919.     else
  920.         fprintf(fp,"\t%u",rrp->type);
  921.     if(rrp->rdlength == 0){
  922.         /* Null data portion, indicates nonexistent record */
  923.         fprintf(fp,"\n");
  924.         return;
  925.     }
  926.     switch(rrp->type){
  927.     case TYPE_CNAME:
  928.     case TYPE_MB:
  929.     case TYPE_MG:
  930.     case TYPE_MR:
  931.     case TYPE_NS:
  932.     case TYPE_PTR:
  933.     case TYPE_TXT:
  934.         /* These are all printable text strings */
  935.         fprintf(fp,"\t%s\n",rrp->rdata.data);
  936.         break;
  937.     case TYPE_A:
  938.         fprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  939.         break;
  940.     case TYPE_MX:
  941.         fprintf(fp,"\t%u\t%s\n",rrp->rdata.mx.pref,
  942.          rrp->rdata.mx.exch);
  943.         break;
  944.     case TYPE_SOA:
  945.         fprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  946.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  947.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  948.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  949.          rrp->rdata.soa.minimum);
  950.         break;
  951.     default:
  952.         fprintf(fp,"\n");
  953.         break;
  954.     }
  955. }
  956. /* Add a record to the database only if it doesn't already exist */
  957. void
  958. addit(fp,rrp1)
  959. FILE *fp;
  960. struct rr *rrp1;
  961. {
  962.     register struct rr *rrp;
  963.  
  964.     rewind(fp);
  965.     while((rrp = dfind(fp,rrp1->name,rrp1->type)) != NULLRR){
  966.         if(rrcmp(rrp,rrp1) == 0){
  967.             free_rr(rrp);
  968.             return;
  969.         }
  970.         free_rr(rrp);
  971.     }
  972.     /*
  973.      * following rewind should not be needed, since it's immediately
  974.      * followed by fseek.  The fseek sometimes goes the wrong place
  975.      * without it.  Buggy Gnu iostream.
  976.      */
  977.     rewind(fp);
  978.     fseek(fp,0L,2);
  979.     putrr(fp,rrp1);
  980. }
  981. static struct dserver *
  982. dslookup(server)
  983. int32 server;
  984. {
  985.     struct dserver *dp;
  986.  
  987.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  988.         if(dp->address == server)
  989.             break;
  990.     return dp;
  991. }
  992. /* Free a domain message */
  993. static void
  994. free_dhdr(dp)
  995. struct dhdr *dp;
  996. {
  997.     int i;
  998.  
  999.     if(dp->qdcount != 0){
  1000.         for(i=0;i<dp->qdcount;i++)
  1001.             free_qu(dp->qlist[i]);
  1002.         free((char *)dp->qlist);
  1003.     }
  1004.     if(dp->ancount != 0){
  1005.         for(i=0;i<dp->ancount;i++)
  1006.             free_rr(dp->ans[i]);
  1007.         free((char *)dp->ans);
  1008.     }
  1009.     if(dp->nscount != 0){
  1010.         for(i=0;i<dp->nscount;i++)
  1011.             free_rr(dp->ns[i]);
  1012.         free((char *)dp->ns);
  1013.     }
  1014.     if(dp->arcount != 0){
  1015.         for(i=0;i<dp->arcount;i++)
  1016.             free_rr(dp->add[i]);
  1017.         free((char *)dp->add);
  1018.     }
  1019. }
  1020.  
  1021. /* Free a question record */
  1022. static void
  1023. free_qu(qp)
  1024. struct quest *qp;
  1025. {
  1026.     free(qp->qname);
  1027.     free((char *)qp);
  1028. }
  1029.  
  1030. /* Free a resource record */
  1031. static void
  1032. free_rr(rrp)
  1033. struct rr *rrp;
  1034. {
  1035.     if(rrp == NULLRR)
  1036.         return;
  1037.     free(rrp->name);
  1038.     if(rrp->rdlength != 0){
  1039.         switch(rrp->type){
  1040.         case TYPE_CNAME:
  1041.         case TYPE_MB:
  1042.         case TYPE_MG:
  1043.         case TYPE_MR:
  1044.         case TYPE_NS:
  1045.         case TYPE_PTR:
  1046.             free(rrp->rdata.name);
  1047.             break;
  1048.         case TYPE_A:
  1049.             break;    /* Nothing allocated in rdata section */
  1050.         case TYPE_HINFO:
  1051.             free(rrp->rdata.hinfo.cpu);
  1052.             free(rrp->rdata.hinfo.os);
  1053.             break;
  1054.         case TYPE_MX:
  1055.             free(rrp->rdata.mx.exch);
  1056.             break;
  1057.         case TYPE_SOA:
  1058.             free(rrp->rdata.soa.mname);
  1059.             free(rrp->rdata.soa.rname);
  1060.             break;
  1061.         case TYPE_TXT:
  1062.             free(rrp->rdata.data);
  1063.             break;
  1064.         }
  1065.     }
  1066.     free((char *)rrp);
  1067. }
  1068. /* Compare two resource records, returning 0 if equal, nonzero otherwise */
  1069. static int
  1070. rrcmp(rr1,rr2)
  1071. register struct rr *rr1,*rr2;
  1072. {
  1073.     int i;
  1074.  
  1075.     if(rr1 == NULLRR || rr2 == NULLRR)
  1076.         return -1;
  1077.     if((i = strlen(rr1->name)) != strlen(rr2->name))
  1078.         return 1;
  1079.     if((i = strncasecmp(rr1->name,rr2->name,i)) != 0)
  1080.         return i;
  1081.     if(rr1->type != rr2->type)
  1082.         return 2;
  1083.     if(rr1->class != rr2->class)
  1084.         return 3;
  1085.     /* Note: rdlengths are not compared because they vary depending
  1086.      * on the representation (ASCII or encoded) this record was
  1087.      * generated from.
  1088.      */
  1089.     switch(rr1->type){
  1090.     case TYPE_A:
  1091.         i = rr1->rdata.addr != rr2->rdata.addr;
  1092.         break;
  1093.     case TYPE_SOA:
  1094.         i = rr1->rdata.soa.serial != rr2->rdata.soa.serial;
  1095.         break;
  1096.     case TYPE_HINFO:
  1097.         i = strcmp(rr1->rdata.hinfo.cpu,rr2->rdata.hinfo.cpu) ||
  1098.             strcmp(rr1->rdata.hinfo.os,rr2->rdata.hinfo.os);
  1099.         break;
  1100.     case TYPE_MX:
  1101.         i = strcmp(rr1->rdata.mx.exch,rr2->rdata.mx.exch);
  1102.         break;
  1103.     case TYPE_MB:
  1104.     case TYPE_MG:
  1105.     case TYPE_MR:
  1106.     case TYPE_NULL:
  1107.     case TYPE_WKS:
  1108.     case TYPE_PTR:
  1109.     case TYPE_MINFO:
  1110.     case TYPE_TXT:
  1111.     case TYPE_NS:
  1112.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1113.         break;
  1114.     case TYPE_MD:
  1115.     case TYPE_MF:
  1116.     case TYPE_CNAME:
  1117.         i = strcmp(rr1->rdata.data,rr2->rdata.data);
  1118.         break;
  1119.     }
  1120.     return i;
  1121. }
  1122.