home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / DOMHDR.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  13KB  |  507 lines

  1. /* Domain header conversion routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Additional support for the Domain Name Server
  5.  * by Johan. K. Reinalda, WG7J,
  6.  * based on previous work by Gerard v.d. Grinten, PA0GRI
  7.  */
  8.  
  9. /****************************************************************************
  10. *    $Id: domhdr.c 1.3 93/07/16 11:43:57 ROOT_DOS Exp $
  11. *    17 May 93    1.3        GT    Fix warnings.                                    *
  12. ****************************************************************************/
  13.  
  14. #include "global.h"
  15. #include "config.h"
  16. #include "mbuf.h"
  17. #include "domain.h"
  18.  
  19. static int dn_expand __ARGS((char *msg,char *eom,char *compressed,char *full,
  20.     int fullen));
  21. static char *dn_compress __ARGS((char *cp, char *name));
  22. static char *getq __ARGS((struct rr **rrpp,char *msg,char *cp));
  23. static char *ntohrr __ARGS((struct rr **rrpp,char *msg,char *cp));
  24. static char *htonrr __ARGS((struct rr *rr, char *buffer));
  25.  
  26.  
  27. int
  28. ntohdomain(dhdr,bpp)
  29. register struct dhdr *dhdr;
  30. struct mbuf **bpp;
  31. {
  32.     int16 tmp,len;
  33.     register int16 i;
  34.     char *msg,*cp;
  35.     struct rr **rrpp;
  36.  
  37.     len = len_p(*bpp);
  38.     msg = mallocw(len);
  39.     pullup(bpp,msg,len);
  40.     memset((char *)dhdr,0,sizeof(*dhdr));
  41.  
  42.     dhdr->id = get16(&msg[0]);
  43.     tmp = get16(&msg[2]);
  44.     if(tmp & 0x8000)
  45.         dhdr->qr = 1;
  46.     dhdr->opcode = (tmp >> 11) & 0xf;
  47.     if(tmp & 0x0400)
  48.         dhdr->aa = 1;
  49.     if(tmp & 0x0200)
  50.         dhdr->tc = 1;
  51.     if(tmp & 0x0100)
  52.         dhdr->rd = 1;
  53.     if(tmp & 0x0080)
  54.         dhdr->ra = 1;
  55.     dhdr->rcode = tmp & 0xf;
  56.     dhdr->qdcount = get16(&msg[4]);
  57.     dhdr->ancount = get16(&msg[6]);
  58.     dhdr->nscount = get16(&msg[8]);
  59.     dhdr->arcount = get16(&msg[10]);
  60.  
  61.     /* Now parse the variable length sections */
  62.     cp = &msg[12];
  63.  
  64.     /* Question section */
  65.     rrpp = &dhdr->questions;
  66.     for(i=0;i<dhdr->qdcount;i++){
  67.         if((cp = getq(rrpp,msg,cp)) == NULLCHAR){
  68.             free(msg);
  69.             return -1;
  70.         }
  71.         (*rrpp)->source = RR_QUESTION;
  72.         rrpp = &(*rrpp)->next;
  73.     }
  74.     *rrpp = NULLRR;
  75.  
  76.     /* Answer section */
  77.     rrpp = &dhdr->answers;
  78.     for(i=0;i<dhdr->ancount;i++){
  79.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  80.             free(msg);
  81.             return -1;
  82.         }
  83.         (*rrpp)->source = RR_ANSWER;
  84.         rrpp = &(*rrpp)->next;
  85.     }
  86.     *rrpp = NULLRR;
  87.  
  88.     /* Name server (authority) section */
  89.     rrpp = &dhdr->authority;
  90.     for(i=0;i<dhdr->nscount;i++){
  91.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  92.             free(msg);
  93.             return -1;
  94.         }
  95.         (*rrpp)->source = RR_AUTHORITY;
  96.         rrpp = &(*rrpp)->next;
  97.     }
  98.     *rrpp = NULLRR;
  99.  
  100.     /* Additional section */
  101.     rrpp = &dhdr->additional;
  102.     for(i=0;i<dhdr->arcount;i++){
  103.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  104.             free(msg);
  105.             return -1;
  106.         }
  107.         (*rrpp)->source = RR_ADDITIONAL;
  108.         rrpp = &(*rrpp)->next;
  109.     }
  110.     *rrpp = NULLRR;
  111.     free(msg);
  112.     return 0;
  113. }
  114. static char *
  115. getq(rrpp,msg,cp)
  116. struct rr **rrpp;
  117. char *msg;
  118. char *cp;
  119. {
  120.     register struct rr *rrp;
  121.     int len;
  122.     char *name;
  123.  
  124.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  125.     name = mallocw(512);
  126.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  127.     if(len == -1){
  128.         free(name);
  129.         return NULLCHAR;
  130.     }
  131.     cp += len;
  132.     rrp->name = strdup(name);
  133.     rrp->type = get16(cp);
  134.     cp += 2;
  135.     rrp->class = get16(cp);
  136.     cp += 2;
  137.     rrp->ttl = 0;
  138.     rrp->rdlength = 0;
  139.     free(name);
  140.     return cp;
  141. }
  142. /* Read a resource record from a domain message into a host structure */
  143. static char *
  144. ntohrr(rrpp,msg,cp)
  145. struct rr **rrpp; /* Where to allocate resource record structure */
  146. char *msg;    /* Pointer to beginning of domain message */
  147. char *cp;    /* Pointer to start of encoded RR record */
  148. {
  149.     register struct rr *rrp;
  150.     int len;
  151.     char *name;
  152.  
  153.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  154.     name = mallocw(512);
  155.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  156.         free(name);
  157.         return NULLCHAR;
  158.     }
  159.     cp += len;
  160.     rrp->name = strdup(name);
  161.     rrp->type = get16(cp);
  162.     cp += 2;
  163.     rrp->class = get16(cp);
  164.     cp+= 2;
  165.     rrp->ttl = get32(cp);
  166.     cp += 4;
  167.     rrp->rdlength = get16(cp);
  168.     cp += 2;
  169.     switch(rrp->type){
  170.     case TYPE_A:
  171.         /* Just read the address directly into the structure */
  172.         rrp->rdata.addr = get32(cp);
  173.         cp += 4;
  174.         break;
  175.     case TYPE_CNAME:
  176.     case TYPE_MB:
  177.     case TYPE_MG:
  178.     case TYPE_MR:
  179.     case TYPE_NS:
  180.     case TYPE_PTR:
  181.         /* These types all consist of a single domain name;
  182.          * convert it to ascii format
  183.          */
  184.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  185.         if(len == -1){
  186.             free(name);
  187.             return NULLCHAR;
  188.         }
  189.         rrp->rdata.name = strdup(name);
  190.         rrp->rdlength = strlen(name);
  191.         cp += len;
  192.         break;
  193.     case TYPE_HINFO:
  194.         len = *cp++;
  195.         rrp->rdata.hinfo.cpu = mallocw(len+1);
  196.         memcpy( rrp->rdata.hinfo.cpu, cp, len );
  197.         rrp->rdata.hinfo.cpu[len] = '\0';
  198.         cp += len;
  199.  
  200.         len = *cp++;
  201.         rrp->rdata.hinfo.os = mallocw(len+1);
  202.         memcpy( rrp->rdata.hinfo.os, cp, len );
  203.         rrp->rdata.hinfo.os[len] = '\0';
  204.         cp += len;
  205.         break;
  206.     case TYPE_MX:
  207.         rrp->rdata.mx.pref = get16(cp);
  208.         cp += 2;
  209.         /* Get domain name of exchanger */
  210.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  211.         if(len == -1){
  212.             free(name);
  213.             return NULLCHAR;
  214.         }
  215.         rrp->rdata.mx.exch = strdup(name);
  216.         cp += len;
  217.         break;
  218.     case TYPE_SOA:
  219.         /* Get domain name of name server */
  220.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  221.         if(len == -1){
  222.             free(name);
  223.             return NULLCHAR;
  224.         }
  225.         rrp->rdata.soa.mname = strdup(name);
  226.         cp += len;
  227.  
  228.         /* Get domain name of responsible person */
  229.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  230.         if(len == -1){
  231.             free(name);
  232.             return NULLCHAR;
  233.         }
  234.         rrp->rdata.soa.rname = strdup(name);
  235.         cp += len;
  236.  
  237.         rrp->rdata.soa.serial = get32(cp);
  238.         cp += 4;
  239.         rrp->rdata.soa.refresh = get32(cp);
  240.         cp += 4;
  241.         rrp->rdata.soa.retry = get32(cp);
  242.         cp += 4;
  243.         rrp->rdata.soa.expire = get32(cp);
  244.         cp += 4;
  245.         rrp->rdata.soa.minimum = get32(cp);
  246.         cp += 4;
  247.         break;
  248.     case TYPE_TXT:
  249.         /* Just stash */
  250.         rrp->rdata.data = mallocw(rrp->rdlength);
  251.         memcpy(rrp->rdata.data,cp,rrp->rdlength);
  252.         cp += rrp->rdlength;
  253.         break;
  254.     default:
  255.         /* Ignore */
  256.         cp += rrp->rdlength;
  257.         break;
  258.     }
  259.     free(name);
  260.     return cp;
  261. }
  262.  
  263. /* Convert a compressed domain name to the human-readable form */
  264. static int
  265. dn_expand(msg,eom,compressed,full,fullen)
  266. char *msg;        /* Complete domain message */
  267. char *eom;
  268. char *compressed;    /* Pointer to compressed name */
  269. char *full;        /* Pointer to result buffer */
  270. int fullen;        /* Length of same */
  271. {
  272.     unsigned int slen;    /* Length of current segment */
  273.     register char *cp;
  274.     int clen = 0;    /* Total length of compressed name */
  275.     int indirect = 0;    /* Set if indirection encountered */
  276.     int nseg = 0;        /* Total number of segments in name */
  277.  
  278.     cp = compressed;
  279.     for(;;){
  280.         slen = uchar(*cp++);    /* Length of this segment */
  281.         if(!indirect)
  282.             clen++;
  283.         if((slen & 0xc0) == 0xc0){
  284.             if(!indirect)
  285.                 clen++;
  286.             indirect = 1;
  287.             /* Follow indirection */
  288.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  289.             slen = uchar(*cp++);
  290.         }
  291.         if(slen == 0)    /* zero length == all done */
  292.             break;
  293.         fullen -= slen + 1;
  294.         if(fullen < 0)
  295.             return -1;
  296.         if(!indirect)
  297.             clen += slen;
  298.         while(slen-- != 0)
  299.             *full++ = *cp++;
  300.         *full++ = '.';
  301.         nseg++;
  302.     }
  303.     if(nseg == 0){
  304.         /* Root name; represent as single dot */
  305.         *full++ = '.';
  306.         fullen--;
  307.     }
  308.     *full++ = '\0';
  309.     fullen--;
  310.     return clen;    /* Length of compressed message */
  311. }
  312.  
  313.  
  314.  
  315. #ifdef DSERVER
  316.  
  317. /* Most of this code is based on the DNS server in PA0GRI's 910828
  318.  * Ported to the current NOS code by Johan. K. Reinalda, WG7J
  319.  * for version and bug/feature info, see domain.c
  320.  */
  321.  
  322. static char *
  323. dn_compress(cp,name)
  324. char *cp, *name;
  325. {
  326.     int len,dlen;
  327.     char *cp1;
  328.     dlen = strlen(name);
  329.     for(;;){
  330.         /* Look for next dot */
  331.         cp1 = strchr(name,'.');
  332.         if(cp1 != NULLCHAR)
  333.             len = (int) (cp1 - name);    /* More to come */
  334.         else
  335.             len = dlen;    /* Last component */
  336.         *cp++ = len;        /* Write length of component */
  337.         if(len == 0)
  338.             return cp;
  339.         /* Copy component up to (but not including) dot */
  340.         strncpy(cp,name,len);
  341.         cp += len;
  342.         if(cp1 == NULLCHAR){
  343.             *cp++ = 0;    /* Last one; write null and finish */
  344.             return cp;
  345.         }
  346.         name += len+1;
  347.         dlen -= len+1;
  348.     }
  349. }
  350.  
  351. /* Translate a resource record from host format to network format */
  352. static char *
  353. htonrr(rr,buffer)
  354. struct rr *rr;
  355. char *buffer;
  356. {
  357.     struct rr *rrp;
  358.     char *cp, *p;
  359.     int i, len;
  360.  
  361.     cp = buffer;
  362.     for(rrp = rr; rrp != NULLRR; rrp = rrp->next) {
  363. #ifdef notdef
  364.         i = strlen(rrp->name);
  365.         if(rrp->name[i-1] != '.'
  366.            && rrp->origin != NULLCHAR) {
  367.             p = mallocw(i + strlen(rrp->origin) + 2);
  368.             sprintf(p,"%s.%s",rrp->name,rrp->origin);
  369.             cp = dn_compress(cp,p);
  370.             free(p);
  371.         } else
  372. #endif
  373.             cp = dn_compress(cp,rrp->name);
  374.         cp = put16(cp,rrp->type);
  375.         cp = put16(cp,rrp->class);
  376.         cp = put32(cp,rrp->ttl);
  377. #ifdef notdef
  378.         /* The length doesn't seem to be right for all types ! */
  379.         cp = put16(cp,rrp->rdlength);
  380. #endif
  381.         p = cp;     /* This is where the length goes ! */
  382.         cp += 2;    /* Save the space for lenght field */
  383.  
  384.         switch(rrp->type) {
  385.         case TYPE_A:
  386.             cp = put32(cp,rrp->rdata.addr);
  387.             break;
  388.         case TYPE_SOA:
  389.             cp = dn_compress(cp,rrp->rdata.soa.mname);
  390.             cp = dn_compress(cp,rrp->rdata.soa.rname);
  391.             cp = put32(cp,rrp->rdata.soa.serial);
  392.             cp = put32(cp,rrp->rdata.soa.refresh);
  393.             cp = put32(cp,rrp->rdata.soa.retry);
  394.             cp = put32(cp,rrp->rdata.soa.expire);
  395.             cp = put32(cp,rrp->rdata.soa.minimum);
  396.             break;
  397.         case TYPE_HINFO:
  398.             *cp++ = len = strlen(rrp->rdata.hinfo.cpu); 
  399.             strncpy(cp,rrp->rdata.hinfo.cpu,len); 
  400.             cp += len;
  401.             *cp++ = len = strlen(rrp->rdata.hinfo.os);
  402.             strncpy(cp,rrp->rdata.hinfo.os,len); 
  403.             cp += len;
  404.             break;
  405.         case TYPE_MX:
  406.             cp = put16(cp,rrp->rdata.mx.pref); 
  407.             cp = dn_compress(cp,rrp->rdata.mx.exch);
  408.             break;
  409.         case TYPE_CNAME:
  410.         case TYPE_MB:
  411.         case TYPE_MG:
  412.         case TYPE_MR:
  413.         case TYPE_NS:
  414.         case TYPE_PTR:
  415.             cp = dn_compress(cp,rrp->rdata.data);
  416.             break;
  417.         case TYPE_MINFO:    /* Unsupported type */
  418.         cp = dn_compress(cp,rrp->rdata.minfo.rmailbx);
  419.         cp = dn_compress(cp,rrp->rdata.minfo.emailbx);
  420.         case TYPE_MD:       /* Unsupported type */
  421.         case TYPE_MF:       /* Unsupported type */
  422.         case TYPE_NULL:     /* Unsupported type */
  423.         case TYPE_WKS:      /* Unsupported type */
  424.             cp = dn_compress(cp,rrp->rdata.data);
  425.             break;
  426.         case TYPE_TXT:
  427.         default:
  428.             cp = put16(cp,rrp->rdlength);
  429.             for(i=0 ; i < rrp->rdlength ; i++)
  430.                 *cp++ = rrp->rdata.data[i];
  431.             break;
  432.         }
  433.         /* Calculate the lenght of the RR */
  434.         len = (int) (cp - p - 2);
  435.         put16(p,len);       /* and set it */
  436.     }
  437.     return cp;
  438. }
  439.  
  440. int
  441. htondomain(dhdr,buffer,buflen)
  442. struct dhdr *dhdr;
  443. char *buffer;    /* Area for query */
  444. int16 buflen;    /* Length of same */
  445. {
  446.     char *cp;
  447.     struct rr *rrp;
  448.     int16 parameter;
  449.     int i, count;
  450.  
  451.     cp = buffer;
  452.     cp = put16(cp,dhdr->id);    
  453.     if(dhdr->qr)
  454.         parameter = 0x8000;
  455.     else
  456.         parameter = 0;
  457.     parameter |= (dhdr->opcode & 0x0f) << 11;
  458.     if(dhdr->aa)
  459.         parameter |= DOM_AUTHORITY;
  460.     if(dhdr->tc)
  461.         parameter |= DOM_TRUNC;
  462.     if(dhdr->rd)
  463.         parameter |= DOM_DORECURSE;
  464.     if(dhdr->ra)
  465.         parameter |= DOM_CANRECURSE;
  466.     parameter |= (dhdr->rcode & 0x0f);
  467.     cp = put16(cp,parameter);
  468.     cp = put16(cp,dhdr->qdcount);
  469.     cp = put16(cp,dhdr->ancount);
  470.     cp = put16(cp,dhdr->nscount);
  471.     cp = put16(cp,dhdr->arcount);
  472.     if((count = dhdr->qdcount) > 0) {
  473.         rrp = dhdr->questions;
  474.         for(i = 0; i < count; i++) {
  475.             cp = dn_compress(cp,rrp->name);
  476.             cp = put16(cp,rrp->type);
  477.             cp = put16(cp,rrp->class);
  478.             rrp = rrp->next;
  479.         }
  480.     }
  481.     if((count = dhdr->ancount) > 0) {
  482.         rrp = dhdr->answers;
  483.         for(i = 0; i < count; i++) {
  484.             cp = htonrr(rrp,cp);
  485.             rrp = rrp->next;
  486.         }
  487.     }
  488.     if((count = dhdr->nscount) > 0) {
  489.         rrp = dhdr->authority;
  490.         for(i = 0; i < count; i++) {
  491.             cp = htonrr(rrp,cp);
  492.             rrp = rrp->next;
  493.         }
  494.     }
  495.     if((count = dhdr->arcount) > 0) {
  496.         rrp = dhdr->additional;
  497.         for(i = 0; i < count; i++) {
  498.             cp = htonrr(rrp,cp);
  499.             rrp = rrp->next;
  500.         }
  501.     }
  502.     return (int) (cp - buffer);
  503. }
  504.  
  505.  
  506. #endif
  507.