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