home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / CEREBRUM / WAT9609.ZIP / APPS / HOST.C < prev    next >
C/C++ Source or Header  |  1992-08-28  |  16KB  |  581 lines

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