8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libresolv / res_gethost.c
blob9649677d2a029b7dba539c089b006732de323594
1 /*
2 * Copyright 2015 Gary Mills
3 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
4 * Use is subject to license terms.
5 */
7 /*
8 * Copyright (c) 1985, 1988 Regents of the University of California.
9 * All rights reserved.
11 * Redistribution and use in source and binary forms are permitted
12 * provided that this notice is preserved and that due credit is given
13 * to the University of California at Berkeley. The name of the University
14 * may not be used to endorse or promote products derived from this
15 * software without specific prior written permission. This software
16 * is provided ``as is'' without express or implied warranty.
20 #include <sys/param.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <ctype.h>
24 #include <netdb.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <arpa/inet.h>
29 #include <arpa/nameser.h>
30 #include <resolv.h>
31 #include <syslog.h>
32 #include "crossl.h"
35 * When the name service switch calls libresolv, it doesn't want fallback
36 * to /etc/hosts, so we provide a method to turn it off.
38 static int no_hosts_fallback = 0;
40 void
41 __res_set_no_hosts_fallback(void) {
42 no_hosts_fallback = 1;
45 static int
46 __res_no_hosts_fallback(void) {
47 return(no_hosts_fallback);
50 static char *h_addr_ptrs[MAXADDRS + 1];
52 static struct hostent host;
53 static char *host_aliases[MAXALIASES];
54 static char hostbuf[BUFSIZ+1];
55 static struct in_addr host_addr;
56 static char HOSTDB[] = "/etc/hosts";
57 static FILE *hostf = NULL;
58 static char hostaddr[MAXADDRS];
59 static char *host_addrs[2];
60 static int stayopen = 0;
61 static char *any();
63 #if PACKETSZ > 1024
64 #define MAXPACKET PACKETSZ
65 #else
66 #define MAXPACKET 1024
67 #endif
69 typedef union {
70 HEADER hdr;
71 u_char buf[MAXPACKET];
72 } querybuf;
74 static union {
75 long al;
76 char ac;
77 } align;
80 int h_errno;
82 static struct hostent *
83 getanswer(answer, anslen, iquery)
84 querybuf *answer;
85 int anslen;
86 int iquery;
88 register HEADER *hp;
89 register u_char *cp;
90 register int n;
91 u_char *eom;
92 char *bp, **ap;
93 int type, class, buflen, ancount, qdcount;
94 int haveanswer, getclass = C_ANY;
95 char **hap;
97 eom = answer->buf + anslen;
99 * find first satisfactory answer
101 hp = &answer->hdr;
102 ancount = ntohs(hp->ancount);
103 qdcount = ntohs(hp->qdcount);
104 bp = hostbuf;
105 buflen = sizeof (hostbuf);
106 cp = answer->buf + sizeof (HEADER);
107 if (qdcount) {
108 if (iquery) {
109 if ((n = dn_expand(answer->buf, eom,
110 cp, (u_char *)bp, buflen)) < 0) {
111 h_errno = NO_RECOVERY;
112 return ((struct hostent *) NULL);
114 cp += n + QFIXEDSZ;
115 host.h_name = bp;
116 n = strlen(bp) + 1;
117 bp += n;
118 buflen -= n;
119 } else
120 cp += dn_skipname(cp, eom) + QFIXEDSZ;
121 while (--qdcount > 0)
122 cp += dn_skipname(cp, eom) + QFIXEDSZ;
123 } else if (iquery) {
124 if (hp->aa)
125 h_errno = HOST_NOT_FOUND;
126 else
127 h_errno = TRY_AGAIN;
128 return ((struct hostent *) NULL);
130 ap = host_aliases;
131 host.h_aliases = host_aliases;
132 hap = h_addr_ptrs;
133 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
134 host.h_addr_list = h_addr_ptrs;
135 #endif
136 haveanswer = 0;
137 while (--ancount >= 0 && cp < eom && haveanswer < MAXADDRS) {
138 if ((n = dn_expand(answer->buf, eom,
139 cp, (u_char *)bp, buflen)) < 0)
140 break;
141 cp += n;
142 type = _getshort(cp);
143 cp += sizeof (u_short);
144 class = _getshort(cp);
145 cp += sizeof (u_short) + sizeof (u_long);
146 n = _getshort(cp);
147 cp += sizeof (u_short);
148 if (type == T_CNAME) {
149 cp += n;
150 if (ap >= &host_aliases[MAXALIASES-1])
151 continue;
152 *ap++ = bp;
153 n = strlen(bp) + 1;
154 bp += n;
155 buflen -= n;
156 continue;
158 if (iquery && type == T_PTR) {
159 if ((n = dn_expand(answer->buf, eom,
160 cp, (u_char *)bp, buflen)) < 0) {
161 cp += n;
162 continue;
164 cp += n;
165 host.h_name = bp;
166 return (&host);
168 if (iquery || type != T_A) {
169 #ifdef DEBUG
170 if (_res.options & RES_DEBUG)
171 printf("unexpected answer type %d, size %d\n",
172 type, n);
173 #endif
174 cp += n;
175 continue;
177 if (haveanswer) {
178 if (n != host.h_length) {
179 cp += n;
180 continue;
182 if (class != getclass) {
183 cp += n;
184 continue;
186 } else {
187 host.h_length = n;
188 getclass = class;
189 host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
190 if (!iquery) {
191 host.h_name = bp;
192 bp += strlen(bp) + 1;
196 bp += sizeof (align) - ((u_long)bp % sizeof (align));
198 if (bp + n >= &hostbuf[sizeof (hostbuf)]) {
199 #ifdef DEBUG
200 if (_res.options & RES_DEBUG)
201 printf("size (%d) too big\n", n);
202 #endif
203 break;
205 #ifdef SYSV
206 memcpy((void *)(*hap++ = bp), (void *)cp, n);
207 #else
208 bcopy(cp, *hap++ = bp, n);
209 #endif
210 bp += n;
211 cp += n;
212 haveanswer++;
214 if (haveanswer) {
215 *ap = NULL;
216 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
217 *hap = NULL;
218 #else
219 host.h_addr = h_addr_ptrs[0];
220 #endif
221 return (&host);
222 } else {
223 h_errno = TRY_AGAIN;
224 return ((struct hostent *) NULL);
228 static struct hostent *_gethtbyname();
230 struct hostent *
231 res_gethostbyname(name)
232 char *name;
234 querybuf buf;
235 register char *cp;
236 int n;
239 * disallow names consisting only of digits/dots, unless
240 * they end in a dot.
242 if (isdigit(name[0]))
243 for (cp = name; /*EMPTY*/; ++cp) {
244 if (!*cp) {
245 if (*--cp == '.')
246 break;
247 h_errno = HOST_NOT_FOUND;
248 return ((struct hostent *) NULL);
250 if (!isdigit(*cp) && *cp != '.')
251 break;
254 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof (buf))) < 0) {
255 #ifdef DEBUG
256 if (_res.options & RES_DEBUG)
257 printf("res_search failed\n");
258 #endif
259 if (errno == ECONNREFUSED)
260 return (_gethtbyname(name));
261 else
262 return ((struct hostent *) NULL);
264 return (getanswer(&buf, n, 0));
267 static struct hostent *_gethtbyaddr();
269 static struct hostent *
270 _getrhbyaddr(addr, len, type)
271 char *addr;
272 int len, type;
274 int n;
275 querybuf buf;
276 register struct hostent *hp;
277 char qbuf[MAXDNAME];
279 if (type != AF_INET)
280 return ((struct hostent *) NULL);
281 (void) sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa",
282 ((unsigned)addr[3] & 0xff),
283 ((unsigned)addr[2] & 0xff),
284 ((unsigned)addr[1] & 0xff),
285 ((unsigned)addr[0] & 0xff));
286 n = res_query(qbuf, C_IN, T_PTR, (u_char *)&buf, sizeof (buf));
287 if (n < 0) {
288 #ifdef DEBUG
289 if (_res.options & RES_DEBUG)
290 printf("res_query failed\n");
291 #endif
292 if (errno == ECONNREFUSED)
293 return (_gethtbyaddr(addr, len, type));
294 return ((struct hostent *) NULL);
296 hp = getanswer(&buf, n, 1);
297 if (hp == NULL)
298 return ((struct hostent *) NULL);
299 hp->h_addrtype = type;
300 hp->h_length = len;
301 h_addr_ptrs[0] = (char *)&host_addr;
302 h_addr_ptrs[1] = (char *)0;
303 host_addr = *(struct in_addr *)addr;
304 return (hp);
308 * First we get what the PTR record says, but do an extra call
309 * to gethostbyname() to make sure that someone is not trying to
310 * spoof us. Hopefully this is not done that often, so good
311 * performance is not really an issue.
313 struct hostent *
314 res_gethostbyaddr(addr, len, type)
315 char *addr;
316 int len;
317 int type;
319 char **a, hbuf[MAXHOSTNAMELEN];
320 struct hostent *hp, *hp2;
322 if ((hp = _getrhbyaddr(addr, len, type)) == (struct hostent *)NULL)
323 return ((struct hostent *)NULL);
325 /* hang on to what we got as an answer */
326 (void) strcpy(hbuf, hp->h_name);
328 /* check to make sure by doing a forward query */
329 if ((hp2 = res_gethostbyname(hbuf)) != (struct hostent *)NULL)
330 for (a = hp2->h_addr_list; *a; a++)
331 #ifdef SYSV
332 if (memcmp(*a, addr, hp2->h_length) == 0)
333 #else
334 if (bcmp(*a, addr, hp2->h_length) == 0)
335 #endif
336 return (hp2);
339 * we've been spoofed, make sure to log it.
340 * XXX - syslog needs a security priority level.
342 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", hbuf,
343 inet_ntoa(*(struct in_addr *)addr));
344 return ((struct hostent *)NULL);
347 static void
348 _sethtent(int f)
350 if (__res_no_hosts_fallback()) return;
352 if (hostf == NULL)
353 hostf = fopen(HOSTDB, "r");
354 else
355 rewind(hostf);
356 stayopen |= f;
359 static void
360 _endhtent(void)
362 if (__res_no_hosts_fallback()) return;
364 if (hostf && !stayopen) {
365 (void) fclose(hostf);
366 hostf = NULL;
370 static struct hostent *
371 _gethtent()
373 char *p;
374 register char *cp, **q;
376 if (__res_no_hosts_fallback()) return(NULL);
378 if (hostf == NULL && (hostf = fopen(HOSTDB, "r")) == NULL)
379 return (NULL);
380 again:
381 if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL)
382 return (NULL);
383 if (*p == '#')
384 goto again;
385 cp = any(p, "#\n");
386 if (cp == NULL)
387 goto again;
388 *cp = '\0';
389 cp = any(p, " \t");
390 if (cp == NULL)
391 goto again;
392 *cp++ = '\0';
393 /* THIS STUFF IS INTERNET SPECIFIC */
394 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */
395 host.h_addr_list = host_addrs;
396 #endif
397 host.h_addr = hostaddr;
398 *((u_long *)host.h_addr) = inet_addr(p);
399 host.h_length = sizeof (u_long);
400 host.h_addrtype = AF_INET;
401 while (*cp == ' ' || *cp == '\t')
402 cp++;
403 host.h_name = cp;
404 q = host.h_aliases = host_aliases;
405 cp = any(cp, " \t");
406 if (cp != NULL)
407 *cp++ = '\0';
408 while (cp && *cp) {
409 if (*cp == ' ' || *cp == '\t') {
410 cp++;
411 continue;
413 if (q < &host_aliases[MAXALIASES - 1])
414 *q++ = cp;
415 cp = any(cp, " \t");
416 if (cp != NULL)
417 *cp++ = '\0';
419 *q = NULL;
420 return (&host);
423 static char *
424 any(cp, match)
425 register char *cp;
426 char *match;
428 register char *mp, c;
430 while (c = *cp) {
431 for (mp = match; *mp; mp++)
432 if (*mp == c)
433 return (cp);
434 cp++;
436 return ((char *)0);
439 static struct hostent *
440 _gethtbyname(name)
441 char *name;
443 register struct hostent *p;
444 register char **cp;
446 _sethtent(0);
447 while (p = _gethtent()) {
448 if (strcasecmp(p->h_name, name) == 0)
449 break;
450 for (cp = p->h_aliases; *cp != 0; cp++)
451 if (strcasecmp(*cp, name) == 0)
452 goto found;
454 found:
455 _endhtent();
456 return (p);
459 static struct hostent *
460 _gethtbyaddr(addr, len, type)
461 char *addr;
462 int len, type;
464 register struct hostent *p;
466 _sethtent(0);
467 while (p = _gethtent())
468 #ifdef SYSV
469 if (p->h_addrtype == type && !memcmp(p->h_addr, addr, len))
470 #else
471 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len))
472 #endif
473 break;
474 _endhtent();
475 return (p);