home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / wattcp.zip / UDP_DOM.C < prev    next >
C/C++ Source or Header  |  1991-11-26  |  13KB  |  505 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. *
  360. *   if adddom is nonzero, add default domain
  361. */
  362. static longword Sdomain(mname, adddom, nameserver, timedout )
  363. char *mname;
  364. int adddom;
  365. longword nameserver;
  366. int *timedout;    /* set to 1 on timeout */
  367. {
  368.     char namebuff[512];
  369.     int domainsremaining;
  370.     int status, i;
  371.     longword response;
  372.  
  373.     response = 0;
  374.     *timedout = 1;
  375.  
  376.     if (!nameserver) {    /* no nameserver, give up now */
  377.     outs("No nameserver defined!\n\r");
  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.  
  406.      for ( i = 2; i < 17; i *= 2) {
  407.     sendom(namebuff,nameserver, 0xf001);    /* try UDP */
  408.  
  409.         ip_timer_init( dom_sock, i );
  410.         do {
  411.             kbhit();
  412.             tcp_tick( dom_sock );
  413.             if (ip_timer_expired( dom_sock )) break;
  414.             if ( watcbroke ) {
  415.                 break;
  416.             }
  417.             if (chk_timeout( timeoutwhen ))
  418.                 break;
  419.             if ( sock_dataready( dom_sock )) *timedout = 0;
  420.         } while ( *timedout );
  421.  
  422.     if ( !*timedout ) break;    /* got an answer */
  423.     }
  424.  
  425.     if ( !*timedout )
  426.     response = udpdom();    /* process the received data */
  427.  
  428.     sock_close( dom_sock );
  429.     return( response );
  430. }
  431.  
  432. /*
  433.  * nextdomain - given domain and count = 0,1,2,..., return next larger
  434.  *        domain or NULL when no more are available
  435.  */
  436. static char *nextdomain( char *domain, int count )
  437. {
  438.     char *p;
  439.     int i;
  440.  
  441.     p = domain;
  442.  
  443.     for (i = 0; i < count; ++i) {
  444.     p = strchr( p, '.' );
  445.     if (!p) return( NULL );
  446.     ++p;
  447.     }
  448.     return( p );
  449. }
  450.  
  451.  
  452. /*
  453.  * resolve()
  454.  *     convert domain name -> address resolution.
  455.  *     returns 0 if name is unresolvable right now
  456.  */
  457. longword resolve(name)
  458. char *name;
  459. {
  460.     longword ip_address, temp;
  461.     int count, i;
  462.     byte timeout[ MAX_NAMESERVERS ];
  463.     struct useek qp;        /* temp buffer */
  464.     udp_Socket ds;          /* temp buffer */
  465.     word oldhndlcbrk;
  466.  
  467.  
  468.     question = &qp;
  469.     dom_sock = &ds;
  470.     if (!name) return( 0 );
  471.     rip( name );
  472.  
  473.     if ( isaddr( name ))
  474.     return( aton( name ));
  475.  
  476.     if (!_domaintimeout) _domaintimeout = sock_delay << 2;
  477.     timeoutwhen = set_timeout( _domaintimeout );
  478.  
  479.     count = 0;
  480.     memset( &timeout, 0, sizeof( timeout ));
  481.  
  482.     oldhndlcbrk = wathndlcbrk;
  483.     wathndlcbrk = 1;        /* enable special interrupt mode */
  484.     watcbroke = 0;
  485.     do {
  486.     if (!(loc_domain = nextdomain( def_domain, count )))
  487.         count = -1;    /* use default name */
  488.  
  489.     for ( i = 0; i < _last_nameserver ; ++i ) {
  490.         if (!timeout[i])
  491.         if (ip_address = Sdomain( name , count != -1 ,
  492.             def_nameservers[i], &timeout[i] ))
  493.             break;    /* got name, bail out of loop */
  494.     }
  495.  
  496.     if (count == -1) break;
  497.     count++;
  498.     } while (!ip_address);
  499.     watcbroke = 0;          /* always clean up */
  500.     wathndlcbrk = oldhndlcbrk;
  501.  
  502.     return( ip_address );
  503. }
  504.  
  505.