home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-02-22 | 59.0 KB | 2,380 lines |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
-
- #include "netdb.h"
- #include "resolve.h"
- #include "socket.h"
- #include "in.h"
- #include "inet.h"
- #include "nameser.h"
- #include "resolv.h"
- #include "global.h"
- #include "timer.h"
- #include "cmdparse.h"
- #include "netuser.h"
- #include "domain.h"
- #include "misc.h"
- #include "mbuf.h"
- #include "tcp.h"
- #include "session.h"
- #include "time.h"
- #include "event.h"
- #include "var.h"
-
- extern varlist global_vars; /* Global variables chain in cmdparse */
-
- #define shortsize 2
-
- #include "if.h" /* for struct ifconf */
-
- #define TCPINBUFFLEN 1024
-
- #define bad_config_format(cmd) \
- cwprintf(NULL, "resolv+: %s: \"%s\" command incorrectly formatted.\n", hostconf, cmd);
-
- #define MAXALIASES 35
- #define MAXADDRS 35
- #define MAXTRIMDOMAINS 4
- #define MAXMXS 16
-
-
- #define SERVICE_NONE 0
- #define SERVICE_BIND 1
- #define SERVICE_HOSTS 2
- #define SERVICE_NIS 3
- #define SERVICE_MAX 3
-
- #define CMD_ORDER "order"
- #define CMD_TRIMDOMAIN "trim"
- #define CMD_HMA "multi"
- #define CMD_SPOOF "nospoof"
- #define CMD_SPOOFALERT "alert"
- #define CMD_REORDER "reorder"
- #define CMD_ON "on"
- #define CMD_OFF "off"
- #define CMD_WARN "warn"
- #define CMD_NOWARN "warn off"
- #define CMD_CACHESIZE "cachesize"
-
- #define ORD_BIND "bind"
- #define ORD_HOSTS "hosts"
- #define ORD_NIS "nis"
-
- #define ENV_HOSTCONF "RESOLV_HOST_CONF"
- #define ENV_SERVORDER "RESOLV_SERV_ORDER"
- #define ENV_SPOOF "RESOLV_SPOOF_CHECK"
- #define ENV_TRIM_OVERR "RESOLV_OVERRIDE_TRIM_DOMAINS"
- #define ENV_TRIM_ADD "RESOLV_ADD_TRIM_DOMAINS"
- #define ENV_HMA "RESOLV_MULTI"
- #define ENV_REORDER "RESOLV_REORDER"
- #define ENV_CACHESIZE "RESOLV_CACHE_SIZE"
-
- #define TOKEN_SEPARATORS " ,;:"
-
- struct state _res = {
- RES_TIMEOUT, /* retransmition time interval */
- 4, /* number of times to retransmit */
- RES_DEFAULT, /* options flags */
- 1, /* number of name servers */
- };
-
- static int service_order[SERVICE_MAX + 1];
- static int service_done = 0;
-
- static char *h_addr_ptrs[MAXADDRS + 1];
- static struct mx_data *mx_ptrs[MAXMXS+1];
- static struct mx_data mx_conts[MAXMXS];
-
- static struct hostent host;
- static char *host_aliases[MAXALIASES];
- static char hostbuf[BUFSIZ+1];
- static struct in_addr host_addr;
- static FILE *hostf = NULL;
- static char hostaddr[MAXADDRS];
- static char *host_addrs[2];
- static int stayopen = 0;
- static int hosts_multiple_addrs = 0;
- static int spoof = 0;
- static int spoofalert = 0;
- static int reorder = 0;
- static char *trimdomain[MAXTRIMDOMAINS];
- static char trimdomainbuf[BUFSIZ];
- static int numtrimdomains = 0;
- static int trace=0;
- static struct tcb *tcpintcb;
- static int timeoutfact = 30;
-
- static int single_query(int);
- int lookupnames = 0;
-
- #if PACKETSZ > 1024
- #define MAXPACKET PACKETSZ
- #else
- #define MAXPACKET 1024
- #endif
-
- typedef union {
- HEADER hdr;
- u_char buf[MAXPACKET];
- }
- querybuf;
-
- typedef union {
- long al;
- char ac;
- }
- align;
-
- int h_errno;
-
- static void print_host( struct hostent *host );
-
- static int doresolve_host( int argc, char **argv )
- {
- unsigned int addr;
- struct hostent *hosts = NULL;
- char name[300];
-
- strcpy( name, argv[1] );
- if( ! ipaddr( name, &addr ) ) {
- cwprintf(NULL, "%d.%d.%d.%d\n", (addr>>24), (addr>>16)&255, (addr>>8)&255, addr&255 );
- hosts = gethostbyaddr(addr, 4, AF_INET);
- }
- else {
- hosts = gethostbyname( name, 0 );
- }
- if( ! hosts ) {
- cwprintf(NULL, "unknown host\n" );
- return 1;
- }
- print_host( hosts );
- if( ! hosts->h_addr_list[0] ) cwprintf(NULL, "no ip address associated with name\n" );
- return 0;
- }
-
-
- static int doresolve_mx( int argc, char **argv )
- {
- struct hostent *hosts = NULL;
- char name[300];
-
- strcpy( name, argv[1] );
- hosts = gethostbyname( name, 1 );
- if( ! hosts )
- {
- cwprintf(NULL, "no mx record found\n" );
- return 1;
- }
- print_host( hosts );
- if( ! hosts->h_mx[0] )
- cwprintf(NULL, "no MX records associated with name\n" );
- return 0;
- }
-
-
- static int dotrace( int argc, char **argv )
- {
- if( argc>1 )
- {
- trace = atoi(argv[1]);
- if( trace ) _res.options |= RES_DEBUG;
- else _res.options &= (~RES_DEBUG);
- }
- else
- cwprintf(NULL, "trace level is %d\n", trace );
- return 0;
- }
-
-
- static int dotimeout( int argc, char **argv )
- {
- int tmp;
-
- if( argc>1 )
- {
- if( ! strcmp( argv[1], "none" ) )
- tmp = -1;
- else
- tmp = atoi(argv[1]);
- if( ! tmp )
- {
- cwprintf(NULL, "timeout cannot be 0 seconds (use 'none' for no timeout)\n" );
- return 1;
- }
- timeoutfact = tmp;
- }
- else
- cwprintf(NULL, "timeout is %d\n", timeoutfact);
- return 0;
- }
-
-
- static int docache( int argc, char **argv )
- {
- cache_print();
- return 0;
- }
-
-
- static int dosave( int argc, char **argv )
- {
- cache_save();
- return 0;
- }
-
-
- static int dopurge( int argc, char **argv )
- {
- cache_purge();
- return 0;
- }
-
-
- static int doload( int argc, char **argv )
- {
- cache_restore();
- return 0;
- }
-
- static int donames(int argc, char **argv)
- {
- if (argc>1)
- {
- if (!strncmp(argv[1], "on", strlen(argv[1])) ||
- !strncmp(argv[1], "yes", strlen(argv[1])))
- lookupnames = 1;
- else if (!strncmp(argv[1], "off", strlen(argv[1])) ||
- !strncmp(argv[1], "no", strlen(argv[1])))
- lookupnames = 0;
- else if (isdigit(*argv[1]))
- lookupnames = atoi(argv[1])!=0;
- else
- return 1;
- }
- else
- cwprintf(NULL, "Address to name lookups %s\r\n", (lookupnames)?"on":"off");
- return 0;
- }
-
- static struct cmds rescmds[] = {
- "cache", docache, 1, "resolve cache", NULLCHAR,
- "host", doresolve_host, 2, "resolve host <host>", NULLCHAR,
- "mx", doresolve_mx, 2, "resolve mx <host>", NULLCHAR,
- "names", donames, 1, "names [y|n]", NULLCHAR,
- "purge", dopurge, 1, "resolve purge", NULLCHAR,
- "restore", doload, 1, "resolve load", NULLCHAR,
- "save", dosave, 1, "resolve save", NULLCHAR,
- "timeout", dotimeout, 1, "resolve timeout [time|none]", NULLCHAR,
- "trace", dotrace, 1, "resolve trace [level]", NULLCHAR,
- NULLCHAR
- };
-
-
- int doresolve( int argc, char **argv )
- {
- return subcmd( rescmds, argc, argv );
- }
-
-
- static void print_host( struct hostent *host )
- {
- int i;
- char **clist;
- char *addr;
- struct mx_data **mxs;
-
- cwprintf(NULL, "host name : %s\n", host->h_name );
- if( host->h_aliases && host->h_aliases[0] )
- {
- cwprintf(NULL, "alias(es) : " );
- for( clist=host->h_aliases; clist[1]; clist++ )
- cwprintf(NULL, "%s, ", *clist );
- cwprintf(NULL, "%s\n", *clist );
- }
- if( host->h_addr_list && host->h_addr_list[0] )
- {
- cwprintf(NULL, "address(es): " );
- for( clist=host->h_addr_list; clist[0]; clist++ )
- {
- for( i=host->h_length-1,addr=clist[0]+host->h_length-1; i; i--,addr-- )
- cwprintf(NULL, "%d.", *(unsigned char *)addr );
- cwprintf(NULL, "%d", *(unsigned char *)addr );
- if( clist[1] )
- cwprintf(NULL, ", " );
- else
- cwprintf(NULL, "\n" );
- }
- }
- if( host->h_mx[0] )
- {
- cwprintf(NULL, "mx host(s) : " );
- for( mxs=host->h_mx; mxs[1]; mxs++ )
- cwprintf(NULL, "%s, ", (*mxs)->host );
- cwprintf(NULL, "%s\n", (*mxs)->host );
- }
- }
-
-
-
-
- int _mxresolve( char *dest )
- {
- struct hostent *he;
- char hname[260];
-
- he = gethostbyname( dest, 1 );
- if( he && he->h_mx[0] ) {
- strcpy( hname, he->h_mx[0]->host );
- dest = hname;
- }
- return resolve( dest );
- }
-
-
- int ipaddr( char *addr, unsigned int *iaddr )
- {
- unsigned int b1, b2, b3, b4;
-
- if( sscanf( addr, "%d.%d.%d.%d", &b1, &b2, &b3, &b4 ) < 4 )
- return -1;
- if( b1>255 || b2>255 || b3>255 || b4>255 )
- return -1;
- *iaddr = (b1<<24) + (b2<<16) + (b3<<8) + b4;
- return 0;
- }
-
- unsigned long res_inet_addr( char *name )
- {
- unsigned int addr;
-
- if (ipaddr( name, &addr ) )
- return -1;
- else
- return addr;
- }
-
- static void
- init_services(void)
- {
- char *cp, *dp, buf[BUFSIZ];
- register int cc = 0;
- FILE *fd;
- char *tdp = trimdomainbuf;
- char *hostconf;
- unsigned int cachesize = CACHE_SIZE;
-
- if(NULL==(hostconf=getenv(ENV_HOSTCONF)))
- {
- hostconf=_PATH_HOSTCONF;
- }
- if ((fd = (FILE *)fopen(hostconf, "r")) == NULL)
- {
- /* make some assumptions */
- service_order[0] = SERVICE_BIND;
- service_order[1] = SERVICE_NONE;
- }
- else
- {
- while (fgets(buf, BUFSIZ, fd) != NULL)
- {
- if ((cp = rindex(buf, '\n')) != NULL)
- *cp = '\0';
- if (buf[0] == '#')
- continue;
-
- #define checkbuf(b, cmd) (!strncasecmp(b, cmd, strlen(cmd)))
-
- if (checkbuf(buf, CMD_ORDER))
- {
- cp = strpbrk(buf, " \t");
- if (!cp)
- {
- bad_config_format(CMD_ORDER);
- }
- else
- {
- do
- {
- while (*cp == ' ' || *cp == '\t')
- cp++;
- dp = strpbrk(cp, TOKEN_SEPARATORS);
- if (dp) *dp = '\0';
- if (checkbuf(cp, ORD_BIND))
- service_order[cc++] = SERVICE_BIND;
- else if (checkbuf(cp, ORD_HOSTS))
- service_order[cc++] = SERVICE_HOSTS;
- else if (checkbuf(cp, ORD_NIS))
- service_order[cc++] = SERVICE_NIS;
- else
- {
- bad_config_format(CMD_ORDER);
- cwprintf(NULL, "resolv+: \"%s\" is an invalid keyword\n", cp);
- cwprintf(NULL, "resolv+: valid keywords are: %s, %s and %s\n",
- ORD_BIND, ORD_HOSTS, ORD_NIS);
- }
-
- if (dp) cp = ++dp;
- }
- while (dp != NULL);
- if (cc == 0)
- {
- bad_config_format(CMD_ORDER);
- cwprintf(NULL, "resolv+: search order not specified or unrecognized keyword, host resolution will fail.\n");
- }
- }
-
- }
- else if (checkbuf(buf, CMD_HMA)) {
- if ( cp = strpbrk(buf, " \t") )
- {
- while (*cp == ' ' || *cp == '\t') cp++;
- if (checkbuf(cp, CMD_ON))
- hosts_multiple_addrs = 1;
- }
- else
- bad_config_format(CMD_HMA);
-
- }
- else if (checkbuf(buf, CMD_SPOOF)) {
- if ( cp = strpbrk(buf, " \t") )
- {
- while (*cp == ' ' || *cp == '\t') cp++;
- if (checkbuf(cp, CMD_ON))
- spoof = 1;
- }
- else
- bad_config_format(CMD_SPOOF);
-
- }
- else if (checkbuf(buf, CMD_SPOOFALERT)) {
- if ( cp = strpbrk(buf, " \t") )
- {
- while (*cp == ' ' || *cp == '\t') cp++;
- if (checkbuf(cp, CMD_ON))
- spoofalert = 1;
- }
- else
- bad_config_format(CMD_SPOOFALERT);
-
- }
- else if (checkbuf(buf, CMD_REORDER)) {
- if (cp = strpbrk(buf, " \t")) {
- while (*cp == ' ' || *cp == '\t') cp++;
- if (checkbuf(cp, CMD_ON))
- reorder = 1;
- }
- else
- bad_config_format(CMD_REORDER);
-
- }
- else if (checkbuf(buf, CMD_TRIMDOMAIN)) {
- if(numtrimdomains<MAXTRIMDOMAINS){
- if ( cp = strpbrk(buf, " \t") )
- {
- while (*cp == ' ' || *cp == '\t') cp++;
- if (cp)
- {
- (void) strcpy(tdp,cp);
- trimdomain[numtrimdomains++]=tdp;
- tdp += strlen(cp)+1;
- }
- else
- bad_config_format(CMD_TRIMDOMAIN);
- }
- else
- bad_config_format(CMD_TRIMDOMAIN);
- }
- }
- else if (checkbuf(buf, CMD_CACHESIZE)) {
- if (cp = strpbrk(buf, " \t")) {
- while (*cp == ' ' || *cp == '\t') cp++;
- cachesize = atoi(cp);
- }
- else
- bad_config_format(CMD_CACHESIZE);
- }
- }
-
- service_order[cc] = SERVICE_NONE;
- }
- fclose(fd);
- /* override service_order if environment variable */
- if(NULL!=(cp=getenv(ENV_SERVORDER))){
- cc=0;
- if(NULL!=(cp=strtok(cp, TOKEN_SEPARATORS))){
- do{
- if(checkbuf(cp, ORD_BIND))
- service_order[cc++] = SERVICE_BIND;
- else if (checkbuf(cp, ORD_HOSTS))
- service_order[cc++] = SERVICE_HOSTS;
- else if (checkbuf(cp, ORD_NIS))
- service_order[cc++] = SERVICE_NIS;
- }
- while(cp=strtok(NULL, TOKEN_SEPARATORS));
- service_order[cc] = SERVICE_NONE;
- }
- }
- /* override spoof if environment variable */
- if(NULL!=(cp=getenv(ENV_SPOOF))){
- if(checkbuf(cp, CMD_WARN)){
- spoof=1;
- spoofalert=1;
- }
- else if (checkbuf(cp, CMD_OFF)){
- spoof=0;
- spoofalert=0;
- }
- else if (checkbuf(cp, CMD_NOWARN)){
- spoof=1;
- spoofalert=0;
- }
- else {
- spoof=1;
- }
- }
-
- /* override hma if environment variable */
- if(NULL!=(cp=getenv(ENV_HMA))) {
- if(checkbuf(cp, CMD_ON))
- hosts_multiple_addrs=1;
- else
- hosts_multiple_addrs=0;
- }
- /* override reorder if environment variable */
- if ((cp = getenv(ENV_REORDER)) != NULL) {
- if (checkbuf(cp, CMD_ON))
- reorder = 1;
- else
- reorder = 0;
- }
- /* add trimdomains from environment variable */
- if(NULL!=(cp=getenv(ENV_TRIM_ADD))){
- if(NULL!=(cp=strtok(cp, TOKEN_SEPARATORS))){
- do{
- if(numtrimdomains<MAXTRIMDOMAINS){
- (void)strcpy(tdp, cp);
- trimdomain[numtrimdomains++]=tdp;
- tdp += strlen(cp)+1;
- }
- }
- while(cp=strtok(NULL, TOKEN_SEPARATORS));
- }
- }
-
- /* override trimdomains from environment variable */
- if(NULL!=(cp=getenv(ENV_TRIM_OVERR))){
- numtrimdomains=0;
- tdp=trimdomainbuf;
- if(NULL!=(cp=strtok(cp, TOKEN_SEPARATORS))){
- do{
- if(numtrimdomains<MAXTRIMDOMAINS){
- (void)strcpy(tdp, cp);
- trimdomain[numtrimdomains++]=tdp;
- tdp += strlen(cp)+1;
- }
- }
- while(cp=strtok(NULL, TOKEN_SEPARATORS));
- }
- }
-
- /* override cache size if environment variable */
- if ((cp = getenv(ENV_CACHESIZE)) != NULL) {
- cachesize = atoi(cp);
- }
-
- cache_init(cachesize);
-
- service_done = 1;
- }
-
-
- static char *gethostname( char *name, int len )
- {
- extern char hostname[];
-
- strncpy( name, hostname, len );
- return name;
- }
-
-
- _sethtent(int f)
- {
- if (hostf == NULL)
- hostf = fopen(HOSTDB, "r" );
- else
- rewind(hostf);
- stayopen |= f;
- }
-
- _endhtent(void)
- {
- if (hostf && !stayopen) {
- (void) fclose(hostf);
- hostf = NULL;
- }
- }
-
- struct hostent *
- _gethtent(void)
- {
- char *p;
- register char *cp, **q;
-
- if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL)
- return (NULL);
- again:
- if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
- return (NULL);
-
- { /* Little patch to ensure variables are translated in the hosts file */
- char xbuf[BUFSIZ];
- var_translate(global_vars, hostbuf, 0, xbuf, BUFSIZ);
- strcpy(hostbuf, xbuf);
- }
- if (*p == '#')
- goto again;
- cp = strpbrk(p, "#\n");
- if (cp == NULL)
- goto again;
- *cp = '\0';
- cp = strpbrk(p, " \t");
- if (cp == NULL)
- goto again;
- *cp++ = '\0';
- /* THIS STUFF IS INTERNET SPECIFIC */
- #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
- host.h_addr_list = host_addrs;
- #endif
- host.h_addr = hostaddr;
- *((u_long *)host.h_addr) = res_inet_addr(p);
- host.h_mx = mx_ptrs;
- mx_ptrs[0] = NULL;
- host.h_length = sizeof (u_long);
- host.h_addrtype = AF_INET;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- host.h_name = cp;
- q = host.h_aliases = host_aliases;
- cp = strpbrk(cp, " \t");
- if (cp != NULL)
- *cp++ = '\0';
- while (cp && *cp) {
- if (*cp == ' ' || *cp == '\t') {
- cp++;
- continue;
- }
- if (q < &host_aliases[MAXALIASES - 1])
- *q++ = cp;
- cp = strpbrk(cp, " \t");
- if (cp != NULL)
- *cp++ = '\0';
- }
- *q = NULL;
- return (&host);
- }
-
-
-
- static u_long ntohl(u_long t)
- {
- union {
- u_long l;
- u_char b[4];
- }
- tr;
- tr.b[0] = t>>24;
- tr.b[1] = t>>16;
- tr.b[2] = t>>8;
- tr.b[3] = t;
- return tr.l;
- }
-
- static u_short ntohs( u_short t )
- {
- union {
- u_short l;
- u_char b[2];
- }
- tr;
-
- tr.b[0] = t>>8;
- tr.b[1] = t;
- return tr.l;
- }
-
- static u_short htons( u_short t )
- {
- union {
- u_short l;
- u_char b[4];
- }
- tr;
-
- tr.b[0] = t>>8;
- tr.b[1] = t;
- return tr.l;
- }
-
-
- void revcopy( char *s, char *d, int n )
- {
- for( s+=n; n; n-- ) *(d++) = *(--s);
- }
-
-
- int _mx_sort(const void *o1, const void *o2)
- {
- if (((struct mx_data *) o1)->preference < ((struct mx_data *) o2)->preference)
- return -1;
- else if (((struct mx_data *) o1)->preference == ((struct mx_data *) o2)->preference )
- return 0;
- else
- return 1;
- }
-
-
- static struct hostent *
- getanswer(querybuf *answer, int anslen, int iquery, int mxquery, long *ansttl)
- {
- register HEADER *hp;
- register u_char *cp;
- register int n;
- u_char *eom;
- char *bp, **ap;
- int type, class, buflen, ancount, qdcount;
- int haveanswer, getclass = C_ANY;
- char **hap;
- struct mx_data **mx, *nextmx;
- int mxrecs=0;
- long ttl;
-
- *ansttl = 0x7fffffff;
- eom = answer->buf + anslen;
- /*
- * find first satisfactory answer
- */
- hp = &answer->hdr;
- ancount = ntohs(hp->ancount);
- qdcount = ntohs(hp->qdcount);
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "Got %d answers and %d questions\n", ancount, qdcount);
- #endif /* DEBUG */
- bp = hostbuf;
- buflen = sizeof(hostbuf);
- cp = answer->buf + sizeof(HEADER);
- if (qdcount) {
- if (iquery || mxquery) {
- if ((n = dn_expand((char *)answer->buf, eom,
- cp, bp, buflen)) < 0) {
- h_errno = NO_RECOVERY;
- return ((struct hostent *) NULL);
- }
- cp += n + QFIXEDSZ;
- host.h_name = bp;
- n = strlen(bp) + 1;
- bp += n;
- buflen -= n;
- }
- else
- cp += dn_skipname(cp, eom) + QFIXEDSZ;
- while (--qdcount > 0)
- cp += dn_skipname(cp, eom) + QFIXEDSZ;
- }
- else if (iquery) {
- if (hp->aa)
- h_errno = HOST_NOT_FOUND;
- else
- h_errno = TRY_AGAIN;
- return ((struct hostent *) NULL);
- }
- ap = host_aliases;
- *ap = NULL;
- host.h_aliases = host_aliases;
- hap = h_addr_ptrs;
- *hap = NULL;
- host.h_mx = mx_ptrs;
- mx = mx_ptrs;
- *mx = NULL;
- nextmx = mx_conts;
- #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
- host.h_addr_list = h_addr_ptrs;
- #endif
- haveanswer = 0;
- while (--ancount >= 0 && cp < eom) {
- if ((n = dn_expand((char *)answer->buf, eom, cp, bp, buflen)) < 0)
- break;
- cp += n;
- type = _getshort(cp);
- cp += sizeof(u_short);
- class = _getshort(cp);
- cp += sizeof(u_short);
- if ((ttl = _getlong(cp)) < *ansttl)
- *ansttl = ttl;
- cp += sizeof(u_long);
- n = _getshort(cp);
- cp += sizeof(u_short);
- if (type == T_CNAME) {
- cp += n;
- if (ap >= &host_aliases[MAXALIASES-1])
- continue;
- *ap++ = bp;
- n = strlen(bp) + 1;
- bp += n;
- buflen -= n;
- mxrecs++;
- continue;
- }
- if (type == T_MX) { /* MX record */
- int i;
- if( trace ) cwprintf(NULL, "MX record in answer\n" );
- if ((i = dn_expand((char *)answer->buf, eom, cp+sizeof(u_short), bp, buflen)) < 0) {
- cp += n;
- continue;
- }
- *mx = nextmx++;
- mxrecs++;
- mx[1] = NULL;
- (*mx)->preference = _getshort(cp);
- (*mx)->host = bp;
- mx++;
- if( trace ) cwprintf(NULL, "MX host: %s\n", bp );
- cp += n;
- n = strlen(bp) + 1;
- bp += n;
- buflen -= n;
- continue;
- }
- if (iquery && type == T_PTR) {
- if ((n = dn_expand((char *)answer->buf, eom,
- cp, bp, buflen)) < 0) {
- cp += n;
- continue;
- }
- cp += n;
- host.h_name = bp;
- return(&host);
- }
- if (iquery || type != T_A) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- printf("unexpected answer type %d, size %d\n",
- type, n);
- #endif
- cp += n;
- continue;
- }
- if (haveanswer) {
- if (n != host.h_length) {
- cp += n;
- continue;
- }
- if (class != getclass) {
- cp += n;
- continue;
- }
- }
- else {
- host.h_length = n;
- getclass = class;
- host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
- if (!iquery) {
- host.h_name = bp;
- bp += strlen(bp) + 1;
- }
- }
-
- bp += sizeof(align) - ((u_long)bp % sizeof(align));
-
- if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- printf("size (%d) too big\n", n);
- #endif
- break;
- }
- revcopy((char *)cp, *hap++ = bp, n);
- bp +=n;
- cp += n;
- haveanswer++;
- }
- if (haveanswer || (mxquery && mxrecs) ) {
- *ap = NULL;
- #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
- *hap = NULL;
- #else
- host.h_addr = h_addr_ptrs[0];
- #endif
- if (mxrecs)
- qsort(mx_conts, mxrecs, sizeof(struct mx_data), _mx_sort);
- return(&host);
- }
- else
- {
- h_errno = TRY_AGAIN;
- return ((struct hostent *) NULL);
- }
- }
-
-
-
- static void
- dotrimdomain(char *c)
- {
- /* assume c points to the start of a host name; trim off any
- domain name matching any of the trimdomains */
- int d,l1,l2;
-
- for(d=0;d<numtrimdomains;d++){
- l1=strlen(trimdomain[d]);
- l2=strlen(c);
- if(l2>l1 && !strcasecmp(c+l2-l1,trimdomain[d]))
- *(c+(strlen(c)-l1))='\0';
- }
- }
-
- static struct hostent *
- trim_domains(struct hostent *h)
- {
- if(numtrimdomains){
- int i;
- dotrimdomain(h->h_name);
- for(i=0;h->h_aliases[i];i++)
- dotrimdomain(h->h_aliases[i]);
- }
- return(h);
- }
-
-
- struct hostent *
- _gethtbyaddr(int addr, int len, int type)
- {
- register struct hostent *p;
- register char **cp;
- int found=0;
-
- /* Reset the hosts file */
- _sethtent(0);
-
- /* Loop over the entries from the hosts file */
- while (p = _gethtent()) {
-
- /* Look for a matching address */
- if ((p->h_length == len) && (p->h_addrtype == type))
- for (cp = p->h_addr_list; *cp != 0; cp++)
- if (memcmp(*cp, &addr, p->h_length) == 0)
- found++;
-
- /* Found the address */
- if (found) {
- _endhtent();
- return(p);
- }
- }
-
- /* Finish with the hosts file */
- _endhtent();
-
- return((struct hostent *)NULL);
- }
-
- struct hostent *gethostbyaddr(unsigned int addr, int len, int type)
- {
- char name[128];
- querybuf buf;
- int n;
- register int cc;
- struct hostent *hp;
- long ttl;
-
- /* See if the address is already cached */
- if(!cache_req(&addr, CACHE_ADDR, len, &hp))
- return hp;
-
- /* Initalise if necessary */
- if ((_res.options & RES_INIT) == 0)
- resolve_init();
- if (!service_done)
- init_services();
-
- /* Loop over the service order list, trying to find the target */
- for (cc = 0; service_order[cc] != SERVICE_NONE && cc <= SERVICE_MAX; cc++) {
- switch (service_order[cc]) {
- case SERVICE_BIND:
- if ((type != AF_INET) || (len != 4))
- break;
- sprintf(name, "%d.%d.%d.%d.IN-ADDR.ARPA", addr&255,
- (addr>>8)&255, (addr>>16)&255, addr>>24);
- if ((n = res_query(name, C_IN, T_PTR, buf.buf, sizeof(buf))) < 0) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_query failed\n");
- #endif
- break;
- }
- hp = getanswer(&buf, n, 1, 0, &ttl);
- /* if (h_addr_ptrs[1] && reorder)
- reorder_addrs(hp); we do never reorder */
- if (hp) {
- hp = trim_domains(hp);
- hp->h_length = len;
- hp->h_addrtype = type;
- hp->h_addr_list[0] = hostbuf;
- bcopy(&addr, hostbuf, len);
- hp->h_addr_list[1] = 0;
- cache_it(&addr, CACHE_ADDR, len, hp, ttl);
- return hp;
- }
- break;
-
- case SERVICE_HOSTS:
- hp = _gethtbyaddr(addr, len, type);
- /* if (h_addr_ptrs[1] && reorder)
- reorder_addrs(hp); we do never reorder */
- if (hp) {
- cache_it(&addr, CACHE_ADDR, len, hp, CACHE_OBSOLETE);
- return hp;
- }
- h_errno = HOST_NOT_FOUND;
- break;
-
- #ifdef NIS
- case SERVICE_NIS:
- hp = _getnishost(name, "hosts.byaddr");
- /* if (h_addr_ptrs[1] && reorder)
- reorder_addrs(hp); we do never reorder */
- if (hp) {
- cache_it(&addr, CACHE_ADDR, len, hp, CACHE_OBSOLETE);
- return hp;
- }
- h_errno = HOST_NOT_FOUND;
- break;
- #endif
- }
- }
-
- /* Cache the fact that we can't find the address */
- cache_it(&addr, CACHE_ADDR, len, NULL, CACHE_OBSOLETE);
-
- return NULL;
- }
-
- /* if hosts_multiple_addrs set, then gethtbyname behaves as follows:
- * - for hosts with multiple addresses, return all addresses, such that
- * the first address is most likely to be one on the same net as the
- * host we're running on, if one exists.
- * - like the dns version of gethostsbyname, the alias field is empty
- * unless the name being looked up is an alias itself, at which point the
- * alias field contains that name, and the name field contains the primary
- * name of the host. Unlike dns, however, this behavior will still take place
- * even if the alias applies only to one of the interfaces.
- * - determining a "local" address to put first is dependant on the netmask
- * being such that the least significant network bit is more significant
- * than any host bit. Only strange netmasks will violate this.
- * - we assume addresses fit into u_longs. That's quite internet specific.
- * - if the host we're running on is not in the host file, the address
- * shuffling will not take place.
- * - John DiMarco <jdd@cdf.toronto.edu>
- */
- struct hostent *
- _gethtbyname(char *name)
- {
- register struct hostent *p;
- register char **cp;
- char **hap, **lhap, *bp, *lbp;
- int htbuflen, locbuflen;
- int found=0, localfound=0;
- char localname[MAXHOSTNAMELEN];
-
- static char htbuf[BUFSIZ+1]; /* buffer for host addresses */
- static char locbuf[BUFSIZ+1]; /* buffer for local hosts's addresses */
- static char *ht_addr_ptrs[MAXADDRS+1];
- static char *loc_addr_ptrs[MAXADDRS+1];
- static struct hostent ht;
- static char *aliases[MAXALIASES];
- static char namebuf[MAXHOSTNAMELEN];
- static struct mx_data *dummymx[1];
-
- hap = ht_addr_ptrs;
- lhap = loc_addr_ptrs;
- *hap = NULL;
- *lhap = NULL;
- bp=htbuf;
- lbp=locbuf;
- htbuflen = sizeof(htbuf);
- locbuflen = sizeof(locbuf);
- ht.h_mx = dummymx;
- dummymx[0] = NULL;
-
- aliases[0]=NULL;
- aliases[1]=NULL;
- (void) strcpy(namebuf, name);
-
- (void)gethostname(localname, sizeof(localname));
-
- _sethtent(0);
- while (p = _gethtent()) {
- if (strcasecmp(p->h_name, name) == 0)
- found++;
- else
- for (cp = p->h_aliases; *cp != 0; cp++)
- if (strcasecmp(*cp, name) == 0){
- found++;
- aliases[0]=name;
- (void) strcpy(namebuf, p->h_name);
- }
- if (strcasecmp(p->h_name, localname) == 0)
- localfound++;
- else
- for (cp=p->h_aliases; *cp != 0; cp++)
- if (strcasecmp(*cp, localname) == 0)
- localfound++;
-
- if(found){
- int n;
-
- if(!hosts_multiple_addrs){
- /* original behaviour requested */
- _endhtent();
- return(p);
- }
- n = p->h_length;
-
- ht.h_addrtype = p->h_addrtype;
- ht.h_length = p->h_length;
-
- if(n<=htbuflen){
- /* add the found address to the list */
- bcopy(p->h_addr_list[0], bp, n);
- *hap++=bp;
- *hap=NULL;
- bp+=n;
- htbuflen-=n;
- }
- found=0;
- }
- if(localfound){
- int n = p->h_length;
- if(n<=locbuflen){
- /* add the found local address to the list */
- bcopy(p->h_addr_list[0], lbp, n);
- *lhap++=lbp;
- *lhap=NULL;
- lbp+=n;
- locbuflen-=n;
- }
- localfound=0;
- }
- }
- _endhtent();
-
- if(NULL==ht_addr_ptrs[0]){
- return((struct hostent *)NULL);
- }
-
- ht.h_aliases = aliases;
- ht.h_name = namebuf;
-
- /* shuffle addresses around to ensure one on same net as local host
- is first, if exists */
- {
- /* "best" address is assumed to be the one with the greatest
- number of leftmost bits matching any of the addresses of
- the local host. This assumes a netmask in which all net
- bits precede host bits. Usually but not always a fair
- assumption. */
-
- /* portability alert: assumption: iaddr fits in u_long.
- This is really internet specific. */
- int i,j, best=0;
- u_long bestval = (u_long)~0;
-
- for(i=0;loc_addr_ptrs[i];i++){
- for(j=0;ht_addr_ptrs[j];j++){
- u_long t, l, h;
- /* assert(sizeof(u_long)>=ht.h_length); */
- bcopy(loc_addr_ptrs[i], (char *)&t,
- ht.h_length);
- l=ntohl(t);
- bcopy(ht_addr_ptrs[j], (char *)&t,
- ht.h_length);
- t=l^h;
-
- if(t<bestval){
- best=j;
- bestval=t;
- }
- }
- }
- if(best){
- char *tmp;
-
- /* swap first and best address */
- tmp=ht_addr_ptrs[0];
- ht_addr_ptrs[0]=ht_addr_ptrs[best];
- ht_addr_ptrs[best]=tmp;
- }
- }
-
- ht.h_addr_list = ht_addr_ptrs;
- return (&ht);
- }
-
-
- struct hostent *gethostbyname(char *name, int mxquery)
- {
- querybuf buf;
- register char *cp;
- register int cc;
- int n;
- struct hostent *hp;
- long ttl;
- extern struct hostent *_gethtbyname();
-
- if( !cache_req(name,mxquery?CACHE_MX:CACHE_NAME,strlen(name),&hp) ) return hp;
- if ((_res.options & RES_INIT) == 0)
- resolve_init();
- /*
- * disallow names consisting only of digits/dots, unless
- * they end in a dot.
- */
- if (isdigit(name[0]))
- for (cp = name;; ++cp) {
- if (!*cp) {
- if (*--cp == '.')
- break;
- /*
- * All-numeric, no dot at the end.
- * Fake up a hostent as if we'd actually
- * done a lookup. What if someone types
- * 255.255.255.255? The test below will
- * succeed spuriously... ???
- */
- if ((host_addr.s_addr = res_inet_addr(name)) == -1) {
- h_errno = HOST_NOT_FOUND;
- cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), NULL, CACHE_OBSOLETE );
- return((struct hostent *) NULL);
- }
- host.h_name = name;
- host.h_aliases = host_aliases;
- host_aliases[0] = NULL;
- host.h_addrtype = AF_INET;
- host.h_length = sizeof(u_long);
- h_addr_ptrs[0] = (char *)&host_addr;
- h_addr_ptrs[1] = (char *)0;
- #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
- host.h_addr_list = h_addr_ptrs;
- #else
- host.h_addr = h_addr_ptrs[0];
- #endif
- cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), &host, CACHE_OBSOLETE );
- return (&host);
- }
- if (!isdigit(*cp) && *cp != '.')
- break;
- }
-
- if (!service_done)
- init_services();
-
- for (cc = 0; service_order[cc] != SERVICE_NONE &&
- cc <= SERVICE_MAX; cc++) {
- switch (service_order[cc]) {
- case SERVICE_BIND:
- if ((n = res_search(name, C_IN, mxquery?T_MX:T_A,
- buf.buf, sizeof(buf))) < 0) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_search failed\n");
- #endif
- break;
- }
- hp = getanswer(&buf, n, 0, mxquery, &ttl);
- /* if (h_addr_ptrs[1] && reorder)
- reorder_addrs(hp); we do never reorder */
- if (hp) {
- hp = trim_domains(hp);
- cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), hp, ttl );
- return hp;
- }
- break;
-
- case SERVICE_HOSTS:
- if (mxquery) break; /* MX records are not recorded in 'hosts' file */
-
- hp = _gethtbyname(name);
- /* if (h_addr_ptrs[1] && reorder)
- reorder_addrs(hp); we do never reorder */
- if (hp) {
- cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), hp, CACHE_OBSOLETE );
- return hp;
- }
- h_errno = HOST_NOT_FOUND;
- break;
- #ifdef NIS
- case SERVICE_NIS:
- hp = _getnishost(name, "hosts.byname");
- /* if (h_addr_ptrs[1] && reorder)
- reorder_addrs(hp); we do never reorder */
- if (hp) {
- cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), hp, CACHE_OBSOLETE );
- return hp;
- }
- h_errno = HOST_NOT_FOUND;
- break;
- #endif
- }
- }
- cache_it( name, mxquery?CACHE_MX:CACHE_NAME, strlen(name), NULL, CACHE_OBSOLETE );
- return ((struct hostent *) NULL);
- }
-
-
-
- /*
- * This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
- * based upon ascii character sequences.
- */
- static u_char charmap[] = {
- '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
- '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
- '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
- '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
- '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
- '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
- '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
- '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
- '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
- '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
- '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
- '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
- '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
- '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
- '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
- '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
- '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
- '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
- '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
- '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
- '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
- '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
- '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
- '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
- '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
- '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
- '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
- '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
- '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
- '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
- '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
- '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
- };
-
- int
- strcasecmp(char *s1, char *s2)
- {
- register u_char *cm = charmap,
- *us1 = (u_char *)s1,
- *us2 = (u_char *)s2;
-
- while (cm[*us1] == cm[*us2++])
- if (*us1++ == '\0')
- return(0);
- return(cm[*us1] - cm[*--us2]);
- }
-
- int
- strncasecmp(char *s1, char *s2, register int n)
- {
- register u_char *cm = charmap,
- *us1 = (u_char *)s1,
- *us2 = (u_char *)s2;
-
- while (--n >= 0 && cm[*us1] == cm[*us2++])
- if (*us1++ == '\0')
- return(0);
- return(n < 0 ? 0 : cm[*us1] - cm[*--us2]);
- }
-
-
- char *hostalias(char *);
-
- int
- res_query(char *name, int class, int type, u_char *answer, int anslen)
- /* size of answer buffer */
- {
- char buf[MAXPACKET];
- HEADER *hp;
- int n;
-
- if ((_res.options & RES_INIT) == 0 && resolve_init() == -1)
- return (-1);
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_query(%s, %d, %d)\n", name, class, type);
- #endif
- n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL,
- buf, sizeof(buf));
-
- if (n <= 0) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_query: mkquery failed\n");
- #endif
- h_errno = NO_RECOVERY;
- return (n);
- }
- n = res_send(buf, n, answer, anslen);
- if (n < 0) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_query: send error\n");
- #endif
- h_errno = TRY_AGAIN;
- return(n);
- }
-
- hp = (HEADER *) answer;
- if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "rcode = %d, ancount=%d\n", hp->rcode,
- ntohs(hp->ancount));
- #endif
- switch (hp->rcode) {
- case NXDOMAIN:
- h_errno = HOST_NOT_FOUND;
- break;
- case SERVFAIL:
- h_errno = TRY_AGAIN;
- break;
- case NOERROR:
- h_errno = NO_DATA;
- break;
- case FORMERR:
- case NOTIMP:
- case REFUSED:
- default:
- h_errno = NO_RECOVERY;
- break;
- }
- return (-1);
- }
- return(n);
- }
-
-
- /*
- * Perform a call on res_query on the concatenation of name and domain,
- * removing a trailing dot from name if domain is NULL.
- */
- int
- res_querydomain(char *name, char *domain, int class, int type,
- u_char *answer, int anslen)
- /* size of answer */
- {
- char nbuf[2*MAXDNAME+2];
- char *longname = nbuf;
- int n;
-
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_querydomain(%s, %s, %d, %d)\n",
- name, domain?domain:"", class, type);
- #endif
- if (domain == NULL) {
- /*
- * Check for trailing '.';
- * copy without '.' if present.
- */
- n = strlen(name) - 1;
- if (name[n] == '.' && n < sizeof(nbuf) - 1) {
- bcopy(name, nbuf, n);
- nbuf[n] = '\0';
- }
- else
- longname = name;
- }
- else
- (void)sprintf(nbuf, "%.*s.%.*s",
- MAXDNAME, name, MAXDNAME, domain);
-
- return (res_query(longname, class, type, answer, anslen));
- }
-
-
- int
- res_search(char *name, int class, int type, u_char *answer, int anslen)
- /* size of answer */
- {
- register char *cp, **domain;
- int n, ret, got_nodata = 0;
- char *hostalias();
-
- if ((_res.options & RES_INIT) == 0 && resolve_init() == -1)
- return (-1);
-
- errno = 0;
- h_errno = HOST_NOT_FOUND; /* default, if we never query */
- if( type == T_MX ) {
- ret = res_querydomain(name, (char *)NULL, class, type, answer, anslen);
- return ret; /* do not use 'searches' for MX find */
- }
-
- for (cp = name, n = 0; *cp; cp++)
- if (*cp == '.')
- n++;
- if (n == 0 && (cp = hostalias(name)))
- return (res_query(cp, class, type, answer, anslen));
-
- /*
- * If it has two or more dots there is a good change it is
- * fully qualified so try it first.
- */
- if ((n >= 2) && (ret = res_querydomain(name, (char *)NULL, class,
- type, answer, anslen)) > 0)
- return (ret);
-
- /*
- * We do at least one level of search if
- * - there is no dot and RES_DEFNAME is set, or
- * - there is at least one dot, there is no trailing dot,
- * and RES_DNSRCH is set.
- */
- if ((n == 0 && _res.options & RES_DEFNAMES) ||
- (n != 0 && *--cp != '.' && _res.options & RES_DNSRCH))
- for (domain = _res.dnsrch; *domain; domain++) {
- ret = res_querydomain(name, *domain, class, type,
- answer, anslen);
- if (ret > 0)
- return (ret);
- /*
- * If no server present, give up.
- * If name isn't found in this domain,
- * keep trying higher domains in the search list
- * (if that's enabled).
- * On a NO_DATA error, keep trying, otherwise
- * a wildcard entry of another type could keep us
- * from finding this entry higher in the domain.
- * If we get some other error (negative answer or
- * server failure), then stop searching up,
- * but try the input name below in case it's fully-qualified.
- */
- if (errno == ECONNREFUSED) {
- h_errno = TRY_AGAIN;
- return (-1);
- }
- if (h_errno == NO_DATA)
- got_nodata++;
- if ((h_errno != HOST_NOT_FOUND && h_errno != NO_DATA) ||
- (_res.options & RES_DNSRCH) == 0)
- break;
- }
- /*
- * If the search/default failed, try the name as fully-qualified,
- * but only if it contained at least one dot (even trailing).
- * This is purely a heuristic; we assume that any reasonable query
- * about a top-level domain (for servers, SOA, etc) will not use
- * res_search.
- */
- if (n && (ret = res_querydomain(name, (char *)NULL, class, type,
- answer, anslen)) > 0)
- return (ret);
- if (got_nodata)
- h_errno = NO_DATA;
- return (-1);
- }
-
-
- char *
- hostalias(register char *name)
- {
- register char *C1, *C2;
- FILE *fp;
- char *file;
- char buf[BUFSIZ];
- static char abuf[MAXDNAME];
-
- file = getenv("HOSTALIASES");
- if (file == NULL || (fp = fopen(file, "r")) == NULL)
- return (NULL);
- buf[sizeof(buf) - 1] = '\0';
- while (fgets(buf, sizeof(buf), fp)) {
- for (C1 = buf; *C1 && !isspace(*C1); ++C1);
- if (!*C1)
- break;
- *C1 = '\0';
- if (!strcasecmp(buf, name)) {
- while (isspace(*++C1));
- if (!*C1)
- break;
- for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
- abuf[sizeof(abuf) - 1] = *C2 = '\0';
- (void)strncpy(abuf, C1, sizeof(abuf) - 1);
- fclose(fp);
- return (abuf);
- }
- }
- fclose(fp);
- return (NULL);
- }
-
-
-
- /*
- * Form all types of queries.
- * Returns the size of the result or -1.
- */
- int
- res_mkquery(int op, char *dname, int class, int type, char *data,
- int datalen, struct rrec *newrr, char *buf, int buflen)
- /* size of buffer */
- {
- register HEADER *hp;
- register char *cp;
- register int n;
- char *dnptrs[10], **dpp, **lastdnptr;
-
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
- #endif /* DEBUG */
- /*
- * Initialize header fields.
- */
- if ((buf == NULL) || (buflen < sizeof(HEADER)))
- return(-1);
- bzero(buf, sizeof(HEADER));
- hp = (HEADER *) buf;
- hp->id = htons(++_res.id);
- hp->opcode = op;
- hp->pr = (_res.options & RES_PRIMARY) != 0;
- hp->rd = (_res.options & RES_RECURSE) != 0;
- hp->rcode = NOERROR;
- cp = buf + sizeof(HEADER);
- buflen -= sizeof(HEADER);
- dpp = dnptrs;
- *dpp++ = buf;
- *dpp++ = NULL;
- lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
- /*
- * perform opcode specific processing
- */
- switch (op) {
- case QUERY:
- if ((buflen -= QFIXEDSZ) < 0)
- return(-1);
- if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
- return (-1);
- cp += n;
- buflen -= n;
- putshort(type, cp);
- cp += sizeof(u_short);
- putshort(class, cp);
- cp += sizeof(u_short);
- hp->qdcount = htons(1);
- if (op == QUERY || data == NULL)
- break;
- /*
- * Make an additional record for completion domain.
- */
- buflen -= RRFIXEDSZ;
- if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
- return (-1);
- cp += n;
- buflen -= n;
- putshort(T_NULL, cp);
- cp += sizeof(u_short);
- putshort(class, cp);
- cp += sizeof(u_short);
- putlong(0, cp);
- cp += sizeof(u_long);
- putshort(0, cp);
- cp += sizeof(u_short);
- hp->arcount = htons(1);
- break;
-
- case IQUERY:
- /*
- * Initialize answer section
- */
- if (buflen < 1 + RRFIXEDSZ + datalen)
- return (-1);
- *cp++ = '\0'; /* no domain name */
- putshort(type, cp);
- cp += sizeof(u_short);
- putshort(class, cp);
- cp += sizeof(u_short);
- putlong(0, cp);
- cp += sizeof(u_long);
- putshort(datalen, cp);
- cp += sizeof(u_short);
- if (datalen) {
- bcopy(data, cp, datalen);
- cp += datalen;
- }
- hp->ancount = htons(1);
- break;
-
- #ifdef ALLOW_UPDATES
- /*
- * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
- * (Record to be modified is followed by its replacement in msg.)
- */
- case UPDATEM:
- case UPDATEMA:
-
- case UPDATED:
- /*
- * The res code for UPDATED and UPDATEDA is the same; user
- * calls them differently: specifies data for UPDATED; server
- * ignores data if specified for UPDATEDA.
- */
- case UPDATEDA:
- buflen -= RRFIXEDSZ + datalen;
- if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
- return (-1);
- cp += n;
- putshort(type, cp);
- cp += sizeof(u_short);
- putshort(class, cp);
- cp += sizeof(u_short);
- putlong(0, cp);
- cp += sizeof(u_long);
- putshort(datalen, cp);
- cp += sizeof(u_short);
- if (datalen) {
- bcopy(data, cp, datalen);
- cp += datalen;
- }
- if ( (op == UPDATED) || (op == UPDATEDA) ) {
- hp->ancount = htons(0);
- break;
- }
- /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
-
- case UPDATEA: /* Add new resource record */
- buflen -= RRFIXEDSZ + datalen;
- if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
- return (-1);
- cp += n;
- putshort(newrr->r_type, cp);
- cp += sizeof(u_short);
- putshort(newrr->r_class, cp);
- cp += sizeof(u_short);
- putlong(0, cp);
- cp += sizeof(u_long);
- putshort(newrr->r_size, cp);
- cp += sizeof(u_short);
- if (newrr->r_size) {
- bcopy(newrr->r_data, cp, newrr->r_size);
- cp += newrr->r_size;
- }
- hp->ancount = htons(0);
- break;
-
- #endif /* ALLOW_UPDATES */
- }
- return (cp - buf);
- }
-
-
-
-
- /*
- * Set up default settings. If the configuration file exist, the values
- * there will have precedence. Otherwise, the server address is set to
- * INADDR_ANY and the default domain name comes from the gethostname().
- *
- * The configuration file should only be used if you want to redefine your
- * domain or run without a server on your machine.
- *
- * Return 0 if completes successfully, -1 on error
- */
- int
- resolve_init(void)
- {
- register FILE *fp;
- register char *cp, **pp;
- register int n;
- char buf[BUFSIZ];
- extern u_long res_inet_addr();
- extern char *index();
- extern char *strcpy(), *strncpy();
- extern char *getenv();
- int nserv = 0; /* number of nameserver records read from file */
- int haveenv = 0;
- int havesearch = 0;
-
- _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
- _res.nsaddr.sin_family = AF_INET;
- _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
- _res.nscount = 1;
-
- /* Allow user to override the local domain definition */
- if ((cp = getenv("LOCALDOMAIN")) != NULL) {
- (void)strncpy(_res.defdname, cp, sizeof(_res.defdname));
- haveenv++;
- }
-
- if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
- /* read the config file */
- while (fgets(buf, sizeof(buf), fp) != NULL) {
- /* read default domain name */
-
- { /* Little patch to ensure variables are translated in the resconf file */
- char xbuf[BUFSIZ];
- var_translate(global_vars, buf, 0, xbuf, BUFSIZ);
- strcpy(buf, xbuf);
- }
-
- if (!strncmp(buf, "domain", sizeof("domain") - 1)) {
- if (haveenv) /* skip if have from environ */
- continue;
- cp = buf + sizeof("domain") - 1;
- while (*cp == ' ' || *cp == '\t' || *cp == '.')
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
- if ((cp = index(_res.defdname, '\n')) != NULL)
- *cp = '\0';
- havesearch = 0;
- continue;
- }
- /* debug */
- if( !strncmp(buf, "debug", sizeof("debug") - 1)) _res.options |= RES_DEBUG;
-
- /* set search list */
- if (!strncmp(buf, "search", sizeof("search") - 1)) {
- if (haveenv) /* skip if have from environ */
- continue;
- cp = buf + sizeof("search") - 1;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
- if ((cp = index(_res.defdname, '\n')) != NULL)
- *cp = '\0';
- /*
- * Set search list to be blank-separated strings
- * on rest of line.
- */
- cp = _res.defdname;
- pp = _res.dnsrch;
- *pp++ = cp;
- for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
- if (*cp == ' ' || *cp == '\t') {
- *cp = 0;
- n = 1;
- }
- else if (n) {
- *pp++ = cp;
- n = 0;
- }
- }
- /* null terminate last domain if there are excess */
- while (*cp != '\0' && *cp != ' ' && *cp != '\t')
- cp++;
- *cp = '\0';
- *pp++ = 0;
- havesearch = 1;
- continue;
- }
- /* read nameservers to query */
- if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) &&
- nserv < MAXNS) {
- cp = buf + sizeof("nameserver") - 1;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- if ((*cp == '\0') || (*cp == '\n'))
- continue;
- if ((_res.nsaddr_list[nserv].sin_addr.s_addr =
- res_inet_addr(cp)) == (unsigned)-1) {
- _res.nsaddr_list[nserv].sin_addr.s_addr
- = INADDR_ANY;
- continue;
- }
- _res.nsaddr_list[nserv].sin_family = AF_INET;
- _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT);
- nserv++;
- continue;
- }
- }
- if (nserv > 1)
- _res.nscount = nserv;
- (void) fclose(fp);
- }
- if (_res.defdname[0] == 0) {
- if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
- (cp = index(buf, '.')))
- (void)strcpy(_res.defdname, cp + 1);
- }
-
- /* find components of local domain that might be searched */
- if (havesearch == 0) {
- pp = _res.dnsrch;
- *pp++ = _res.defdname;
- for (cp = _res.defdname, n = 0; *cp; cp++)
- if (*cp == '.')
- n++;
- cp = _res.defdname;
- for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH;
- n--) {
- cp = index(cp, '.');
- *pp++ = ++cp;
- }
- *pp++ = 0;
- }
- _res.options |= RES_INIT;
- return (0);
- }
-
-
- static struct sockaddr no_addr;
-
- static void rs_rec(struct tcb *, int16);
- static void rs_cts(struct tcb *, int16);
- static void rs_state(struct tcb *, char, char);
- static void rs_init( void );
- static void poll( int to );
- static struct tcb *tcb;
- static void sendit( void *, int );
- static char tcpinbuff[TCPINBUFFLEN];
- static int tcpinbuff_ptr = 0;
-
- static int read( char *, int );
-
- static enum {
- state_SYNC,
- state_ESTABLISHED,
- state_CLOSED,
- state_TIMEOUT
- }
- state;
-
- static char *states[] = {
- "state_SYNC",
- "state_ESTABLISHED",
- "state_CLOSED",
- "state_TIMEOUT"
- };
-
-
- #ifndef FD_SET
- #define NFDBITS 32
- #define FD_SETSIZE 32
- #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
- #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
- #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
- #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
- #endif
-
- int
- res_send(char *buf, int buflen, char *answer, int anslen)
- {
- register int n;
- int s=-1;
- int try, v_circuit, resplen, ns;
- int gotsomewhere = 0;
- int connreset = 0;
- u_short id, len;
- char *cp;
- HEADER *hp = (HEADER *) buf;
- HEADER *anhp = (HEADER *) answer;
- int terrno = ETIMEDOUT;
- char junk[512];
- struct mbuf *bp;
-
- struct socket lsocket, fsocket;
-
- #ifdef DEBUG
- if (_res.options & RES_DEBUG) {
- cwprintf(NULL, "res_send()\n");
- /*p_query(buf);*/
- }
- #endif /* DEBUG */
- if (!(_res.options & RES_INIT))
- if (res_init() == -1) {
- return(-1);
- }
- v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
-
- /* Only allow one TCP query at a time */
- if (v_circuit && single_query(1))
- return (-1);
-
- id = hp->id;
- /*
- * Send request, RETRY times, or until successful
- */
- for (try = 0; try < _res.retry; try++) {
- for (ns = 0; ns < _res.nscount; ns++) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "Querying server (# %d) address = %d.%d.%d.%d\n", ns+1,
- (_res.nsaddr_list[ns].sin_addr.s_addr >> 24) & 0xff,
- (_res.nsaddr_list[ns].sin_addr.s_addr >> 16) & 0xff,
- (_res.nsaddr_list[ns].sin_addr.s_addr >> 8) & 0xff,
- _res.nsaddr_list[ns].sin_addr.s_addr & 0xff);
- #endif /* DEBUG */
- if (v_circuit) {
- int truncated = 0;
-
- /*
- * Use virtual circuit;
- * at most one attempt per server.
- */
- try = _res.retry;
- if (s<0) {
- lsocket.address = ip_addr;
- lsocket.port = lport++;
- fsocket.address = _res.nsaddr_list[ns].sin_addr.s_addr;
- fsocket.port = ntohs(_res.nsaddr_list[ns].sin_port);
-
- state = state_SYNC;
- tcpintcb = tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,tcp_window,
- (void(*)())rs_rec, (void(*)())rs_cts, (void(*)())rs_state,0,NULL);
- rs_init();
- if (!tcb) {
- terrno = errno;
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "socket (vc) failed\n");
- #endif /* DEBUG */
- continue;
- }
- s = 1;
- poll(timeoutfact);
- while( state == state_SYNC ) poll(0);
- if( state != state_ESTABLISHED ) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "connect failed, status=%s\n", states[state]);
- #endif /* DEBUG */
- (void) close_tcp(tcb);
- s = -1;
- continue;
- }
- }
- /* Send length & message
- */
- len = htons((u_short)buflen);
- sendit( &len, shortsize );
- sendit( buf, buflen );
- /* Receive length & response */
- cp = answer;
- len = shortsize;
- while (len != 0 &&
- (n = read( (char *)cp, (int)len)) > 0) {
- cp += n;
- len -= n;
- }
- if (n <= 0)
- {
- terrno = errno;
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "read failed, status=%s\n", states[state]);
- #endif /* DEBUG */
- (void) close_tcp(tcb);
- s = -1;
- /* A long running process might get its TCP
- connection reset if the remote server was
- restarted. Requery the server instead of
- trying a new one. When there is only one
- server, this means that a query might work
- instead of failing. We only allow one reset
- per query to prevent looping. */
- if (terrno == ECONNRESET && !connreset)
- {
- connreset = 1;
- ns--;
- }
- continue;
- }
- cp = answer;
- if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "response truncated\n");
- #endif /* DEBUG */
- len = anslen;
- truncated = 1;
- }
- else
- len = resplen;
- while (len != 0 &&
- (n = read( (char *)cp, (int)len)) > 0) {
- cp += n;
- len -= n;
- }
- if (n <= 0) {
- terrno = errno;
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "read failed\n");
- #endif /* DEBUG */
- (void) close_tcp(tcb);
- s = -1;
- continue;
- }
- if (truncated)
- {
- /* Flush rest of answer
- so connection stays in synch. */
- anhp->tc = 1;
- len = resplen - anslen;
- while (len != 0) {
- n = (len > sizeof(junk) ?
- sizeof(junk) : len);
- if ((n = read(junk, n)) > 0)
- len -= n;
- else
- break;
- }
- }
- }
- else
- {
- /* Set up the socket descriptors */
- lsocket.address = ip_addr;
- lsocket.port = lport++;
- fsocket.address = _res.nsaddr_list[ns].sin_addr.s_addr;
- fsocket.port = ntohs(_res.nsaddr_list[ns].sin_port);
-
- /* Create the local socket to catch the response */
- if (open_udp(&lsocket,NULL) < 0) {
- terrno = errno;
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "socket failed\n");
- #endif /* DEBUG */
- continue;
- }
-
- /* Send length and message */
- bp = qdata(buf,(int16)buflen);
- if (send_udp(&lsocket,&fsocket,0,0,bp,0,0,0) == 0) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "send failed\n");
- #endif /* DEBUG */
- (void)del_udp(&lsocket);
- continue;
- }
-
- /* Wait until we get an answer or time out */
- state = state_ESTABLISHED;
- poll(timeoutfact);
- while( ( state == state_ESTABLISHED ) &&
- ( (resplen = recv_udp(&lsocket,&fsocket,&bp)) < 0 ) )
- poll(0);
-
- /* Give up on this server if we've timed out */
- if (state != state_ESTABLISHED) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "lookup failed, status=%s\n", states[state]);
- #endif /* DEBUG */
- (void)del_udp(&lsocket);
- continue;
- }
-
- /* Check the size of the answer */
- if (resplen > anslen) {
- #ifdef DEBUG
- if (_res.options & RES_DEBUG)
- cwprintf(NULL, "response truncated\n");
- #endif /* DEBUG */
- len = anslen;
- }
- else
- len = resplen;
-
- /* Read the answer, and throw away and excess data */
- pullup(&bp,(char *)answer,len);
- free_p(bp);
-
- /* Delete the local socket */
- del_udp(&lsocket);
- }
- #ifdef DEBUG
- if (_res.options & RES_DEBUG) {
- cwprintf(NULL, "got answer:\n");
- /*p_query(answer);*/
- }
- #endif /* DEBUG */
- /*
- * If using virtual circuits, we assume that the first server
- * is preferred * over the rest (i.e. it is on the local
- * machine) and only keep that one open.
- * If we have temporarily opened a virtual circuit,
- * or if we haven't been asked to keep a socket open,
- * close the socket.
- */
- if ((v_circuit &&
- ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
- (_res.options & RES_STAYOPEN) == 0) {
- (void) close_tcp(tcb);
- s = -1;
- }
- single_query(0);
- return (resplen);
- }
- }
- if (s >= 0) {
- (void) close_tcp(tcb);
- s = -1;
- }
- if (v_circuit == 0)
- if (gotsomewhere == 0)
- errno = ECONNREFUSED; /* no nameservers found */
- else
- errno = ETIMEDOUT; /* no answer obtained */
- else
- errno = terrno;
- single_query(0);
- return (-1);
- }
-
-
-
- static void rs_cts(struct tcb *tcb, int16 cnt)
- {
- tcb = tcb;
- cnt = cnt;
- /* we actually don't use it */
- }
-
-
- static void rs_state(register struct tcb *tcb, char old, char new)
- {
- if( trace>1 ) cwprintf(NULL, "resolve: state called, new state: %d\n", new );
- switch(new)
- {
- case SYN_SENT:
- case SYN_RECEIVED:
- state = state_SYNC;
- break;
- case ESTABLISHED:
- state = state_ESTABLISHED;
- break;
- case CLOSE_WAIT:
- close_tcp(tcb); /* shut things down */
- break;
- case CLOSED:
- /* if this close was not done by us ie. a RST */
- del_tcp(tcb);
- state = state_CLOSED;
- break;
- case LISTEN:
- case FINWAIT1:
- case FINWAIT2:
- break;
- }
- }
-
- static void rs_rec(struct tcb *tcb, int16 cnt)
- {
- struct mbuf *bp;
-
- if( tcb != tcpintcb ) return; /* to avoid receiving data from former queries */
- recv_tcp(tcb,&bp,cnt); /* suck up chars from low level routine */
-
- tcpinbuff_ptr += pullup(&bp,&tcpinbuff[tcpinbuff_ptr],TCPINBUFFLEN-tcpinbuff_ptr);
- if( tcpinbuff_ptr >= TCPINBUFFLEN ) cwprintf(NULL, "resolve: tcp buffer overflow\n" );
- if( _res.options&RES_DEBUG ) cwprintf(NULL, "bytes in inqueue: %d\n", tcpinbuff_ptr );
- }
-
- static void rs_init(void)
- {
- tcpinbuff_ptr = 0;
- }
-
- static void seterrno(void)
- {
- switch( state )
- {
- case state_TIMEOUT:
- errno = ETIMEDOUT;
- break;
- case state_CLOSED :
- errno = ECONNREFUSED;
- break;
- default:
- errno = 0;
- }
- }
-
- static int read( char *buff, int len )
- {
- while( state == state_ESTABLISHED && ! tcpinbuff_ptr ) poll(0);
- if( tcpinbuff_ptr ) {
- len = (len>tcpinbuff_ptr)?tcpinbuff_ptr:len;
- memcpy( buff, tcpinbuff, len );
- if( len<tcpinbuff_ptr ) memmove( tcpinbuff, &tcpinbuff[len], tcpinbuff_ptr - len );
- tcpinbuff_ptr -= len;
- if( _res.options & RES_DEBUG ) cwprintf(NULL, "read: %d bytes read\n", len );
- return len;
- }
- else {
- if( _res.options & RES_DEBUG ) cwprintf(NULL, "read: state changed to %s\n", states[state] );
- seterrno();
- return 0;
- }
- }
-
- static void poll( int to )
- {
- static int timeout=-1;
- static time_t stime;
- time_t etime;
-
- if( to )
- {
- time( &stime );
- timeout = to;
- }
- event_process();
- if( timeout > 0 )
- {
- time( &etime );
- if( difftime( etime, stime ) >= timeout )
- {
- state = state_TIMEOUT;
- cwprintf(NULL, "resolve: time out\n" );
- }
- }
- }
-
- /* Send message back to server */
- static void sendit( void *buff, int len)
- {
- struct mbuf *bp;
-
- bp = qdata(buff,(int16)len);
- send_tcp(tcb,bp);
- }
-
- int single_query( int pg )
- {
- static int in_progress=0;
-
- if( pg )
- {
- if( in_progress )
- return 1;
- in_progress = 1;
- return 0;
- }
- else
- in_progress = 0;
- return 0;
- }
-