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