home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.wwiv.com
/
ftp.wwiv.com.zip
/
ftp.wwiv.com
/
pub
/
PPPBCKP
/
SRC
/
SRC15B96.ZIP
/
WATTSRC.ZIP
/
UDP_DOM.C
< prev
next >
Wrap
Text File
|
1994-11-28
|
16KB
|
575 lines
/* domain name server protocol
*
* This portion of the code needs some major work. I ported it (read STOLE IT)
* from NCSA and lost about half the code somewhere in the process.
*
* Note, this is a user level process. We include <tcp.h> not <wattcp.h>
*
* 0.3 : Jan 8, 1994 - hooks for different RR types; rev lookups. messy!
* 0.2 : Apr 24, 1991 - use substring portions of domain
* 0.1 : Mar 18, 1991 - improved the trailing domain list
* 0.0 : Feb 19, 1991 - pirated by Erick Engelke
* -1.0 : - NCSA code
*/
#include <copyright.h>
#include <stdio.h>
#include <string.h>
#include <mem.h>
#include <conio.h>
#include <tcp.h>
/*
* #include <elib.h>
*/
/* These next 'constants' are loaded from WATTCP.CFG file */
char *def_domain;
char *loc_domain; /* current subname to be used by the domain system */
longword def_nameservers[ MAX_NAMESERVERS ];
int _last_nameserver;
word _domaintimeout = 0;
static longword timeoutwhen;
/*
longword def_nameserver;
longword def2_nameserver;
*/
static udp_Socket *dom_sock;
#define DOMSIZE 512 /* maximum domain message size to mess with */
/*
* Header for the DOMAIN queries
* ALL OF THESE ARE BYTE SWAPPED QUANTITIES!
* We are the poor slobs who are incompatible with the world's byte order
*/
struct dhead {
word ident, /* unique identifier */
flags,
qdcount, /* question section, # of entries */
ancount, /* answers, how many */
nscount, /* count of name server RRs */
arcount; /* number of "additional" records */
};
/*
* flag masks for the flags field of the DOMAIN header
*/
#define DQR 0x8000 /* query = 0, response = 1 */
#define DOPCODE 0x7100 /* opcode, see below */
#define DAA 0x0400 /* Authoritative answer */
#define DTC 0x0200 /* Truncation, response was cut off at 512 */
#define DRD 0x0100 /* Recursion desired */
#define DRA 0x0080 /* Recursion available */
#define DRCODE 0x000F /* response code, see below */
/* opcode possible values: */
#define DOPQUERY 0 /* a standard query */
#define DOPIQ 1 /* an inverse query */
#define DOPCQM 2 /* a completion query, multiple reply */
#define DOPCQU 3 /* a completion query, single reply */
/* the rest reserved for future */
/* legal response codes: */
#define DROK 0 /* okay response */
#define DRFORM 1 /* format error */
#define DRFAIL 2 /* their problem, server failed */
#define DRNAME 3 /* name error, we know name doesn't exist */
#define DRNOPE 4 /* no can do request */
#define DRNOWAY 5 /* name server refusing to do request */
#define DTYPEA 1 /* host address resource record (RR) */
#define DTYPEPTR 12 /* a domain name ptr */
#define DIN 1 /* ARPA internet class */
#define DWILD 255 /* wildcard for several of the classifications */
/*
* a resource record is made up of a compressed domain name followed by
* this structure. All of these ints need to be byteswapped before use.
*/
struct rrpart {
word rtype, /* resource record type = DTYPEA */
rclass; /* RR class = DIN */
longword ttl; /* time-to-live, changed to 32 bits */
word rdlength; /* length of next field */
byte rdata[DOMSIZE]; /* data field */
};
/*
* data for domain name lookup
*/
static struct useek {
struct dhead h;
byte x[DOMSIZE];
} *question;
typedef void (*unpacker_funct)(void *data,struct rrpart *rrp,struct useek *qp);
/*
* prototypes
*/
static int packdom(char *dst, char *src);
static int countpaths(char *pathstring);
static int unpackdom(char *dst, char *src, char *buf);
static longword ddextract( struct useek *qp, byte type,
unpacker_funct unpacker, void *data );
static char *getpath(char *pathstring, int whichone);
static int sendom(char *s, longword towho, word num, byte dtype);
static int udpdom(byte dtype, unpacker_funct unpacker, void *data );
static int Sdomain(char *mname, byte dtype, unpacker_funct unpacker,
void *data, int adddom, longword nameserver, byte *timedout);
static int do_ns_lookup(char *name, byte dtype, unpacker_funct unpacker,
void *data );
static void qinit( void )
{
question->h.flags = intel16(DRD);
question->h.qdcount = intel16(1);
question->h.ancount = 0;
question->h.nscount = 0;
question->h.arcount = 0;
}
/*********************************************************************/
/* packdom
* pack a regular text string into a packed domain name, suitable
* for the name server.
*
* returns length
*/
static packdom( char *dst,char *src )
{
char *p,*q,*savedst;
int i,dotflag,defflag;
p = src;
dotflag = defflag = 0;
savedst = dst;
do { /* copy whole string */
*dst = 0;
q = dst + 1;
while (*p && (*p != '.'))
*q++ = *p++;
i = p - src;
if (i > 0x3f)
return(-1);
*dst = i;
*q = 0;
if (*p) { /* update pointers */
dotflag = 1;
src = ++p;
dst = q;
}
else if (!dotflag && !defflag && loc_domain) {
p = loc_domain; /* continue packing with default */
defflag = 1;
src = p;
dst = q;
}
}
while (*p);
q++;
return(q-savedst); /* length of packed string */
}
/*********************************************************************/
/* unpackdom
* Unpack a compressed domain name that we have received from another
* host. Handles pointers to continuation domain names -- buf is used
* as the base for the offset of any pointer which is present.
* returns the number of bytes at src which should be skipped over.
* Includes the NULL terminator in its length count.
*/
static int unpackdom( char *dst, char *src, char *buf )
{
int i,j,retval;
char *savesrc;
savesrc = src;
retval = 0;
while (*src) {
j = *src;
while ((j & 0xC0) == 0xC0) {
if (!retval)
retval = src-savesrc+2;
src++;
src = &buf[(j & 0x3f)*256+*src]; /* pointer dereference */
j = *src;
}
src++;
for (i=0; i < (j & 0x3f) ; i++)
*dst++ = *src++;
*dst++ = '.';
}
*(--dst) = 0; /* add terminator */
src++; /* account for terminator on src */
if (!retval)
retval = src-savesrc;
return(retval);
}
/*********************************************************************/
/* sendom
* put together a domain lookup packet and send it
* uses port 53
* num is used as identifier
*/
static int sendom( char *s, longword towho, word num, byte dtype )
{
word i,ulen;
byte *psave,*p;
psave = (byte*)&(question->x);
i = packdom((byte *)&(question->x),s);
p = &(question->x[i]);
*p++ = 0; /* high byte of qtype */
*p++ = dtype; /* number is < 256, so we know high byte=0 */
*p++ = 0; /* high byte of qclass */
*p++ = DIN; /* qtype is < 256 */
question->h.ident = intel16(num);
ulen = sizeof(struct dhead)+(p-psave);
udp_open( dom_sock, 997, towho, 53, NULL ); /* divide err */
sock_write( (sock_type*)dom_sock, (byte*)question, ulen );
return( ulen);
}
static int countpaths( char *pathstring )
{
int count = 0;
char *p;
for(p=pathstring; (*p != 0) || (*(p+1) != 0); p++) {
if(*p == 0)
count++;
}
return(++count);
}
static char *getpath( char *pathstring, int whichone )
/* the path list to search */
/* which path to get, starts at 1 */
{
char *retval;
if(whichone > countpaths(pathstring))
return(NULL);
whichone--;
for(retval = pathstring;whichone ; retval++ ) {
if(*retval == 0)
whichone--;
}
return(retval);
}
/*
* Unpack a DTYPA RR (address record)
*/
static void typea_unpacker( void *data, /* where to put IP */
struct rrpart *rrp, struct useek *qp )
{
qp = qp;
movmem(rrp->rdata,data,4); /* save IP # */
}
/*
* Unpack a DTYPEPTR RR
*
* assumes: data buffer long enough for the name.
* 256 chars should be enough(?)
*/
static void typeptr_unpacker( void *data,
struct rrpart *rrp, struct useek *qp )
{
unpackdom((char*)data,(char*)rrp->rdata,(char*)qp);
}
/*********************************************************************/
/* ddextract
* extract the data from a response message.
* returns the appropriate status code and if the data is available,
* copies it into data
* dtype is the RR type; unpacker is the function to get the data
* from the RR.
*/
static longword ddextract( struct useek *qp, byte dtype,
unpacker_funct unpacker, void *data )
{
word i,j,nans,rcode;
struct rrpart *rrp;
byte *p,space[260];
nans = intel16(qp->h.ancount); /* number of answers */
rcode = DRCODE & intel16(qp->h.flags); /* return code for this message*/
if (rcode > 0)
return(rcode);
if (nans > 0 && /* at least one answer */
(intel16(qp->h.flags) & DQR)) { /* response flag is set */
p = (byte *)&qp->x; /* where question starts */
i = unpackdom(space,(char*)p,(char*)qp); /* unpack question name */
/* spec defines name then QTYPE + QCLASS = 4 bytes */
p += i+4;
/*
* at this point, there may be several answers. We will take the first
* one which has an IP number. There may be other types of answers that
* we want to support later.
*/
while (nans-- > 0) { /* look at each answer */
i = unpackdom(space,(char*)p,(char*)qp); /* answer name to unpack */
/* n_puts(space);*/
p += i; /* account for string */
rrp = (struct rrpart *)p; /* resource record here */
/*
* check things which might not align on 68000 chip one byte at a time
*/
if (!*p && *(p+1) == dtype && /* correct type and class */
!*(p+2) && *(p+3) == DIN) {
unpacker(data,rrp,qp); /* get data we're looking for */
return(0); /* successful return */
}
movmem(&rrp->rdlength,&j,2); /* 68000 alignment */
p += 10+intel16(j); /* length of rest of RR */
}
}
return(-1); /* generic failed to parse */
}
/*********************************************************************/
/* getdomain
* Look at the results to see if our DOMAIN request is ready.
* It may be a timeout, which requires another query.
*/
static int udpdom( byte dtype, unpacker_funct unpacker, void *data )
{
int i,uret;
uret = sock_fastread((sock_type*)dom_sock, (byte*)question, sizeof(struct useek ));
/* this does not happen */
if (uret < 0) {
/* netputevent(USERCLASS,DOMFAIL,-1); */
return(0); /* ?? why'd I change this? -md */
// return(-1);
}
/* num = intel16(question->h.ident); */ /* get machine number */
/*
* check to see if the necessary information was in the UDP response
*/
i = ddextract(question, dtype, unpacker, data);
switch (i) {
case 0: return(1); /* we got a response */
case 3: return(0); /* name does not exist */
case -1:return( 0 ); /* strange return code from ddextract */
default:return( 0 ); /* dunno */
}
}
/**************************************************************************/
/* Sdomain
* DOMAIN based name lookup
* query a domain name server to get resource record data
* Returns the data on a machine from a particular RR type.
* Events generated will have this number tagged with them.
* Returns various negative numbers on error conditions.
*
* if adddom is nonzero, add default domain
*
* Returns true if we got data, false otherwise.
*/
static int Sdomain( char *mname, byte dtype, unpacker_funct unpacker,
void *data, int adddom, longword nameserver, byte *timedout )
/* int *timedout; set to 1 on timeout */
{
char namebuff[512];
/* int domainsremaining; */
int /*status,*/ i;
int result;
result = 0;
*timedout = 1;
if (!nameserver) { /* no nameserver, give up now */
outs("No nameserver defined!\n\r");
return(0);
}
while (*mname && *mname < 33) mname ++; /* kill leading spaces */
if (!(*mname))
return(0);
qinit(); /* initialize some flag fields */
strcpy( namebuff, mname );
if ( adddom ) {
if(namebuff[strlen(namebuff)-1] != '.') { /* if no trailing dot */
if(loc_domain) { /* there is a search list */
// domainsremaining = countpaths( loc_domain ); // why this here? -md
strcat(namebuff,".");
strcat(namebuff,getpath(loc_domain,1));
}
} else
namebuff[ strlen(namebuff)-1] = 0; /* kill trailing dot */
}
/*
* This is not terribly good, but it attempts to use a binary
* exponentially increasing delays.
*/
for ( i = 2; i < 17; i *= 2) {
sendom(namebuff,nameserver, 0xf001, dtype); /* try UDP */
ip_timer_init( dom_sock, i );
do {
kbhit();
tcp_tick( dom_sock );
if (ip_timer_expired( dom_sock )) break;
if ( watcbroke ) {
break;
}
if (chk_timeout( timeoutwhen ))
break;
if ( sock_dataready( dom_sock )) *timedout = 0;
} while ( *timedout );
if ( !*timedout ) break; /* got an answer */
}
if ( !*timedout )
result = udpdom(dtype, unpacker, data); /* process the received data */
sock_close( dom_sock );
return( result );
}
/*
* nextdomain - given domain and count = 0,1,2,..., return next larger
* domain or NULL when no more are available
*/
static char *nextdomain( char *domain, int count )
{
char *p;
int i;
p = domain;
for (i = 0; i < count; ++i) {
p = strchr( p, '.' );
if (!p) return( NULL );
++p;
}
return( p );
}
/*
* Perform a nameserver lookup of specified type using specified
* unpacker to extract data, if found.
*/
static int do_ns_lookup( char *name, byte dtype,
unpacker_funct unpacker, void *data )
{
/* longword temp; */
int result = 0; // init to false
int count, i;
byte timeout[ MAX_NAMESERVERS ];
struct useek qp; /* temp buffer */
udp_Socket ds; /* temp buffer */
word oldhndlcbrk;
question = &qp;
dom_sock = &ds;
if (!name) return( 0 );
rip( name );
if (!_domaintimeout) _domaintimeout = sock_delay << 2;
timeoutwhen = set_timeout( _domaintimeout );
count = 0;
memset( &timeout, 0, sizeof( timeout ));
oldhndlcbrk = wathndlcbrk;
wathndlcbrk = 1; /* enable special interrupt mode */
watcbroke = 0;
do {
if ( (loc_domain = nextdomain( def_domain, count )) == NULL )
count = -1; /* use default name */
for ( i = 0; i < _last_nameserver ; ++i ) {
if (!timeout[i])
if ((result = Sdomain( name, dtype, unpacker, data, count != -1 ,
def_nameservers[i], &timeout[i] )) == 1)
break; /* got name, bail out of loop */
}
if (count == -1) break;
count++;
} while (!result);
watcbroke = 0; /* always clean up */
wathndlcbrk = oldhndlcbrk;
return( result );
}
/*
* resolve()
* convert domain name -> address resolution.
* returns 0 if name is unresolvable right now
*/
longword resolve( char *name )
{
longword ipaddr;
if( !name ) return 0L;
if ( isaddr( name ))
return( aton( name ));
if( do_ns_lookup(name, DTYPEA, typea_unpacker, &ipaddr) )
return (intel(ipaddr));
else return (0L);
}
/*
* reverse_addr_lookup()
* lookup a hostname based on IP address
* (PTR lookups in the .in-addr.arpa domain)
*
* Returns true if the info was found, false otherwise.
*
* assumes: name buffer is big enough for the longest hostname
*/
int reverse_addr_lookup( longword ipaddr, char *name )
{
char revname[64];
inet_ntoa( revname, ntohl(ipaddr) ); /* ntohl flips order */
strcat(revname, ".IN-ADDR.ARPA.");
return ( do_ns_lookup(revname, DTYPEPTR, typeptr_unpacker, (void*)name) );
}