/* domain.c */ #define DOMAINMASTER /* * Includes */ #include #include #include "vtcpip.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "prodat.h" #include "tcpdat.h" #include "domdat.h" #include "mapskt.h" #include "bytprc.h" /* * Sdomain * * DOMAIN based name lookup * query a domain name server to get an IP number * Returns various negative numbers on error conditions. * Checks for different port and saves the port number */ static int domwait = 0; int Sdomain(sknum,mname) int sknum; register char *mname; { register struct machinfo *m; int new,i,port,pflag; /* * no nameserver, give up now */ if(!Sns) return(-12); /* * kill leading spaces */ while(*mname && *mname<33) mname++; if(!(*mname)) return(-10); pflag = 0; port = 0; /* * Find out what port to open to */ for(i=0; (mname[i]!=' ') && (mname[i]!='#') && (mname[i]!='\0'); i++); if((mname[i]==' ') || (mname[i]=='#')) { mname[i++] = '\0'; for( ; (mname[i]==' ') || (mname[i]=='#') ; i++); new = i; for( ; (mname[i]!='\0') && isdigit(mname[i]) ; i++); if((mname[i]=='\0') && (new!=i)) { pflag = 1; port = (unsigned int)atoi(&mname[new]); } } /* * adds the number to the machlist */ if(!(m = Smadd(sknum,mname))) return(-13); /* * set the minimum timeout */ if(domwaithname) m->hname = m->sname; /* * Put save port number */ if(pflag) m->port = port; /* * try UDP */ sendom(m->hname,Sns->hostip,sknum); m->mstat = UDPDOM; /* * time out quickly first time */ stmrset(SCLASS,UDPTO,sktlist[sknum].inport,domwait); return(sknum); } VOID qinit() { question.h.flags = intswap(DRD); question.h.qdcount = intswap(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. */ static int packdom(dst,src) char *src,*dst; { register char *p,*q; char *savedst; int i,dotflag,defflag; p = src; dotflag = defflag = 0; savedst = dst; /* * copy whole string */ do { *dst = 0; q = dst+1; /* * copy the next label along, char by char * until it meets a period or end of string. */ while(*p && (*p!='.')) *q++ = *p++; i = p-src; if(i>0x3f) return(-1); *dst = (char)i; *q = 0; /* * update pointers */ if(*p) { dotflag = 1; src = ++p; dst = q; } else if(!dotflag && !defflag && Scon.defdom) { /* * continue packing with default */ p = Scon.defdom; defflag = 1; src = p; dst = q; ntposterr(801); } } while(*p); q++; /* * length of packed string */ return((int)(q-savedst)); } /* * 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(dst,src,buf) register char *src,*dst; char buf[]; { int i,j,retval; char *savesrc; retval = 0; savesrc = src; while(*src) { j = *src; while((j & 0xC0)==0xC0) { if(!retval) retval = src-savesrc+2; src++; /* * pointer dereference */ src = &buf[(j & 0x3f)*256+*src]; j = *src; } src++; for(i=0; i<(j & 0x3f) ; i++) *dst++ = *src++; *dst++ = '.'; } /* * add terminator */ *(--dst) = 0; /* * account for terminator on src */ src++; if(!retval) retval = src-savesrc; return(retval); } /* * sendom * * put together a domain lookup packet and send it * uses port 53 */ VOID sendom(s,towho,sknum) char *s,*towho; int sknum; { unsigned int i,ulen; register char *psave,*p; psave = (char *)question.x; i = packdom(question.x,s); /* * load the fields of the question structure */ p = &question.x[i]; *p++ = 0; /* high byte of qtype */ *p++ = DTYPEA; /* number is<256, so we know high byte = 0 */ *p++ = 0; /* high byte of qclass */ *p++ = DIN; /* qtype is<256 */ question.h.identity = intswap(sktlist[sknum].inport); ulen = sizeof(struct dhead)+(p-psave); ntusend(towho,53,997,(char *)&question,ulen); /* * remap socket sknum after ntusend */ mapskt(sknum); } /* * udpdom * * Look at the results to see if our DOMAIN request is ready. * It may be a timeout, which requires another query. */ int udpdom() { register struct machinfo *m; register struct socket *skt; int i,id,uret,sknum; register char *p; uret = nturead((char *)&question); if(uret<0) { return(-1); } /* * get unique id */ id = intswap(question.h.identity); /* * scan sockets for matching id */ skt = -1; sknum = 0; while(skt==-1 && sknummpp; /* * got a response, so reset timeout value * to recommended minimum */ domwait = nndomto; /* * check to see if the necessary information * was in the UDP response */ i = ddextract(&question,m->hostip); switch (i) { case 3: /* name does not exist */ stmrunset(SCLASS,UDPTO,id); ntposterr(802); p = nterrstring(-1); strncpy(p,m->hname,78); ntposterr(-1); ntptevent(USERCLASS,DOMFAIL,sknum); return(-1); case 0: /* we found the IP number */ stmrunset(SCLASS,UDPTO,id); /* * mark that we have it from DOMAIN */ m->mstat = DOM; ntptevent(USERCLASS,DOMOK,sknum); break; case -1: /* strange return code from ddextract */ ntposterr(803); break; default: ntposterr(804); break; } return(0); } /* * domto * * Handle time out for DOMAIN name lookup * Retry as many times as recommended by config file */ int domto(id) int id; { register int sknum; register struct machinfo *m; register struct socket *skt; /* * scan sockets for matching id */ skt = -1; sknum = 0; while(skt==-1 && sknummpp; if(m->mstat>UDPDOM+nnretry) { /* * permanent timeout */ ntptevent(USERCLASS,DOMFAIL,sknum); return(-1); } else { /* * one more timeout */ m->mstat++; } /* * exponential backoff */ if(domwaithname,Sns->hostip,sknum); /* * time out more slowly */ stmrset(SCLASS,UDPTO,sktlist[sknum].inport,domwait); return(sknum); } /* * ddextract * * extract the ip number from a response message. * returns the appropriate status code and if the ip number is available, * copies it into mip */ int ddextract(qp,mip) register struct useek *qp; char *mip; { unsigned int i,j,nans,rcode; register struct rrpart *rrp; char *p,space[260]; /* * number of answers */ nans = intswap(qp->h.ancount); /* * return code for this message */ rcode = DRCODE & intswap(qp->h.flags); if(rcode>0) return((int)rcode); /* * response flag is set and at least one answer */ if(nans>0 && (intswap(qp->h.flags) & DQR)) { /* * where question starts */ p = (char *)qp->x; /* * unpack question name */ i = unpackdom(space,p,(char *)qp); /* * 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. */ /* * look at each answer */ while(nans-->0) { /* * answer name to unpack */ i = unpackdom(space,p,(char *)qp); /* * account for string */ p += i; /* * resource record here */ rrp = (struct rrpart *)p; /* * correct type and class */ if(!*p && *(p+1)==DTYPEA && !*(p+2) && *(p+3)==DIN) { /* * save IP # */ movebytes(mip,rrp->rdata,4); /* * successful return */ return(0); } movebytes(&j,&rrp->rdlength,2); p += 10+intswap(j); } } /* * generic failed to parse */ return(-1); }