UDP_DOM.C
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:18k
源码类别:

操作系统开发

开发平台:

DOS

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