home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / MSDOS / WATTCP / NEWWATCP.ZIP / SRC / UDP_DOM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-05  |  13.1 KB  |  493 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(char *dst,char *src)
  125. {
  126.     char *p,*q,*savedst;
  127.     int i,dotflag,defflag;
  128.  
  129.     p = src;
  130.     dotflag = defflag = 0;
  131.     savedst = dst;
  132.  
  133.     do {            /* copy whole string */
  134.     *dst = 0;
  135.     q = dst + 1;
  136.     while (*p && (*p != '.'))
  137.         *q++ = *p++;
  138.  
  139.     i = p - src;
  140.     if (i > 0x3f)
  141.         return(-1);
  142.     *dst = i;
  143.     *q = 0;
  144.  
  145.     if (*p) {                    /* update pointers */
  146.         dotflag = 1;
  147.         src = ++p;
  148.         dst = q;
  149.     }
  150.     else if (!dotflag && !defflag && loc_domain) {
  151.         p = loc_domain;        /* continue packing with default */
  152.         defflag = 1;
  153.         src = p;
  154.         dst = q;
  155.     }
  156.     }
  157.     while (*p);
  158.     q++;
  159.     return(q-savedst);            /* length of packed string */
  160. }
  161.  
  162. /*********************************************************************/
  163. /*  unpackdom
  164. *  Unpack a compressed domain name that we have received from another
  165. *  host.  Handles pointers to continuation domain names -- buf is used
  166. *  as the base for the offset of any pointer which is present.
  167. *  returns the number of bytes at src which should be skipped over.
  168. *  Includes the NULL terminator in its length count.
  169. */
  170. static unpackdom(char *dst,char *src,char *buf)
  171. {
  172.     int i,j,retval;
  173.     char *savesrc;
  174.  
  175.     savesrc = src;
  176.     retval = 0;
  177.  
  178.     while (*src) {
  179.     j = *src;
  180.  
  181.     while ((j & 0xC0) == 0xC0) {
  182.         if (!retval)
  183.         retval = src-savesrc+2;
  184.         src++;
  185.         src = &buf[(j & 0x3f)*256+*src];        /* pointer dereference */
  186.         j = *src;
  187.     }
  188.  
  189.     src++;
  190.     for (i=0; i < (j & 0x3f) ; i++)
  191.         *dst++ = *src++;
  192.  
  193.     *dst++ = '.';
  194.     }
  195.  
  196.     *(--dst) = 0;            /* add terminator */
  197.     src++;                    /* account for terminator on src */
  198.  
  199.     if (!retval)
  200.     retval = src-savesrc;
  201.  
  202.     return(retval);
  203. }
  204.  
  205. /*********************************************************************/
  206. /*  sendom
  207. *   put together a domain lookup packet and send it
  208. *   uses port 53
  209. *    num is used as identifier
  210. */
  211. static sendom(char *s,longword towho,word num)
  212. {
  213.     word i,ulen;
  214.     byte *psave,*p;
  215.  
  216.     psave = (byte*)&(question->x);
  217.     i = packdom((byte *)&(question->x),s);
  218.  
  219.     p = &(question->x[i]);
  220.     *p++ = 0;                /* high byte of qtype */
  221.     *p++ = DTYPEA;            /* number is < 256, so we know high byte=0 */
  222.     *p++ = 0;                /* high byte of qclass */
  223.     *p++ = DIN;                /* qtype is < 256 */
  224.  
  225.     question->h.ident = intel16(num);
  226.     ulen = sizeof(struct dhead)+(p-psave);
  227.  
  228.     udp_open( dom_sock, 997, towho, 53, NULL );    /* divide err */
  229.  
  230.     sock_write( dom_sock, question, ulen );
  231.     return( ulen);
  232. }
  233.  
  234. int countpaths(char *pathstring)
  235. {
  236.     int     count = 0;
  237.     char    *p;
  238.  
  239.     for(p=pathstring; (*p != 0) || (*(p+1) != 0); p++) {
  240.     if(*p == 0)
  241.         count++;
  242.     }
  243.     return(++count);
  244. }
  245.  
  246. static char *getpath(char *pathstring,int whichone)
  247.             /* the path list to search      */
  248.             /* which path to get, starts at 1 */
  249. {
  250.     char    *retval;
  251.  
  252.     if(whichone > countpaths(pathstring))
  253.     return(NULL);
  254.     whichone--;
  255.     for(retval = pathstring;whichone ; retval++ ) {
  256.     if(*retval == 0)
  257.         whichone--;
  258.     }
  259.     return(retval);
  260. }
  261.  
  262. /*********************************************************************/
  263. /*  ddextract
  264. *   extract the ip number from a response message.
  265. *   returns the appropriate status code and if the ip number is available,
  266. *   copies it into mip
  267. */
  268. static longword ddextract(struct useek *qp,unsigned char *mip)
  269. {
  270.     word i,j,nans,rcode;
  271.     struct rrpart *rrp;
  272.     byte *p,space[260];
  273.  
  274.     nans = intel16(qp->h.ancount);        /* number of answers */
  275.     rcode = DRCODE & intel16(qp->h.flags);    /* return code for this message*/
  276.     if (rcode > 0)
  277.     return(rcode);
  278.  
  279.     if (nans > 0 &&                                /* at least one answer */
  280.     (intel16(qp->h.flags) & DQR)) {            /* response flag is set */
  281.     p = (byte *)&qp->x;                 /* where question starts */
  282.     i = unpackdom(space,p,qp);                /* unpack question name */
  283.     /*  spec defines name then  QTYPE + QCLASS = 4 bytes */
  284.     p += i+4;
  285. /*
  286.  *  at this point, there may be several answers.  We will take the first
  287.  *  one which has an IP number.  There may be other types of answers that
  288.  *  we want to support later.
  289.  */
  290.     while (nans-- > 0) {                    /* look at each answer */
  291.         i = unpackdom(space,p,qp);            /* answer name to unpack */
  292.         /*            n_puts(space);*/
  293.         p += i;                                /* account for string */
  294.         rrp = (struct rrpart *)p;            /* resource record here */
  295.  /*
  296.   *  check things which might not align on 68000 chip one byte at a time
  297.   */
  298.         if (!*p && *(p+1) == DTYPEA &&         /* correct type and class */
  299.         !*(p+2) && *(p+3) == DIN) {
  300.         movmem(rrp->rdata,mip,4);    /* save IP #         */
  301.         return(0);                        /* successful return */
  302.         }
  303.         movmem(&rrp->rdlength,&j,2);    /* 68000 alignment */
  304.         p += 10+intel16(j);                /* length of rest of RR */
  305.     }
  306.     }
  307.  
  308.     return(-1);                        /* generic failed to parse */
  309. }
  310.  
  311. /*********************************************************************/
  312. /*  getdomain
  313. *   Look at the results to see if our DOMAIN request is ready.
  314. *   It may be a timeout, which requires another query.
  315. */
  316.  
  317. static longword udpdom()
  318. {
  319.     int i,uret;
  320.     longword desired;
  321.  
  322.     uret = sock_fastread(dom_sock, question, sizeof(struct useek ));
  323.     /* this does not happen */
  324.     if (uret < 0) {
  325.     /*        netputevent(USERCLASS,DOMFAIL,-1);  */
  326.     return(-1);
  327.     }
  328.  
  329.  /* num = intel16(question->h.ident); */     /* get machine number */
  330. /*
  331.  *  check to see if the necessary information was in the UDP response
  332.  */
  333.  
  334.     i = ddextract(question, &desired);
  335.     switch (i) {
  336.         case 3:    return(0);        /* name does not exist */
  337.         case 0: return(intel(desired)); /* we found the IP number */
  338.         case -1:return( 0 );        /* strange return code from ddextract */
  339.         default:return( 0 );            /* dunno */
  340.     }
  341. }
  342.  
  343.  
  344. /**************************************************************************/
  345. /*  Sdomain
  346. *   DOMAIN based name lookup
  347. *   query a domain name server to get an IP number
  348. *    Returns the machine number of the machine record for future reference.
  349. *   Events generated will have this number tagged with them.
  350. *   Returns various negative numbers on error conditions.
  351. *
  352. *   if adddom is nonzero, add default domain
  353. */
  354. static longword Sdomain(char *mname, int adddom, longword nameserver, int *timedout )
  355. /* int *timedout; set to 1 on timeout */
  356. {
  357.     char namebuff[512];
  358.     int domainsremaining;
  359.     int status, i;
  360.     longword response;
  361.  
  362.     response = 0;
  363.     *timedout = 1;
  364.  
  365.     if (!nameserver) {    /* no nameserver, give up now */
  366.     outs("No nameserver defined!\n\r");
  367.     return(0);
  368.     }
  369.  
  370.     while (*mname && *mname < 33) mname ++;   /* kill leading spaces */
  371.  
  372.     if (!(*mname))
  373.     return(0L);
  374.  
  375.     qinit();                /* initialize some flag fields */
  376.  
  377.     strcpy( namebuff, mname );
  378.  
  379.     if ( adddom ) {
  380.     if(namebuff[strlen(namebuff)-1] != '.') {       /* if no trailing dot */
  381.         if(loc_domain) {             /* there is a search list */
  382.         domainsremaining = countpaths( loc_domain );
  383.  
  384.         strcat(namebuff,".");
  385.         strcat(namebuff,getpath(loc_domain,1));
  386.         }
  387.     } else
  388.         namebuff[ strlen(namebuff)-1] = 0;    /* kill trailing dot */
  389.     }
  390.     /*
  391.      * This is not terribly good, but it attempts to use a binary
  392.      * exponentially increasing delays.
  393.      */
  394.  
  395.      for ( i = 2; i < 17; i *= 2) {
  396.     sendom(namebuff,nameserver, 0xf001);    /* try UDP */
  397.  
  398.         ip_timer_init( dom_sock, i );
  399.         do {
  400.             kbhit();
  401.             tcp_tick( dom_sock );
  402.             if (ip_timer_expired( dom_sock )) break;
  403.             if ( watcbroke ) {
  404.                 break;
  405.             }
  406.             if (chk_timeout( timeoutwhen ))
  407.                 break;
  408.             if ( sock_dataready( dom_sock )) *timedout = 0;
  409.         } while ( *timedout );
  410.  
  411.     if ( !*timedout ) break;    /* got an answer */
  412.     }
  413.  
  414.     if ( !*timedout )
  415.     response = udpdom();    /* process the received data */
  416.  
  417.     sock_close( dom_sock );
  418.     return( response );
  419. }
  420.  
  421. /*
  422.  * nextdomain - given domain and count = 0,1,2,..., return next larger
  423.  *        domain or NULL when no more are available
  424.  */
  425. static char *nextdomain( char *domain, int count )
  426. {
  427.     char *p;
  428.     int i;
  429.  
  430.     p = domain;
  431.  
  432.     for (i = 0; i < count; ++i) {
  433.     p = strchr( p, '.' );
  434.     if (!p) return( NULL );
  435.     ++p;
  436.     }
  437.     return( p );
  438. }
  439.  
  440.  
  441. /*
  442.  * resolve()
  443.  *     convert domain name -> address resolution.
  444.  *     returns 0 if name is unresolvable right now
  445.  */
  446. longword resolve(char *name)
  447. {
  448.     longword ip_address, temp;
  449.     int count, i;
  450.     byte timeout[ MAX_NAMESERVERS ];
  451.     struct useek qp;        /* temp buffer */
  452.     udp_Socket ds;          /* temp buffer */
  453.     word oldhndlcbrk;
  454.  
  455.  
  456.     question = &qp;
  457.     dom_sock = &ds;
  458.     if (!name) return( 0 );
  459.     rip( name );
  460.  
  461.     if ( isaddr( name ))
  462.     return( aton( name ));
  463.  
  464.     if (!_domaintimeout) _domaintimeout = sock_delay << 2;
  465.     timeoutwhen = set_timeout( _domaintimeout );
  466.  
  467.     count = 0;
  468.     memset( &timeout, 0, sizeof( timeout ));
  469.  
  470.     oldhndlcbrk = wathndlcbrk;
  471.     wathndlcbrk = 1;        /* enable special interrupt mode */
  472.     watcbroke = 0;
  473.     do {
  474.     if (!(loc_domain = nextdomain( def_domain, count )))
  475.         count = -1;    /* use default name */
  476.  
  477.     for ( i = 0; i < _last_nameserver ; ++i ) {
  478.         if (!timeout[i])
  479.         if (ip_address = Sdomain( name , count != -1 ,
  480.             def_nameservers[i], &timeout[i] ))
  481.             break;    /* got name, bail out of loop */
  482.     }
  483.  
  484.     if (count == -1) break;
  485.     count++;
  486.     } while (!ip_address);
  487.     watcbroke = 0;          /* always clean up */
  488.     wathndlcbrk = oldhndlcbrk;
  489.  
  490.     return( ip_address );
  491. }
  492.  
  493.