xref: /original-bsd/lib/libc/net/gethostnamadr.c (revision 65901293)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)gethostnamadr.c	5.7 (Berkeley) 09/14/85";
9 #endif not lint
10 
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <netdb.h>
15 #include <stdio.h>
16 #include <arpa/nameser.h>
17 #include <arpa/resolv.h>
18 
19 #define	MAXALIASES	35
20 #define MAXADDRS	35
21 
22 static char *h_addr_ptrs[MAXADDRS + 1];
23 
24 static struct hostent host;
25 static char *host_aliases[MAXALIASES];
26 static char hostbuf[BUFSIZ+1];
27 
28 
29 static struct hostent *
30 getanswer(msg, msglen, iquery)
31 	char *msg;
32 	int msglen, iquery;
33 {
34 	register HEADER *hp;
35 	register char *cp;
36 	register int n;
37 	char answer[PACKETSZ];
38 	char *eom, *bp, **ap;
39 	int type, class, ancount, buflen;
40 	int haveanswer, getclass;
41 	char **hap;
42 
43 	n = res_send(msg, msglen, answer, sizeof(answer));
44 	if (n < 0) {
45 #ifdef DEBUG
46 		if (_res.options & RES_DEBUG)
47 			printf("res_send failed\n");
48 #endif
49 		return (NULL);
50 	}
51 	eom = answer + n;
52 	/*
53 	 * find first satisfactory answer
54 	 */
55 	hp = (HEADER *) answer;
56 	ancount = ntohs(hp->ancount);
57 	if (hp->rcode != NOERROR || ancount == 0) {
58 #ifdef DEBUG
59 		if (_res.options & RES_DEBUG)
60 			printf("rcode = %d, ancount=%d\n", hp->rcode, ancount);
61 #endif
62 		return (NULL);
63 	}
64 	bp = hostbuf;
65 	buflen = sizeof(hostbuf);
66 	cp = answer + sizeof(HEADER);
67 	if (hp->qdcount) {
68 		if (iquery) {
69 			if ((n = dn_expand(answer, cp, bp, buflen)) < 0)
70 				return (NULL);
71 			cp += n + QFIXEDSZ;
72 			host.h_name = bp;
73 			n = strlen(bp) + 1;
74 			bp += n;
75 			buflen -= n;
76 		} else
77 			cp += dn_skip(cp) + QFIXEDSZ;
78 	} else if (iquery)
79 		return (NULL);
80 	ap = host_aliases;
81 	host.h_aliases = host_aliases;
82 	hap = h_addr_ptrs;
83 	host.h_addr_list = h_addr_ptrs;
84 	haveanswer = 0;
85 	while (--ancount >= 0 && cp < eom) {
86 		if ((n = dn_expand(answer, cp, bp, buflen)) < 0)
87 			break;
88 		cp += n;
89 		type = getshort(cp);
90  		cp += sizeof(u_short);
91 		class = getshort(cp);
92  		cp += sizeof(u_short) + sizeof(u_long);
93 		n = getshort(cp);
94 		cp += sizeof(u_short);
95 		if (type == T_CNAME) {
96 			cp += n;
97 			if (ap >= &host_aliases[MAXALIASES-1])
98 				continue;
99 			*ap++ = bp;
100 			n = strlen(bp) + 1;
101 			bp += n;
102 			buflen -= n;
103 			continue;
104 		}
105 		if (type != T_A)  {
106 #ifdef DEBUG
107 			if (_res.options & RES_DEBUG)
108 				printf("unexpected answer type %d, size %d\n",
109 					type, n);
110 #endif
111 			cp += n;
112 			continue;
113 		}
114 		if (haveanswer) {
115 			if (n != host.h_length) {
116 				cp += n;
117 				continue;
118 			}
119 			if (class != getclass) {
120 				cp += n;
121 				continue;
122 			}
123 		} else {
124 			host.h_length = n;
125 			getclass = class;
126 			host.h_addrtype = C_IN ? AF_INET : AF_UNSPEC;
127 			if (!iquery) {
128 				host.h_name = bp;
129 				bp += strlen(bp) + 1;
130 			}
131 		}
132 		if (bp + n >= &hostbuf[sizeof(hostbuf)]) {
133 #ifdef DEBUG
134 			if (_res.options & RES_DEBUG)
135 				printf("size (%d) too big\n", n);
136 #endif
137 			break;
138 		}
139 		bcopy(cp, *hap++ = bp, n);
140 		bp +=n;
141 		cp += n;
142 		haveanswer++;
143 	}
144 	if (haveanswer) {
145 		*ap = NULL;
146 		*hap = NULL;
147 		return (&host);
148 	} else
149 		return (NULL);
150 }
151 
152 struct hostent *
153 gethostbyname(name)
154 	char *name;
155 {
156 	int n;
157 	char buf[BUFSIZ+1];
158 
159 	n = res_mkquery(QUERY, name, C_ANY, T_A, (char *)NULL, 0, NULL,
160 		buf, sizeof(buf));
161 	if (n < 0) {
162 #ifdef DEBUG
163 		if (_res.options & RES_DEBUG)
164 			printf("res_mkquery failed\n");
165 #endif
166 		return (NULL);
167 	}
168 	return(getanswer(buf, n, 0));
169 }
170 
171 struct hostent *
172 gethostbyaddr(addr, len, type)
173 	char *addr;
174 	int len, type;
175 {
176 	int n;
177 	char buf[BUFSIZ+1];
178 
179 	if (type != AF_INET)
180 		return (NULL);
181 	n = res_mkquery(IQUERY, (char *)NULL, C_IN, T_A, addr, len, NULL,
182 		buf, sizeof(buf));
183 	if (n < 0) {
184 #ifdef DEBUG
185 		if (_res.options & RES_DEBUG)
186 			printf("res_mkquery failed\n");
187 #endif
188 		return (NULL);
189 	}
190 	return(getanswer(buf, n, 1));
191 }
192 
193 
194