home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / wattcp / src / udp_dom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  13.1 KB  |  495 lines

  1. /* domain name server protocol
  2.  *
  3.  * This portion of the code needs some major work.  I ported it (read STOLE IT)
  4.  * from NCSA and lost about half the code somewhere in the process.
  5.  *
  6.  * Note, this is a user level process.  We include <tcp.h> not <wattcp.h>
  7.  *
  8.  *  0.2 : Apr 24, 1991 - use substring portions of domain
  9.  *  0.1 : Mar 18, 1991 - improved the trailing domain list
  10.  *  0.0 : Feb 19, 1991 - pirated by Erick Engelke
  11.  * -1.0 :              - NCSA code
  12.  */
  13. #include"capalloc.h"
  14. #include"capstdio.h"
  15. #include <copyright.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include "..\wattcp\include\tcp.h"
  19.  
  20. /*
  21.  * #include <elib.h>
  22.  */
  23.  
  24. /* These next 'constants' are loaded from WATTCP.CFG file */
  25.  
  26. char *def_domain;
  27. char *loc_domain;    /* current subname to be used by the domain system */
  28.  
  29. longword def_nameservers[ MAX_NAMESERVERS ];
  30. int _last_nameserver;
  31. word _domaintimeout = 0;
  32.  
  33. static longword timeoutwhen;
  34.  
  35. /*
  36. longword def_nameserver;
  37. longword def2_nameserver;
  38. */
  39. static udp_Socket *dom_sock;
  40.  
  41. #define DOMSIZE 512                /* maximum domain message size to mess with */
  42.  
  43. /*
  44.  *  Header for the DOMAIN queries
  45.  *  ALL OF THESE ARE BYTE SWAPPED QUANTITIES!
  46.  *  We are the poor slobs who are incompatible with the world's byte order
  47.  */
  48. struct dhead {
  49.     word    ident,        /* unique identifier */
  50.         flags,
  51.         qdcount,    /* question section, # of entries */
  52.         ancount,    /* answers, how many */
  53.         nscount,    /* count of name server RRs */
  54.         arcount;    /* number of "additional" records */
  55. };
  56.  
  57. /*
  58.  *  flag masks for the flags field of the DOMAIN header
  59.  */
  60. #define DQR        0x8000    /* query = 0, response = 1 */
  61. #define DOPCODE        0x7100    /* opcode, see below */
  62. #define DAA        0x0400    /* Authoritative answer */
  63. #define DTC        0x0200    /* Truncation, response was cut off at 512 */
  64. #define DRD        0x0100    /* Recursion desired */
  65. #define DRA        0x0080    /* Recursion available */
  66. #define DRCODE        0x000F    /* response code, see below */
  67.  
  68. /* opcode possible values: */
  69. #define DOPQUERY    0    /* a standard query */
  70. #define DOPIQ        1    /* an inverse query */
  71. #define DOPCQM        2    /* a completion query, multiple reply */
  72. #define DOPCQU        3         /* a completion query, single reply */
  73. /* the rest reserved for future */
  74.  
  75. /* legal response codes: */
  76. #define DROK    0        /* okay response */
  77. #define DRFORM    1        /* format error */
  78. #define DRFAIL    2        /* their problem, server failed */
  79. #define DRNAME    3        /* name error, we know name doesn't exist */
  80. #define DRNOPE    4        /* no can do request */
  81. #define DRNOWAY    5        /* name server refusing to do request */
  82.  
  83. #define DTYPEA        1    /* host address resource record (RR) */
  84. #define DTYPEPTR    12    /* a domain name ptr */
  85.  
  86. #define DIN        1    /* ARPA internet class */
  87. #define DWILD        255    /* wildcard for several of the classifications */
  88.  
  89. /*
  90.  *  a resource record is made up of a compressed domain name followed by
  91.  *  this structure.  All of these ints need to be byteswapped before use.
  92.  */
  93. struct rrpart {
  94.     word       rtype,        /* resource record type = DTYPEA */
  95.         rclass;        /* RR class = DIN */
  96.     longword    ttl;        /* time-to-live, changed to 32 bits */
  97.     word    rdlength;    /* length of next field */
  98.     byte     rdata[DOMSIZE];    /* data field */
  99. };
  100.  
  101. /*
  102.  *  data for domain name lookup
  103.  */
  104. static struct useek {
  105.     struct dhead h;
  106.     byte         x[DOMSIZE];
  107. } *question;
  108.  
  109. static qinit()
  110. {
  111.     question->h.flags = intel16(DRD);
  112.     question->h.qdcount = intel16(1);
  113.     question->h.ancount = 0;
  114.     question->h.nscount = 0;
  115.     question->h.arcount = 0;
  116. }
  117.  
  118. /*********************************************************************/
  119. /*  packdom
  120. *   pack a regular text string into a packed domain name, suitable
  121. *   for the name server.
  122. *
  123. *   returns length
  124. */
  125. static packdom(char *dst,char *src)
  126. {
  127.     char *p,*q,*savedst;
  128.     int i,dotflag,defflag;
  129.  
  130.     p = src;
  131.     dotflag = defflag = 0;
  132.     savedst = dst;
  133.  
  134.     do {            /* copy whole string */
  135.     *dst = 0;
  136.     q = dst + 1;
  137.     while (*p && (*p != '.'))
  138.         *q++ = *p++;
  139.  
  140.     i = p - src;
  141.     if (i > 0x3f)
  142.         return(-1);
  143.     *dst = i;
  144.     *q = 0;
  145.  
  146.     if (*p) {                    /* update pointers */
  147.         dotflag = 1;
  148.         src = ++p;
  149.         dst = q;
  150.     }
  151.     else if (!dotflag && !defflag && loc_domain) {
  152.         p = loc_domain;        /* continue packing with default */
  153.         defflag = 1;
  154.         src = p;
  155.         dst = q;
  156.     }
  157.     }
  158.     while (*p);
  159.     q++;
  160.     return(q-savedst);            /* length of packed string */
  161. }
  162.  
  163. /*********************************************************************/
  164. /*  unpackdom
  165. *  Unpack a compressed domain name that we have received from another
  166. *  host.  Handles pointers to continuation domain names -- buf is used
  167. *  as the base for the offset of any pointer which is present.
  168. *  returns the number of bytes at src which should be skipped over.
  169. *  Includes the NULL terminator in its length count.
  170. */
  171. static unpackdom(char *dst,char *src,char *buf)
  172. {
  173.     int i,j,retval;
  174.     char *savesrc;
  175.  
  176.     savesrc = src;
  177.     retval = 0;
  178.  
  179.     while (*src) {
  180.     j = *src;
  181.  
  182.     while ((j & 0xC0) == 0xC0) {
  183.         if (!retval)
  184.         retval = src-savesrc+2;
  185.         src++;
  186.         src = &buf[(j & 0x3f)*256+*src];        /* pointer dereference */
  187.         j = *src;
  188.     }
  189.  
  190.     src++;
  191.     for (i=0; i < (j & 0x3f) ; i++)
  192.         *dst++ = *src++;
  193.  
  194.     *dst++ = '.';
  195.     }
  196.  
  197.     *(--dst) = 0;            /* add terminator */
  198.     src++;                    /* account for terminator on src */
  199.  
  200.     if (!retval)
  201.     retval = src-savesrc;
  202.  
  203.     return(retval);
  204. }
  205.  
  206. /*********************************************************************/
  207. /*  sendom
  208. *   put together a domain lookup packet and send it
  209. *   uses port 53
  210. *    num is used as identifier
  211. */
  212. static sendom(char *s,longword towho,word num)
  213. {
  214.     word i,ulen;
  215.     byte *psave,*p;
  216.  
  217.     psave = (byte*)&(question->x);
  218.     i = packdom((byte *)&(question->x),s);
  219.  
  220.     p = &(question->x[i]);
  221.     *p++ = 0;                /* high byte of qtype */
  222.     *p++ = DTYPEA;            /* number is < 256, so we know high byte=0 */
  223.     *p++ = 0;                /* high byte of qclass */
  224.     *p++ = DIN;                /* qtype is < 256 */
  225.  
  226.     question->h.ident = intel16(num);
  227.     ulen = sizeof(struct dhead)+(p-psave);
  228.  
  229.     udp_open( dom_sock, 997, towho, 53, NULL );    /* divide err */
  230.  
  231.     sock_write( dom_sock, question, ulen );
  232.     return( ulen);
  233. }
  234.  
  235. int countpaths(char *pathstring)
  236. {
  237.     int     count = 0;
  238.     char    *p;
  239.  
  240.     for(p=pathstring; (*p != 0) || (*(p+1) != 0); p++) {
  241.     if(*p == 0)
  242.         count++;
  243.     }
  244.     return(++count);
  245. }
  246.  
  247. static char *getpath(char *pathstring,int whichone)
  248.         /* the path list to search      */
  249.             /* which path to get, starts at 1 */
  250. {
  251.     char    *retval;
  252.  
  253.     if(whichone > countpaths(pathstring))
  254.     return(NULL);
  255.     whichone--;
  256.     for(retval = pathstring;whichone ; retval++ ) {
  257.     if(*retval == 0)
  258.         whichone--;
  259.     }
  260.     return(retval);
  261. }
  262.  
  263. /*********************************************************************/
  264. /*  ddextract
  265. *   extract the ip number from a response message.
  266. *   returns the appropriate status code and if the ip number is available,
  267. *   copies it into mip
  268. */
  269. static longword ddextract(struct useek *qp,unsigned char *mip)
  270. {
  271.     word i,j,nans,rcode;
  272.     struct rrpart *rrp;
  273.     byte *p,space[260];
  274.  
  275.     nans = intel16(qp->h.ancount);        /* number of answers */
  276.     rcode = DRCODE & intel16(qp->h.flags);    /* return code for this message*/
  277.     if (rcode > 0)
  278.     return(rcode);
  279.  
  280.     if (nans > 0 &&                                /* at least one answer */
  281.     (intel16(qp->h.flags) & DQR)) {            /* response flag is set */
  282.     p = (byte *)&qp->x;                 /* where question starts */
  283.     i = unpackdom(space,p,qp);                /* unpack question name */
  284.     /*  spec defines name then  QTYPE + QCLASS = 4 bytes */
  285.     p += i+4;
  286. /*
  287.  *  at this point, there may be several answers.  We will take the first
  288.  *  one which has an IP number.  There may be other types of answers that
  289.  *  we want to support later.
  290.  */
  291.     while (nans-- > 0) {                    /* look at each answer */
  292.         i = unpackdom(space,p,qp);            /* answer name to unpack */
  293.         /*            n_puts(space);*/
  294.         p += i;                                /* account for string */
  295.         rrp = (struct rrpart *)p;            /* resource record here */
  296.  /*
  297.   *  check things which might not align on 68000 chip one byte at a time
  298.   */
  299.         if (!*p && *(p+1) == DTYPEA &&         /* correct type and class */
  300.         !*(p+2) && *(p+3) == DIN) {
  301.         movmem(rrp->rdata,mip,4);    /* save IP #         */
  302.         return(0);                        /* successful return */
  303.         }
  304.         movmem(&rrp->rdlength,&j,2);    /* 68000 alignment */
  305.         p += 10+intel16(j);                /* length of rest of RR */
  306.     }
  307.     }
  308.  
  309.     return(-1);                        /* generic failed to parse */
  310. }
  311.  
  312. /*********************************************************************/
  313. /*  getdomain
  314. *   Look at the results to see if our DOMAIN request is ready.
  315. *   It may be a timeout, which requires another query.
  316. */
  317.  
  318. static longword udpdom()
  319. {
  320.     int i,uret;
  321.     longword desired;
  322.  
  323.     uret = sock_fastread(dom_sock, question, sizeof(struct useek ));
  324.     /* this does not happen */
  325.     if (uret < 0) {
  326.     /*        netputevent(USERCLASS,DOMFAIL,-1);  */
  327.     return(-1);
  328.     }
  329.  
  330.  /* num = intel16(question->h.ident); */     /* get machine number */
  331. /*
  332.  *  check to see if the necessary information was in the UDP response
  333.  */
  334.  
  335.     i = ddextract(question, &desired);
  336.     switch (i) {
  337.         case 3:    return(0);        /* name does not exist */
  338.     case 0: return(intel(desired)); /* we found the IP number */
  339.         case -1:return( 0 );        /* strange return code from ddextract */
  340.     default:return( 0 );            /* dunno */
  341.     }
  342. }
  343.  
  344.  
  345. /**************************************************************************/
  346. /*  Sdomain
  347. *   DOMAIN based name lookup
  348. *   query a domain name server to get an IP number
  349. *    Returns the machine number of the machine record for future reference.
  350. *   Events generated will have this number tagged with them.
  351. *   Returns various negative numbers on error conditions.
  352. *
  353. *   if adddom is nonzero, add default domain
  354. */
  355. static longword Sdomain(char *mname, int adddom, longword nameserver, int *timedout )
  356. /* int *timedout; set to 1 on timeout */
  357. {
  358.     char namebuff[512];
  359.     int domainsremaining;
  360.     int status, i;
  361.     longword response;
  362.  
  363.     response = 0;
  364.     *timedout = 1;
  365.  
  366.     if (!nameserver) {    /* no nameserver, give up now */
  367.     outs("No nameserver defined!\n");
  368.     return(0);
  369.     }
  370.  
  371.     while (*mname && *mname < 33) mname ++;   /* kill leading spaces */
  372.  
  373.     if (!(*mname))
  374.     return(0L);
  375.  
  376.     qinit();                /* initialize some flag fields */
  377.  
  378.     strcpy( namebuff, mname );
  379.  
  380.     if ( adddom ) {
  381.     if(namebuff[strlen(namebuff)-1] != '.') {       /* if no trailing dot */
  382.         if(loc_domain) {             /* there is a search list */
  383.         domainsremaining = countpaths( loc_domain );
  384.  
  385.         strcat(namebuff,".");
  386.         strcat(namebuff,getpath(loc_domain,1));
  387.         }
  388.     } else
  389.         namebuff[ strlen(namebuff)-1] = 0;    /* kill trailing dot */
  390.     }
  391.     /*
  392.      * This is not terribly good, but it attempts to use a binary
  393.      * exponentially increasing delays.
  394.      */
  395.  
  396.      for ( i = 2; i < 17; i *= 2) {
  397.     sendom(namebuff,nameserver, 0xf001);    /* try UDP */
  398.  
  399.         ip_timer_init( dom_sock, i );
  400.         do {
  401.             kbhit();
  402.             tcp_tick( dom_sock );
  403.             if (ip_timer_expired( dom_sock )) break;
  404.             if ( watcbroke ) {
  405.                 break;
  406.             }
  407.         if (chk_timeout( timeoutwhen ))
  408.         break;
  409.             if ( sock_dataready( dom_sock )) *timedout = 0;
  410.     } while ( *timedout );
  411.  
  412.     if ( !*timedout ) break;    /* got an answer */
  413.     }
  414.  
  415.     if ( !*timedout )
  416.     response = udpdom();    /* process the received data */
  417.  
  418.     sock_close( dom_sock );
  419.     return( response );
  420. }
  421.  
  422. /*
  423.  * nextdomain - given domain and count = 0,1,2,..., return next larger
  424.  *        domain or NULL when no more are available
  425.  */
  426. static char *nextdomain( char *domain, int count )
  427. {
  428.     char *p;
  429.     int i;
  430.  
  431.     p = domain;
  432.  
  433.     for (i = 0; i < count; ++i) {
  434.     p = strchr( p, '.' );
  435.     if (!p) return( NULL );
  436.     ++p;
  437.     }
  438.     return( p );
  439. }
  440.  
  441.  
  442. /*
  443.  * resolve()
  444.  *     convert domain name -> address resolution.
  445.  *     returns 0 if name is unresolvable right now
  446.  */
  447. longword resolve(char *name)
  448. {
  449.     longword ip_address, temp;
  450.     int count, i;
  451.     byte timeout[ MAX_NAMESERVERS ];
  452.     struct useek qp;        /* temp buffer */
  453.     udp_Socket ds;          /* temp buffer */
  454.     word oldhndlcbrk;
  455.  
  456.  
  457.     question = &qp;
  458.     dom_sock = &ds;
  459.     if (!name)
  460.      return( 0 );
  461.     rip( name );
  462.  
  463.     if ( isaddr( name ))
  464.     return( aton( name ));
  465.  
  466.     if (!_domaintimeout) _domaintimeout = sock_delay << 2;
  467.     timeoutwhen = set_timeout( _domaintimeout );
  468.  
  469.     count = 0;
  470.     memset( &timeout, 0, sizeof( timeout ));
  471.  
  472.     oldhndlcbrk = wathndlcbrk;
  473.     wathndlcbrk = 1;        /* enable special interrupt mode */
  474.     watcbroke = 0;
  475.     do {
  476.     if (!(loc_domain = nextdomain( def_domain, count )))
  477.         count = -1;    /* use default name */
  478.  
  479.     for ( i = 0; i < _last_nameserver ; ++i ) {
  480.         if (!timeout[i])
  481.         if (ip_address = Sdomain( name , count != -1 ,
  482.             def_nameservers[i], &timeout[i] ))
  483.             break;    /* got name, bail out of loop */
  484.  
  485.     }
  486.  
  487.     if (count == -1) break;
  488.     count++;
  489.     } while (!ip_address);
  490.     watcbroke = 0;          /* always clean up */
  491.     wathndlcbrk = oldhndlcbrk;
  492.  
  493.     return( ip_address );
  494. }
  495.