xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 31780)
121374Sdist /*
225302Skjd  * Copyright (c) 1985 Regents of the University of California.
321374Sdist  * All rights reserved.  The Berkeley software License Agreement
421374Sdist  * specifies the terms and conditions for redistribution.
521374Sdist  */
615662Sralph 
726630Sdonn #if defined(LIBC_SCCS) && !defined(lint)
8*31780Sbostic static char sccsid[] = "@(#)gethostnamadr.c	6.20 (Berkeley) 07/05/87";
926630Sdonn #endif LIBC_SCCS and not lint
1021374Sdist 
1130468Skjd #include <sys/param.h>
1218505Sralph #include <sys/socket.h>
1318505Sralph #include <netinet/in.h>
1426887Skjd #include <ctype.h>
1518505Sralph #include <netdb.h>
1615662Sralph #include <stdio.h>
1726887Skjd #include <errno.h>
1827034Skjd #include <arpa/inet.h>
1924508Sbloom #include <arpa/nameser.h>
2026894Skjd #include <resolv.h>
2115662Sralph 
2215662Sralph #define	MAXALIASES	35
2324687Sbloom #define MAXADDRS	35
2415662Sralph 
2524687Sbloom static char *h_addr_ptrs[MAXADDRS + 1];
2624687Sbloom 
2724687Sbloom static struct hostent host;
2815662Sralph static char *host_aliases[MAXALIASES];
2915912Sralph static char hostbuf[BUFSIZ+1];
3025153Sbloom static struct in_addr host_addr;
3126887Skjd static char HOSTDB[] = "/etc/hosts";
3226887Skjd static FILE *hostf = NULL;
3326887Skjd static char line[BUFSIZ+1];
3426887Skjd static char hostaddr[MAXADDRS];
3526887Skjd static char *host_addrs[2];
3626887Skjd static int stayopen = 0;
3726887Skjd static char *any();
3815662Sralph 
3925302Skjd typedef union {
4025302Skjd     HEADER qb1;
4125302Skjd     char qb2[PACKETSZ];
4225302Skjd } querybuf;
4324509Sbloom 
4425302Skjd static union {
4525302Skjd     long al;
4625302Skjd     char ac;
4725302Skjd } align;
4825302Skjd 
4925302Skjd 
5025484Skjd int h_errno;
5126887Skjd extern errno;
5225484Skjd 
5315662Sralph static struct hostent *
5418505Sralph getanswer(msg, msglen, iquery)
5518505Sralph 	char *msg;
5618505Sralph 	int msglen, iquery;
5715662Sralph {
5818505Sralph 	register HEADER *hp;
5918505Sralph 	register char *cp;
6018505Sralph 	register int n;
6125302Skjd 	querybuf answer;
6218505Sralph 	char *eom, *bp, **ap;
6327034Skjd 	int type, class, buflen, ancount, qdcount;
6427034Skjd 	int haveanswer, getclass = C_ANY;
6524687Sbloom 	char **hap;
6615662Sralph 
6725302Skjd 	n = res_send(msg, msglen, (char *)&answer, sizeof(answer));
6818505Sralph 	if (n < 0) {
6924733Sbloom #ifdef DEBUG
7026887Skjd 		int terrno;
7126887Skjd 		terrno = errno;
7218505Sralph 		if (_res.options & RES_DEBUG)
7318531Sralph 			printf("res_send failed\n");
7426887Skjd 		errno = terrno;
7524733Sbloom #endif
7625484Skjd 		h_errno = TRY_AGAIN;
7718505Sralph 		return (NULL);
7815662Sralph 	}
7925302Skjd 	eom = (char *)&answer + n;
8018505Sralph 	/*
8118505Sralph 	 * find first satisfactory answer
8218505Sralph 	 */
8325302Skjd 	hp = (HEADER *) &answer;
8418505Sralph 	ancount = ntohs(hp->ancount);
8525153Sbloom 	qdcount = ntohs(hp->qdcount);
8618505Sralph 	if (hp->rcode != NOERROR || ancount == 0) {
8724733Sbloom #ifdef DEBUG
8818505Sralph 		if (_res.options & RES_DEBUG)
8918505Sralph 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
9024733Sbloom #endif
9125484Skjd 		switch (hp->rcode) {
9225484Skjd 			case NXDOMAIN:
9325484Skjd 				/* Check if it's an authoritive answer */
9425484Skjd 				if (hp->aa)
9525484Skjd 					h_errno = HOST_NOT_FOUND;
9625484Skjd 				else
9725484Skjd 					h_errno = TRY_AGAIN;
9825484Skjd 				break;
9925484Skjd 			case SERVFAIL:
10025484Skjd 				h_errno = TRY_AGAIN;
10125484Skjd 				break;
10225484Skjd 			case NOERROR:
10325484Skjd 				h_errno = NO_ADDRESS;
10425484Skjd 				break;
10525484Skjd 			case FORMERR:
10625484Skjd 			case NOTIMP:
10725484Skjd 			case REFUSED:
10825484Skjd 				h_errno = NO_RECOVERY;
10925484Skjd 		}
11018505Sralph 		return (NULL);
11118505Sralph 	}
11218505Sralph 	bp = hostbuf;
11318505Sralph 	buflen = sizeof(hostbuf);
11425302Skjd 	cp = (char *)&answer + sizeof(HEADER);
11525153Sbloom 	if (qdcount) {
11618505Sralph 		if (iquery) {
11726066Skjd 			if ((n = dn_expand((char *)&answer, eom,
11826066Skjd 			     cp, bp, buflen)) < 0) {
11925484Skjd 				h_errno = NO_RECOVERY;
12018505Sralph 				return (NULL);
12125484Skjd 			}
12218505Sralph 			cp += n + QFIXEDSZ;
12318505Sralph 			host.h_name = bp;
12418505Sralph 			n = strlen(bp) + 1;
12518505Sralph 			bp += n;
12618505Sralph 			buflen -= n;
12718505Sralph 		} else
12818505Sralph 			cp += dn_skip(cp) + QFIXEDSZ;
12925153Sbloom 		while (--qdcount > 0)
13025153Sbloom 			cp += dn_skip(cp) + QFIXEDSZ;
13125484Skjd 	} else if (iquery) {
13225484Skjd 		if (hp->aa)
13325484Skjd 			h_errno = HOST_NOT_FOUND;
13425484Skjd 		else
13525484Skjd 			h_errno = TRY_AGAIN;
13618505Sralph 		return (NULL);
13725484Skjd 	}
13824687Sbloom 	ap = host_aliases;
13924687Sbloom 	host.h_aliases = host_aliases;
14024687Sbloom 	hap = h_addr_ptrs;
14130468Skjd #if BSD >= 43
14224687Sbloom 	host.h_addr_list = h_addr_ptrs;
14330460Skjd #else
14430460Skjd 	host.h_addr = h_addr_ptrs[0];
14530460Skjd #endif
14624687Sbloom 	haveanswer = 0;
14718505Sralph 	while (--ancount >= 0 && cp < eom) {
14826066Skjd 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
14924687Sbloom 			break;
15018505Sralph 		cp += n;
15130440Skjd 		type = _getshort(cp);
15218505Sralph  		cp += sizeof(u_short);
15330440Skjd 		class = _getshort(cp);
15418505Sralph  		cp += sizeof(u_short) + sizeof(u_long);
15530440Skjd 		n = _getshort(cp);
15618505Sralph 		cp += sizeof(u_short);
15718505Sralph 		if (type == T_CNAME) {
15818505Sralph 			cp += n;
15918505Sralph 			if (ap >= &host_aliases[MAXALIASES-1])
16018505Sralph 				continue;
16118505Sralph 			*ap++ = bp;
16218505Sralph 			n = strlen(bp) + 1;
16318505Sralph 			bp += n;
16418505Sralph 			buflen -= n;
16518505Sralph 			continue;
16618505Sralph 		}
16725153Sbloom 		if (type == T_PTR) {
16827034Skjd 			if ((n = dn_expand((char *)&answer, eom,
16927034Skjd 			    cp, bp, buflen)) < 0) {
17025153Sbloom 				cp += n;
17125153Sbloom 				continue;
17225153Sbloom 			}
17325153Sbloom 			cp += n;
17425153Sbloom 			host.h_name = bp;
17525153Sbloom 			return(&host);
17625153Sbloom 		}
17724687Sbloom 		if (type != T_A)  {
17824733Sbloom #ifdef DEBUG
17918505Sralph 			if (_res.options & RES_DEBUG)
18018505Sralph 				printf("unexpected answer type %d, size %d\n",
18118505Sralph 					type, n);
18224733Sbloom #endif
18324687Sbloom 			cp += n;
18418505Sralph 			continue;
18518505Sralph 		}
18624687Sbloom 		if (haveanswer) {
18724687Sbloom 			if (n != host.h_length) {
18824687Sbloom 				cp += n;
18924687Sbloom 				continue;
19024687Sbloom 			}
19124687Sbloom 			if (class != getclass) {
19224687Sbloom 				cp += n;
19324687Sbloom 				continue;
19424687Sbloom 			}
19524687Sbloom 		} else {
19624687Sbloom 			host.h_length = n;
19724687Sbloom 			getclass = class;
19825386Skjd 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
19924687Sbloom 			if (!iquery) {
20024687Sbloom 				host.h_name = bp;
20124687Sbloom 				bp += strlen(bp) + 1;
20224687Sbloom 			}
20318505Sralph 		}
20425302Skjd 
20529568Ssam 		bp += (sizeof(align) - ((u_long)bp % sizeof(align))) &~
20629568Ssam 		    sizeof(align);
20725302Skjd 
20818505Sralph 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
20924733Sbloom #ifdef DEBUG
21018505Sralph 			if (_res.options & RES_DEBUG)
21118505Sralph 				printf("size (%d) too big\n", n);
21224733Sbloom #endif
21324687Sbloom 			break;
21418505Sralph 		}
21524687Sbloom 		bcopy(cp, *hap++ = bp, n);
21624687Sbloom 		bp +=n;
21724687Sbloom 		cp += n;
21824687Sbloom 		haveanswer++;
21924687Sbloom 	}
22024687Sbloom 	if (haveanswer) {
22124687Sbloom 		*ap = NULL;
22224687Sbloom 		*hap = NULL;
22318505Sralph 		return (&host);
22425484Skjd 	} else {
22525484Skjd 		h_errno = TRY_AGAIN;
22624687Sbloom 		return (NULL);
22725484Skjd 	}
22815662Sralph }
22915662Sralph 
23015662Sralph struct hostent *
23118505Sralph gethostbyname(name)
23218505Sralph 	char *name;
23315662Sralph {
23431111Skarels 	register char *cp, **domain;
23518505Sralph 	int n;
23631111Skarels 	struct hostent *hp, *gethostdomain();
23731111Skarels 	char *hostalias();
23826887Skjd 	extern struct hostent *_gethtbyname();
23915662Sralph 
24031111Skarels 	if (!(_res.options & RES_INIT) && res_init() == -1)
24131111Skarels 		return (NULL);
24229930Skjd 	errno = 0;
24331111Skarels 	for (cp = name, n = 0; *cp; cp++)
24431111Skarels 		if (*cp == '.')
24531111Skarels 			n++;
24631111Skarels 	if ((n && cp[-1] == '.') || (_res.options & RES_DEFNAMES) == 0) {
24731111Skarels 		cp[-1] = 0;
24831111Skarels 		hp = gethostdomain(name, (char *)NULL);
24931111Skarels 		cp[-1] = '.';
25031111Skarels 		return (hp);
25131111Skarels 	}
25231111Skarels 	if (n == 0 && (cp = hostalias(name)))
25331111Skarels 		return (gethostdomain(cp, (char *)NULL));
25431111Skarels 	for (domain = _res.dnsrch; *domain; domain++) {
25531111Skarels 		hp = gethostdomain(name, *domain);
25631111Skarels 		if (hp)
25731111Skarels 			return (hp);
25831111Skarels 		if (errno == ECONNREFUSED)
25931111Skarels 			return (_gethtbyname(name));
26031111Skarels 		if (h_errno != HOST_NOT_FOUND ||
26131111Skarels 		    (_res.options & RES_DNSRCH) == 0)
26231111Skarels 			return (NULL);
26331709Skarels 		h_errno = 0;
26431111Skarels 	}
26531111Skarels 	return (gethostdomain(name, (char *)NULL));
26631111Skarels }
26731111Skarels 
26831111Skarels static struct hostent *
26931111Skarels gethostdomain(name, domain)
27031111Skarels 	char *name, *domain;
27131111Skarels {
27231111Skarels 	querybuf buf;
27331111Skarels 	char nbuf[2*MAXDNAME+2];
27431111Skarels 	int n;
27531111Skarels 
27631111Skarels 	sprintf(nbuf, "%.*s.%.*s", MAXDNAME, name, MAXDNAME, domain);
27731111Skarels 	n = res_mkquery(QUERY, nbuf, C_IN, T_A, (char *)NULL, 0, NULL,
27825302Skjd 		(char *)&buf, sizeof(buf));
27918505Sralph 	if (n < 0) {
28024733Sbloom #ifdef DEBUG
28118505Sralph 		if (_res.options & RES_DEBUG)
28218531Sralph 			printf("res_mkquery failed\n");
28324733Sbloom #endif
28418505Sralph 		return (NULL);
28517761Sserge 	}
28631111Skarels 	return (getanswer((char *)&buf, n, 0));
28715662Sralph }
28815662Sralph 
28915662Sralph struct hostent *
29018505Sralph gethostbyaddr(addr, len, type)
29115662Sralph 	char *addr;
29218505Sralph 	int len, type;
29315662Sralph {
29418505Sralph 	int n;
29525302Skjd 	querybuf buf;
29625153Sbloom 	register struct hostent *hp;
29725153Sbloom 	char qbuf[MAXDNAME];
29826887Skjd 	extern struct hostent *_gethtbyaddr();
29926887Skjd 
30018505Sralph 	if (type != AF_INET)
30118505Sralph 		return (NULL);
30225153Sbloom 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
30325484Skjd 		((unsigned)addr[3] & 0xff),
30425484Skjd 		((unsigned)addr[2] & 0xff),
30525484Skjd 		((unsigned)addr[1] & 0xff),
30625484Skjd 		((unsigned)addr[0] & 0xff));
30727034Skjd 	n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, (char *)NULL, 0, NULL,
30825302Skjd 		(char *)&buf, sizeof(buf));
30918505Sralph 	if (n < 0) {
31024733Sbloom #ifdef DEBUG
31118505Sralph 		if (_res.options & RES_DEBUG)
31218531Sralph 			printf("res_mkquery failed\n");
31324733Sbloom #endif
31418505Sralph 		return (NULL);
31517761Sserge 	}
31626887Skjd 	hp = getanswer((char *)&buf, n, 1);
31726887Skjd 	if (hp == NULL && errno == ECONNREFUSED)
31826887Skjd 		hp = _gethtbyaddr(addr, len, type);
31926887Skjd 	if (hp == NULL)
32025153Sbloom 		return(NULL);
32125153Sbloom 	hp->h_addrtype = type;
32225153Sbloom 	hp->h_length = len;
32325282Sbloom 	h_addr_ptrs[0] = (char *)&host_addr;
32425153Sbloom 	h_addr_ptrs[1] = (char *)0;
32525153Sbloom 	host_addr = *(struct in_addr *)addr;
32625153Sbloom 	return(hp);
32715662Sralph }
32825302Skjd 
32931111Skarels char *
33031111Skarels hostalias(name)
33131111Skarels 	register char *name;
33231111Skarels {
333*31780Sbostic 	register char *C1, *C2;
33431111Skarels 	FILE *fp;
335*31780Sbostic 	char *file, *getenv(), *strcpy(), *strncpy();
336*31780Sbostic 	char buf[BUFSIZ];
33731111Skarels 	static char abuf[MAXDNAME];
33826887Skjd 
33931111Skarels 	file = getenv("HOSTALIASES");
34031111Skarels 	if (file == NULL || (fp = fopen(file, "r")) == NULL)
34131111Skarels 		return (NULL);
342*31780Sbostic 	buf[sizeof(buf) - 1] = '\0';
343*31780Sbostic 	while (fgets(buf, sizeof(buf), fp)) {
344*31780Sbostic 		for (C1 = buf; *C1 && !isspace(*C1); ++C1);
345*31780Sbostic 		if (!*C1 || *C1 == '\n')
346*31780Sbostic 			break;
347*31780Sbostic 		if (!strncmp(buf, name, C1 - buf)) {
348*31780Sbostic 			while (isspace(*++C1));
349*31780Sbostic 			if (!*C1)
350*31780Sbostic 				break;
351*31780Sbostic 			for (C2 = C1 + 1; *C2 && !isspace(*C2); ++C2);
352*31780Sbostic 			abuf[sizeof(abuf) - 1] = *C2 = '\0';
353*31780Sbostic 			(void)strncpy(abuf, C1, sizeof(abuf) - 1);
35431111Skarels 			fclose(fp);
35531111Skarels 			return (abuf);
35631111Skarels 		}
357*31780Sbostic 	}
35831111Skarels 	fclose(fp);
35931111Skarels 	return (NULL);
36031111Skarels }
36131111Skarels 
36226887Skjd _sethtent(f)
36326887Skjd 	int f;
36426887Skjd {
36526887Skjd 	if (hostf == NULL)
36626887Skjd 		hostf = fopen(HOSTDB, "r" );
36726887Skjd 	else
36826887Skjd 		rewind(hostf);
36926887Skjd 	stayopen |= f;
37026887Skjd }
37126887Skjd 
37226887Skjd _endhtent()
37326887Skjd {
37426887Skjd 	if (hostf && !stayopen) {
37527034Skjd 		(void) fclose(hostf);
37626887Skjd 		hostf = NULL;
37726887Skjd 	}
37826887Skjd }
37926887Skjd 
38026887Skjd struct hostent *
38126887Skjd _gethtent()
38226887Skjd {
38326887Skjd 	char *p;
38426887Skjd 	register char *cp, **q;
38526887Skjd 
38626887Skjd 	if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL)
38726887Skjd 		return (NULL);
38826887Skjd again:
38926887Skjd 	if ((p = fgets(line, BUFSIZ, hostf)) == NULL)
39026887Skjd 		return (NULL);
39126887Skjd 	if (*p == '#')
39226887Skjd 		goto again;
39326887Skjd 	cp = any(p, "#\n");
39426887Skjd 	if (cp == NULL)
39526887Skjd 		goto again;
39626887Skjd 	*cp = '\0';
39726887Skjd 	cp = any(p, " \t");
39826887Skjd 	if (cp == NULL)
39926887Skjd 		goto again;
40026887Skjd 	*cp++ = '\0';
40126887Skjd 	/* THIS STUFF IS INTERNET SPECIFIC */
40230468Skjd #if	BSD >= 43
40326887Skjd 	host.h_addr_list = host_addrs;
40430460Skjd #endif
40526887Skjd 	host.h_addr = hostaddr;
40626887Skjd 	*((u_long *)host.h_addr) = inet_addr(p);
40726887Skjd 	host.h_length = sizeof (u_long);
40826887Skjd 	host.h_addrtype = AF_INET;
40926887Skjd 	while (*cp == ' ' || *cp == '\t')
41026887Skjd 		cp++;
41126887Skjd 	host.h_name = cp;
41226887Skjd 	q = host.h_aliases = host_aliases;
41326887Skjd 	cp = any(cp, " \t");
41426887Skjd 	if (cp != NULL)
41526887Skjd 		*cp++ = '\0';
41626887Skjd 	while (cp && *cp) {
41726887Skjd 		if (*cp == ' ' || *cp == '\t') {
41826887Skjd 			cp++;
41926887Skjd 			continue;
42026887Skjd 		}
42126887Skjd 		if (q < &host_aliases[MAXALIASES - 1])
42226887Skjd 			*q++ = cp;
42326887Skjd 		cp = any(cp, " \t");
42426887Skjd 		if (cp != NULL)
42526887Skjd 			*cp++ = '\0';
42626887Skjd 	}
42726887Skjd 	*q = NULL;
42826887Skjd 	return (&host);
42926887Skjd }
43026887Skjd 
43126887Skjd static char *
43226887Skjd any(cp, match)
43326887Skjd 	register char *cp;
43426887Skjd 	char *match;
43526887Skjd {
43626887Skjd 	register char *mp, c;
43726887Skjd 
43826887Skjd 	while (c = *cp) {
43926887Skjd 		for (mp = match; *mp; mp++)
44026887Skjd 			if (*mp == c)
44126887Skjd 				return (cp);
44226887Skjd 		cp++;
44326887Skjd 	}
44426887Skjd 	return ((char *)0);
44526887Skjd }
44626887Skjd 
44726887Skjd struct hostent *
44826887Skjd _gethtbyname(name)
44926887Skjd 	char *name;
45026887Skjd {
45126887Skjd 	register struct hostent *p;
45226887Skjd 	register char **cp;
45328307Skarels 	char lowname[128];
45428307Skarels 	register char *lp = lowname;
45528307Skarels 
45628307Skarels 	while (*name)
45728307Skarels 		if (isupper(*name))
45828307Skarels 			*lp++ = tolower(*name++);
45928307Skarels 		else
46028307Skarels 			*lp++ = *name++;
46128307Skarels 	*lp = '\0';
46226887Skjd 
46326887Skjd 	_sethtent(0);
46426887Skjd 	while (p = _gethtent()) {
46528307Skarels 		if (strcmp(p->h_name, lowname) == 0)
46626887Skjd 			break;
46726887Skjd 		for (cp = p->h_aliases; *cp != 0; cp++)
46828307Skarels 			if (strcmp(*cp, lowname) == 0)
46926887Skjd 				goto found;
47026887Skjd 	}
47126887Skjd found:
47226887Skjd 	_endhtent();
47326887Skjd 	return (p);
47426887Skjd }
47526887Skjd 
47626887Skjd struct hostent *
47726887Skjd _gethtbyaddr(addr, len, type)
47826887Skjd 	char *addr;
47926887Skjd 	int len, type;
48026887Skjd {
48126887Skjd 	register struct hostent *p;
48226887Skjd 
48326887Skjd 	_sethtent(0);
48426887Skjd 	while (p = _gethtent())
48526909Skjd 		if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
48626887Skjd 			break;
48726887Skjd 	_endhtent();
48826887Skjd 	return (p);
48926887Skjd }
490