xref: /csrg-svn/lib/libc/net/gethostnamadr.c (revision 26066)
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 
721374Sdist #ifndef lint
8*26066Skjd static char sccsid[] = "@(#)gethostnamadr.c	6.4 (Berkeley) 02/04/86";
921374Sdist #endif not lint
1021374Sdist 
1125386Skjd #include <sys/param.h>
1218505Sralph #include <sys/socket.h>
1318505Sralph #include <netinet/in.h>
1418505Sralph #include <netdb.h>
1515662Sralph #include <stdio.h>
1624508Sbloom #include <arpa/nameser.h>
1724508Sbloom #include <arpa/resolv.h>
1815662Sralph 
1915662Sralph #define	MAXALIASES	35
2024687Sbloom #define MAXADDRS	35
2115662Sralph 
2224687Sbloom static char *h_addr_ptrs[MAXADDRS + 1];
2324687Sbloom 
2424687Sbloom static struct hostent host;
2515662Sralph static char *host_aliases[MAXALIASES];
2615912Sralph static char hostbuf[BUFSIZ+1];
2725153Sbloom static struct in_addr host_addr;
2815662Sralph 
2925302Skjd typedef union {
3025302Skjd     HEADER qb1;
3125302Skjd     char qb2[PACKETSZ];
3225302Skjd } querybuf;
3324509Sbloom 
3425302Skjd static union {
3525302Skjd     long al;
3625302Skjd     char ac;
3725302Skjd } align;
3825302Skjd 
3925302Skjd 
4025484Skjd int h_errno;
4125484Skjd 
4215662Sralph static struct hostent *
4318505Sralph getanswer(msg, msglen, iquery)
4418505Sralph 	char *msg;
4518505Sralph 	int msglen, iquery;
4615662Sralph {
4718505Sralph 	register HEADER *hp;
4818505Sralph 	register char *cp;
4918505Sralph 	register int n;
5025302Skjd 	querybuf answer;
5118505Sralph 	char *eom, *bp, **ap;
5225153Sbloom 	int type, class, ancount, qdcount, buflen;
5324687Sbloom 	int haveanswer, getclass;
5424687Sbloom 	char **hap;
5515662Sralph 
5625302Skjd 	n = res_send(msg, msglen, (char *)&answer, sizeof(answer));
5718505Sralph 	if (n < 0) {
5824733Sbloom #ifdef DEBUG
5918505Sralph 		if (_res.options & RES_DEBUG)
6018531Sralph 			printf("res_send failed\n");
6124733Sbloom #endif
6225484Skjd 		h_errno = TRY_AGAIN;
6318505Sralph 		return (NULL);
6415662Sralph 	}
6525302Skjd 	eom = (char *)&answer + n;
6618505Sralph 	/*
6718505Sralph 	 * find first satisfactory answer
6818505Sralph 	 */
6925302Skjd 	hp = (HEADER *) &answer;
7018505Sralph 	ancount = ntohs(hp->ancount);
7125153Sbloom 	qdcount = ntohs(hp->qdcount);
7218505Sralph 	if (hp->rcode != NOERROR || ancount == 0) {
7324733Sbloom #ifdef DEBUG
7418505Sralph 		if (_res.options & RES_DEBUG)
7518505Sralph 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
7624733Sbloom #endif
7725484Skjd 		switch (hp->rcode) {
7825484Skjd 			case NXDOMAIN:
7925484Skjd 				/* Check if it's an authoritive answer */
8025484Skjd 				if (hp->aa)
8125484Skjd 					h_errno = HOST_NOT_FOUND;
8225484Skjd 				else
8325484Skjd 					h_errno = TRY_AGAIN;
8425484Skjd 				break;
8525484Skjd 			case SERVFAIL:
8625484Skjd 				h_errno = TRY_AGAIN;
8725484Skjd 				break;
8825484Skjd 			case NOERROR:
8925484Skjd 				h_errno = NO_ADDRESS;
9025484Skjd 				break;
9125484Skjd 			case FORMERR:
9225484Skjd 			case NOTIMP:
9325484Skjd 			case REFUSED:
9425484Skjd 				h_errno = NO_RECOVERY;
9525484Skjd 		}
9618505Sralph 		return (NULL);
9718505Sralph 	}
9818505Sralph 	bp = hostbuf;
9918505Sralph 	buflen = sizeof(hostbuf);
10025302Skjd 	cp = (char *)&answer + sizeof(HEADER);
10125153Sbloom 	if (qdcount) {
10218505Sralph 		if (iquery) {
103*26066Skjd 			if ((n = dn_expand((char *)&answer, eom,
104*26066Skjd 			     cp, bp, buflen)) < 0) {
10525484Skjd 				h_errno = NO_RECOVERY;
10618505Sralph 				return (NULL);
10725484Skjd 			}
10818505Sralph 			cp += n + QFIXEDSZ;
10918505Sralph 			host.h_name = bp;
11018505Sralph 			n = strlen(bp) + 1;
11118505Sralph 			bp += n;
11218505Sralph 			buflen -= n;
11318505Sralph 		} else
11418505Sralph 			cp += dn_skip(cp) + QFIXEDSZ;
11525153Sbloom 		while (--qdcount > 0)
11625153Sbloom 			cp += dn_skip(cp) + QFIXEDSZ;
11725484Skjd 	} else if (iquery) {
11825484Skjd 		if (hp->aa)
11925484Skjd 			h_errno = HOST_NOT_FOUND;
12025484Skjd 		else
12125484Skjd 			h_errno = TRY_AGAIN;
12218505Sralph 		return (NULL);
12325484Skjd 	}
12424687Sbloom 	ap = host_aliases;
12524687Sbloom 	host.h_aliases = host_aliases;
12624687Sbloom 	hap = h_addr_ptrs;
12724687Sbloom 	host.h_addr_list = h_addr_ptrs;
12824687Sbloom 	haveanswer = 0;
12918505Sralph 	while (--ancount >= 0 && cp < eom) {
130*26066Skjd 		if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0)
13124687Sbloom 			break;
13218505Sralph 		cp += n;
13318505Sralph 		type = getshort(cp);
13418505Sralph  		cp += sizeof(u_short);
13518505Sralph 		class = getshort(cp);
13618505Sralph  		cp += sizeof(u_short) + sizeof(u_long);
13718505Sralph 		n = getshort(cp);
13818505Sralph 		cp += sizeof(u_short);
13918505Sralph 		if (type == T_CNAME) {
14018505Sralph 			cp += n;
14118505Sralph 			if (ap >= &host_aliases[MAXALIASES-1])
14218505Sralph 				continue;
14318505Sralph 			*ap++ = bp;
14418505Sralph 			n = strlen(bp) + 1;
14518505Sralph 			bp += n;
14618505Sralph 			buflen -= n;
14718505Sralph 			continue;
14818505Sralph 		}
14925153Sbloom 		if (type == T_PTR) {
150*26066Skjd 			if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) <
15125302Skjd 0) {
15225153Sbloom 				cp += n;
15325153Sbloom 				continue;
15425153Sbloom 			}
15525153Sbloom 			cp += n;
15625153Sbloom 			host.h_name = bp;
15725153Sbloom 			return(&host);
15825153Sbloom 		}
15924687Sbloom 		if (type != T_A)  {
16024733Sbloom #ifdef DEBUG
16118505Sralph 			if (_res.options & RES_DEBUG)
16218505Sralph 				printf("unexpected answer type %d, size %d\n",
16318505Sralph 					type, n);
16424733Sbloom #endif
16524687Sbloom 			cp += n;
16618505Sralph 			continue;
16718505Sralph 		}
16824687Sbloom 		if (haveanswer) {
16924687Sbloom 			if (n != host.h_length) {
17024687Sbloom 				cp += n;
17124687Sbloom 				continue;
17224687Sbloom 			}
17324687Sbloom 			if (class != getclass) {
17424687Sbloom 				cp += n;
17524687Sbloom 				continue;
17624687Sbloom 			}
17724687Sbloom 		} else {
17824687Sbloom 			host.h_length = n;
17924687Sbloom 			getclass = class;
18025386Skjd 			host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
18124687Sbloom 			if (!iquery) {
18224687Sbloom 				host.h_name = bp;
18324687Sbloom 				bp += strlen(bp) + 1;
18424687Sbloom 			}
18518505Sralph 		}
18625302Skjd 
18725302Skjd 		bp += ((u_long)bp % sizeof(align));
18825302Skjd 
18918505Sralph 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
19024733Sbloom #ifdef DEBUG
19118505Sralph 			if (_res.options & RES_DEBUG)
19218505Sralph 				printf("size (%d) too big\n", n);
19324733Sbloom #endif
19424687Sbloom 			break;
19518505Sralph 		}
19624687Sbloom 		bcopy(cp, *hap++ = bp, n);
19724687Sbloom 		bp +=n;
19824687Sbloom 		cp += n;
19924687Sbloom 		haveanswer++;
20024687Sbloom 	}
20124687Sbloom 	if (haveanswer) {
20224687Sbloom 		*ap = NULL;
20324687Sbloom 		*hap = NULL;
20418505Sralph 		return (&host);
20525484Skjd 	} else {
20625484Skjd 		h_errno = TRY_AGAIN;
20724687Sbloom 		return (NULL);
20825484Skjd 	}
20915662Sralph }
21015662Sralph 
21115662Sralph struct hostent *
21218505Sralph gethostbyname(name)
21318505Sralph 	char *name;
21415662Sralph {
21518505Sralph 	int n;
21625302Skjd 	querybuf buf;
21715662Sralph 
21824687Sbloom 	n = res_mkquery(QUERY, name, C_ANY, T_A, (char *)NULL, 0, NULL,
21925302Skjd 		(char *)&buf, sizeof(buf));
22018505Sralph 	if (n < 0) {
22124733Sbloom #ifdef DEBUG
22218505Sralph 		if (_res.options & RES_DEBUG)
22318531Sralph 			printf("res_mkquery failed\n");
22424733Sbloom #endif
22518505Sralph 		return (NULL);
22617761Sserge 	}
22725302Skjd 	return(getanswer((char *)&buf, n, 0));
22815662Sralph }
22915662Sralph 
23015662Sralph struct hostent *
23118505Sralph gethostbyaddr(addr, len, type)
23215662Sralph 	char *addr;
23318505Sralph 	int len, type;
23415662Sralph {
23518505Sralph 	int n;
23625302Skjd 	querybuf buf;
23725153Sbloom 	register struct hostent *hp;
23825153Sbloom 	char qbuf[MAXDNAME];
23915662Sralph 
24018505Sralph 	if (type != AF_INET)
24118505Sralph 		return (NULL);
24225153Sbloom 	(void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
24325484Skjd 		((unsigned)addr[3] & 0xff),
24425484Skjd 		((unsigned)addr[2] & 0xff),
24525484Skjd 		((unsigned)addr[1] & 0xff),
24625484Skjd 		((unsigned)addr[0] & 0xff));
24725153Sbloom 	n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, NULL, 0, NULL,
24825302Skjd 		(char *)&buf, sizeof(buf));
24918505Sralph 	if (n < 0) {
25024733Sbloom #ifdef DEBUG
25118505Sralph 		if (_res.options & RES_DEBUG)
25218531Sralph 			printf("res_mkquery failed\n");
25324733Sbloom #endif
25418505Sralph 		return (NULL);
25517761Sserge 	}
25625302Skjd 	if ((hp = getanswer((char *)&buf, n, 1)) == NULL)
25725153Sbloom 		return(NULL);
25825153Sbloom 	hp->h_addrtype = type;
25925153Sbloom 	hp->h_length = len;
26025282Sbloom 	h_addr_ptrs[0] = (char *)&host_addr;
26125153Sbloom 	h_addr_ptrs[1] = (char *)0;
26225153Sbloom 	host_addr = *(struct in_addr *)addr;
26325153Sbloom 	return(hp);
26415662Sralph }
26525302Skjd 
266