home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / MSDOS / WATTCP / MSWATTCP.ZIP / SRC / UDP_DOM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-06  |  16.1 KB  |  555 lines

  1. /****
  2.  *
  3.  * File: udp_dom.c
  4.  * 27-Aug-93 fr
  5.  *    final cleanup
  6.  * 25-May-93 fr
  7.  *      added add_hosts_table and is_in_table
  8.  * 28-Aug-92 lr
  9.  *      I have moved the udp socket for domain queries out of the
  10.  *      stack. Chances are that a late reply would hang the system
  11.  *      because that memory is not valid anymore.
  12.  * 13-Jul-92 lr
  13.  *      there are some problems here. Sometimes the system hangs
  14.  *      right after calling resolve()
  15.  *      I think it's because they do sendom() (which includes udp_open())
  16.  *      more than once
  17.  * domain name server protocol
  18.  *
  19.  * This portion of the code needs some major work.  I ported it (read STOLE IT)
  20.  * from NCSA and lost about half the code somewhere in the process.
  21.  *
  22.  * Note, this is a user level process, not KERNEL.
  23.  *
  24.  *  0.2 : Apr 24, 1991 - use substring portions of domain
  25.  *  0.1 : Mar 18, 1991 - improved the trailing domain list
  26.  *  0.0 : Feb 19, 1991 - pirated by Erick Engelke
  27.  * -1.0 :              - NCSA code
  28.  */
  29.  
  30. #define UDP_DOM
  31. #include <tcp.h>
  32.  
  33. #define DIM 200         /* hosts table dimension */
  34.  
  35. typedef struct {
  36.     longword        ip;
  37.     char            name[80];
  38.     } hosts_tables;
  39.  
  40. static hosts_tables hosts_data[DIM];
  41. static int free_idx = 0;
  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. /***************************** STATICS *******************/
  112. static void qinit(void);
  113. static int packdom(char *dst,char *src);
  114. static int unpackdom(char *dst,char *src,char buf[]);
  115. static void sendom(char *s,longword towho,word num);
  116. static char *getpath(char *pathstring,int whichone);
  117. static longword ddextract(struct useek *qp,unsigned char *mip);
  118. static longword udpdom(void);
  119. static longword Sdomain(char *mname, int adddom, longword nameserver, byte *timedout);
  120. static char *nextdomain( char *domain, int count );
  121. static longword is_in_table( char *name );
  122.  
  123. static longword timeoutwhen;
  124. static udp_Socket *dom_sock;
  125.  
  126. /***********************END OF STATICS *******************/
  127.  
  128. static void qinit(void)
  129. {
  130.     question->h.flags = intel16(DRD);
  131.     question->h.qdcount = intel16(1);
  132.     question->h.ancount = 0;
  133.     question->h.nscount = 0;
  134.     question->h.arcount = 0;
  135. }
  136.  
  137. /*********************************************************************/
  138. /*  packdom
  139. *   pack a regular text string into a packed domain name, suitable
  140. *   for the name server.
  141. *
  142. *   returns length
  143. */
  144. static int
  145. packdom(char *dst,char *src)
  146. {
  147.     char *p=src,*q,*savedst=dst;
  148.     int i,dotflag=0,defflag=0;
  149.  
  150.     do {                        /* copy whole string */
  151.     *dst = 0;
  152.     q = dst + 1;
  153.     while (*p && (*p != '.')) *q++ = *p++;  /* copy first part */
  154.     i = p - src;
  155.     if (i > 0x3f) return(-1); /* too long */
  156.     *dst = (char)i;
  157.     *q = 0;
  158.  
  159.     if (*p) {/* must be a dot, update pointers */
  160.         dotflag = 1;
  161.         src = ++p; /* skip it */
  162.         dst = q;
  163.     } else if (!dotflag && !defflag && loc_domain) {
  164.         p = loc_domain;     /* continue packing with default */
  165.         defflag = 1;
  166.         src = p;
  167.         dst = q;
  168.     }
  169.     }
  170.     while (*p);
  171.     q++;
  172.     return(q-savedst);                  /* length of packed string */
  173. }
  174.  
  175. /*********************************************************************/
  176. /*  unpackdom
  177. *  Unpack a compressed domain name that we have received from another
  178. *  host.  Handles pointers to continuation domain names -- buf is used
  179. *  as the base for the offset of any pointer which is present.
  180. *  returns the number of bytes at src which should be skipped over.
  181. *  Includes the NULL terminator in its length count.
  182. */
  183. static int
  184. unpackdom(char *dst,char *src,char buf[])
  185. {
  186.     int i,j,retval=0;
  187.     char *savesrc=src;
  188.  
  189.     while (*src) {
  190.     j = *src;
  191.  
  192.     while ((j & 0xC0) == 0xC0) {
  193.         if (!retval) retval = src-savesrc+2;
  194.         src++;
  195.         src = &buf[(j & 0x3f)*256+ (*src)];
  196.         j = *src;
  197.     }
  198.  
  199.     src++;
  200.     for (i=0; i < (j & 0x3f) ; i++) *dst++ = *src++;
  201.  
  202.     *dst++ = '.';
  203.     }
  204.  
  205.     *(--dst) = 0;       /* add terminator */
  206.     src++;              /* account for terminator on src */
  207.  
  208.     if (!retval) retval = src-savesrc;
  209.  
  210.     return(retval);
  211. }
  212.  
  213. /*********************************************************************/
  214. /*  sendom
  215. *   put together a domain lookup packet and send it
  216. *   uses port 53
  217. *       num is used as identifier
  218. */
  219. static void
  220. sendom(char *s,longword towho,word num)
  221. {
  222.     word i,ulen;
  223.     byte *psave,*p;
  224.     char buf[60];
  225.  
  226.     DB2((stderr,
  227.     "called sendom(); resolving '%s' with nameserver %s\n",
  228.     s,w_inet_ntoa(buf,towho) ));
  229.     psave = (byte*)&(question->x);
  230.     i = packdom(question->x,s);
  231.  
  232.     p = &(question->x[i]);
  233.     *p++ = 0;           /* high byte of qtype */
  234.     *p++ = DTYPEA;      /* number is < 256, so we know high byte=0 */
  235.     *p++ = 0;           /* high byte of qclass */
  236.     *p++ = DIN;         /* qtype is < 256 */
  237.  
  238.     question->h.ident = intel16(num);
  239.     ulen = sizeof(struct dhead)+(p-psave);
  240.  
  241.     udp_open( dom_sock, 997, towho, 53, NULL );    /* divide err */
  242.  
  243.     sock_write( (sock_type *)dom_sock, (byte *)question, ulen );
  244.     return /* ( ulen) */;
  245. }
  246.  
  247. int
  248. countpaths(char *pathstring)
  249. {
  250.     int     count = 0;
  251.     char    *p;
  252.  
  253.     for(p=pathstring; (*p != 0) || (*(p+1) != 0); p++) {
  254.     if(*p == 0) count++;
  255.     }
  256.     return(++count);
  257. }
  258.  
  259. static char *
  260. getpath(char *pathstring,int whichone)
  261. /* the path list to search, which path to get, starts at 1 */
  262. {
  263.     char    *retval;
  264.  
  265.     if(whichone > countpaths(pathstring)) return(NULL);
  266.     whichone--;
  267.     for(retval = pathstring;whichone ; retval++ ) {
  268.     if(*retval == 0) whichone--;
  269.     }
  270.     return(retval);
  271. }
  272.  
  273. /*********************************************************************/
  274. /*  ddextract
  275. *   extract the ip number from a response message.
  276. *   returns the appropriate status code and if the ip number is available,
  277. *   copies it into mip
  278. */
  279. static longword
  280. ddextract(struct useek *qp,unsigned char *mip)
  281. {
  282.     word i,j,nans,rcode;
  283.     struct rrpart *rrp;
  284.     byte *p,space[260];
  285.  
  286.     nans = intel16(qp->h.ancount);         /* number of answers */
  287.     DB2((stderr,"ddextract: %d answer(s) received\n",nans));
  288.     rcode = DRCODE & intel16(qp->h.flags); /* return code for this message*/
  289.     if (rcode > 0) return(rcode);
  290.  
  291.     if (  nans > 0 &&           /* at least one answer */
  292.       (intel16(qp->h.flags) & DQR)) {       /* response flag is set */
  293.     p = (byte *)&qp->x;             /* where question starts */
  294.     i = unpackdom(space,(char *)p,(char *)qp); /* unpack question name */
  295.     /*  spec defines name then  QTYPE + QCLASS = 4 bytes */
  296.     p += i+4;
  297. /*
  298.  *  at this point, there may be several answers.  We will take the first
  299.  *  one which has an IP number.  There may be other types of answers that
  300.  *  we want to support later.
  301.  */
  302.     while (nans-- > 0) {            /* look at each answer */
  303.         i = unpackdom(space,p,(char *)qp);  /* answer name to unpack */
  304.         p += i;                     /* account for string */
  305.         rrp = (struct rrpart *)p;   /* resource record here */
  306.  /*
  307.   *  check things which might not align on 68000 chip one byte at a time
  308.   */
  309.         if (!*p && *(p+1) == DTYPEA &&      /* correct type and class */
  310.         !*(p+2) && *(p+3) == DIN) {
  311.         movmem(rrp->rdata,mip,4);       /* save IP #            */
  312.         return(0);                      /* successful return */
  313.         }
  314.         movmem(&rrp->rdlength,&j,2);        /* 68000 alignment */
  315.         p += 10+intel16(j);                 /* length of rest of RR */
  316.         }
  317.     }
  318.  
  319.     return(-1);                                 /* generic failed to parse */
  320. }
  321.  
  322. /*********************************************************************/
  323. /*  getdomain
  324. *   Look at the results to see if our DOMAIN request is ready.
  325. *   It may be a timeout, which requires another query.
  326. */
  327.  
  328. static longword
  329. udpdom(void)
  330. {
  331.     int i,uret;
  332.     longword desired;
  333.  
  334.     DB2((FDB,"called udpdom() to process received data\n"));
  335.     uret = sock_fastread((sock_type *)dom_sock,(byte *)question, sizeof(struct useek ));
  336.     /* this does not happen */
  337.     if (uret < 0) {
  338.     /*              netputevent(USERCLASS,DOMFAIL,-1);  */
  339.     return(-1);
  340.     }
  341.  
  342.  /* num = intel16(question->h.ident); */     /* get machine number */
  343. /*
  344.  *  check to see if the necessary information was in the UDP response
  345.  */
  346.  
  347.     i = (int)ddextract(question, (unsigned char *)&desired);
  348.     switch (i) {
  349.     case 3: return(0);              /* name does not exist */
  350.     case 0: return(intel(desired)); /* we found the IP number */
  351.     case -1:return( 0 );            /* strange return code from ddextract */
  352.     default:return( 0 );            /* dunno */
  353.     }
  354. }
  355.  
  356.  
  357. /**************************************************************************/
  358. /*  Sdomain
  359. *   DOMAIN based name lookup
  360. *   query a domain name server to get an IP number
  361. *       Returns the machine number of the machine record for future reference.
  362. *   Events generated will have this number tagged with them.
  363. *   Returns various negative numbers on error conditions.
  364. *
  365. *   if adddom is nonzero, add default domain
  366. */
  367. static longword
  368. Sdomain(char *mname, int adddom, longword nameserver, byte *timedout )
  369. {
  370.     char namebuff[512];
  371.     int domainsremaining;
  372.     int /* status, */ i;
  373.     longword response;
  374.  
  375.     DB2((stderr,
  376.     "called Sdomain()   ; resolving '%s' with nameserver %s\n",
  377.     mname,w_inet_ntoa(namebuff,nameserver)));
  378.     response = 0;
  379.     *timedout = 1;
  380.  
  381.     if (!nameserver) {  /* no nameserver, give up now */
  382.     outs("No nameserver defined!\n\r");
  383.     return(0);
  384.     }
  385.  
  386.     while (*mname && *mname < 33) mname ++;   /* kill leading spaces */
  387.  
  388.     if (!(*mname)) return(0L);
  389.  
  390.     qinit();                            /* initialize some flag fields */
  391.  
  392.     strcpy( namebuff, mname );
  393.  
  394.     if ( adddom ) {
  395.     if(namebuff[strlen(namebuff)-1] != '.') {  /* if no trailing dot */
  396.         if(loc_domain) {             /* there is a search list */
  397.         domainsremaining = countpaths( loc_domain );
  398.  
  399.         strcat(namebuff,".");
  400.         strcat(namebuff,getpath(loc_domain,1));
  401.         }
  402.     } else
  403.         namebuff[ strlen(namebuff)-1] = 0;  /* kill trailing dot */
  404.     }
  405.     /*
  406.      * This is not terribly good, but it attempts to use a binary
  407.      * exponentially increasing delays.
  408.      */
  409.  
  410.      for ( i = 2; i < 17; i *= 2) {
  411.     sendom(namebuff,nameserver, 0xf001);    /* try UDP */
  412.  
  413.     ip_timer_init( dom_sock, i );
  414.     do {
  415.         kbhit();
  416.         tcp_tick((sock_type *) dom_sock );
  417.         if (ip_timer_expired( dom_sock )) break;
  418.         if ( watcbroke ) break;
  419.         if (chk_timeout( timeoutwhen )) break;
  420.         /*if ( dom_sock->rdatalen ) *timedout = 0;*/
  421.         if ( sock_dataready((sock_type *) dom_sock )) *timedout = 0;
  422.     } while ( *timedout );
  423.  
  424.     if ( !*timedout ){
  425.         break;        /* got an answer */
  426.     }
  427.     }
  428.  
  429.     if ( !*timedout ) response = udpdom(); /* process the received data */
  430.     if (response) {
  431.     DB4((stderr,"resolved %s = %s\n\n",
  432.         mname, w_inet_ntoa(namebuff,response)));
  433.     } else {
  434.     DB4((stderr,"%s unresolved (at this time)\n\n",mname)); 
  435.     }
  436.     sock_close((sock_type *) dom_sock );
  437.     return( response );
  438. }
  439.  
  440. /*
  441.  * nextdomain - given domain and count = 0,1,2,..., return next larger
  442.  *              domain or NULL when no more are available
  443.  */
  444. static char *
  445. nextdomain( char *domain, int count )
  446. {
  447.     char *p;
  448.     int i;
  449.  
  450.     p = domain;
  451.  
  452.     for (i = 0; i < count; ++i) {
  453.     p = strchr( p, '.' );
  454.     if (!p) return( NULL );
  455.     ++p;
  456.     }
  457.     return( p );
  458. }
  459.  
  460.  
  461. /*
  462.  * resolve()
  463.  *      convert domain name -> address resolution.
  464.  *      returns 0 if name is unresolvable right now
  465.  */
  466. static udp_Socket ds;          /* temp buffer for udp domain requests */
  467. longword
  468. resolve(char *name)
  469. {
  470.     longword addr, ip_address=0L /* , temp */ ;
  471.     int count, i;
  472.     byte timeout[ MAX_NAMESERVERS ];
  473.     struct useek qp;        /* temp buffer */
  474.     word oldhndlcbrk;
  475.     char buf[255];
  476.  
  477.     DB2((stderr,"called resolve() for %s\n",name));
  478.     question = &qp;
  479.     dom_sock = &ds;
  480.     if (!name) return( 0 );
  481.     rip( name );
  482.  
  483.     if ( isaddr( name )) return( aton( name ));
  484.  
  485.     if (addr = is_in_table(name)){
  486.     DB3((stderr,"Table resolved %s = %s\n",name,
  487.         w_inet_ntoa(buf,addr) ));
  488.     return(addr);
  489.     }
  490.     if (!_domaintimeout) _domaintimeout = sock_delay << 2;
  491.     timeoutwhen = set_timeout( _domaintimeout );
  492.  
  493.     count = 0;
  494.     memset( &timeout, 0, sizeof( timeout ));
  495.  
  496.     oldhndlcbrk = wathndlcbrk;
  497.     wathndlcbrk = 1;        /* enable special interrupt mode */
  498.     watcbroke = 0;
  499.     do {
  500.     if (!(loc_domain = nextdomain( def_domain, count )))
  501.         count = -1;     /* use default name */
  502.  
  503.     for ( i = 0; i < _last_nameserver ; ++i ) {
  504.         if (!timeout[i])
  505.         if (ip_address = Sdomain( name , count != -1 ,
  506.             def_nameservers[i], &timeout[i] ))
  507.             break;      /* got name, bail out of loop */
  508.     }
  509.  
  510.     if (count == -1) break;
  511.     count++;
  512.     } while (!ip_address);
  513.     watcbroke = 0;          /* always clean up */
  514.     wathndlcbrk = oldhndlcbrk;
  515.     if(ip_address) 
  516.     add_hosts_table( w_inet_ntoa(buf,ip_address) , name );
  517.     return( ip_address );
  518. }
  519.  
  520.  
  521. #ifdef unused
  522. void 
  523. disp_hosts_table()
  524. {
  525.     int i;
  526.     char buf[255];
  527.     for( i=0; i<DIM && *hosts_data[i].name; i++ ) 
  528.     fprintf(stderr,"%d %-18s %-28s\n",i+1,
  529.         w_inet_ntoa(buf,hosts_data[i].ip),hosts_data[i].name);
  530.  
  531. }
  532. #endif /* unused */
  533.  
  534. void 
  535. add_hosts_table(char *ip, char *ipname)
  536. {
  537.     if ( *ip && *ipname && free_idx < (DIM-1) ){
  538.     hosts_data[free_idx].ip = aton(ip) ;
  539.     strcpy( hosts_data[free_idx].name, ipname );
  540.     free_idx++;
  541.     }
  542. }
  543.  
  544. static longword
  545. is_in_table( char *name )
  546. {
  547.     int i;
  548.     /* should make this case insensitive... */
  549.     for (i=0; i<DIM && strcmp( hosts_data[i].name, name);i++ ) ;
  550.     return( (i<DIM) ? hosts_data[i].ip : 0 );
  551. }
  552.  
  553.  
  554. /*** end of file udp_dom.c  ***/
  555.