1 /*
2 * Copyright 2015 Gary Mills
3 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
4 * Use is subject to license terms.
5 */
6
7 /*
8 * Copyright (c) 1985, 1988 Regents of the University of California.
9 * All rights reserved.
10 *
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.
17 *
18 */
19
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"
33
34 /*
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.
37 */
38 static int no_hosts_fallback = 0;
39
40 void
__res_set_no_hosts_fallback(void)41 __res_set_no_hosts_fallback(void) {
42 no_hosts_fallback = 1;
43 }
44
45 static int
__res_no_hosts_fallback(void)46 __res_no_hosts_fallback(void) {
47 return(no_hosts_fallback);
48 }
49
50 static char *h_addr_ptrs[MAXADDRS + 1];
51
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();
62
63 #if PACKETSZ > 1024
64 #define MAXPACKET PACKETSZ
65 #else
66 #define MAXPACKET 1024
67 #endif
68
69 typedef union {
70 HEADER hdr;
71 u_char buf[MAXPACKET];
72 } querybuf;
73
74 static union {
75 long al;
76 char ac;
77 } align;
78
79
80 int h_errno;
81
82 static struct hostent *
getanswer(answer,anslen,iquery)83 getanswer(answer, anslen, iquery)
84 querybuf *answer;
85 int anslen;
86 int iquery;
87 {
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;
96
97 eom = answer->buf + anslen;
98 /*
99 * find first satisfactory answer
100 */
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);
113 }
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);
129 }
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;
157 }
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;
163 }
164 cp += n;
165 host.h_name = bp;
166 return (&host);
167 }
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;
176 }
177 if (haveanswer) {
178 if (n != host.h_length) {
179 cp += n;
180 continue;
181 }
182 if (class != getclass) {
183 cp += n;
184 continue;
185 }
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;
193 }
194 }
195
196 bp += sizeof (align) - ((u_long)bp % sizeof (align));
197
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;
204 }
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++;
213 }
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);
225 }
226 }
227
228 static struct hostent *_gethtbyname();
229
230 struct hostent *
res_gethostbyname(name)231 res_gethostbyname(name)
232 char *name;
233 {
234 querybuf buf;
235 register char *cp;
236 int n;
237
238 /*
239 * disallow names consisting only of digits/dots, unless
240 * they end in a dot.
241 */
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);
249 }
250 if (!isdigit(*cp) && *cp != '.')
251 break;
252 }
253
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);
263 }
264 return (getanswer(&buf, n, 0));
265 }
266
267 static struct hostent *_gethtbyaddr();
268
269 static struct hostent *
_getrhbyaddr(addr,len,type)270 _getrhbyaddr(addr, len, type)
271 char *addr;
272 int len, type;
273 {
274 int n;
275 querybuf buf;
276 register struct hostent *hp;
277 char qbuf[MAXDNAME];
278
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);
295 }
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);
305 }
306
307 /*
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.
312 */
313 struct hostent *
res_gethostbyaddr(addr,len,type)314 res_gethostbyaddr(addr, len, type)
315 char *addr;
316 int len;
317 int type;
318 {
319 char **a, hbuf[MAXHOSTNAMELEN];
320 struct hostent *hp, *hp2;
321
322 if ((hp = _getrhbyaddr(addr, len, type)) == (struct hostent *)NULL)
323 return ((struct hostent *)NULL);
324
325 /* hang on to what we got as an answer */
326 (void) strcpy(hbuf, hp->h_name);
327
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);
337
338 /*
339 * we've been spoofed, make sure to log it.
340 * XXX - syslog needs a security priority level.
341 */
342 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", hbuf,
343 inet_ntoa(*(struct in_addr *)addr));
344 return ((struct hostent *)NULL);
345 }
346
347 static void
_sethtent(int f)348 _sethtent(int f)
349 {
350 if (__res_no_hosts_fallback()) return;
351
352 if (hostf == NULL)
353 hostf = fopen(HOSTDB, "r");
354 else
355 rewind(hostf);
356 stayopen |= f;
357 }
358
359 static void
_endhtent(void)360 _endhtent(void)
361 {
362 if (__res_no_hosts_fallback()) return;
363
364 if (hostf && !stayopen) {
365 (void) fclose(hostf);
366 hostf = NULL;
367 }
368 }
369
370 static struct hostent *
_gethtent()371 _gethtent()
372 {
373 char *p;
374 register char *cp, **q;
375
376 if (__res_no_hosts_fallback()) return(NULL);
377
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;
412 }
413 if (q < &host_aliases[MAXALIASES - 1])
414 *q++ = cp;
415 cp = any(cp, " \t");
416 if (cp != NULL)
417 *cp++ = '\0';
418 }
419 *q = NULL;
420 return (&host);
421 }
422
423 static char *
any(cp,match)424 any(cp, match)
425 register char *cp;
426 char *match;
427 {
428 register char *mp, c;
429
430 while (c = *cp) {
431 for (mp = match; *mp; mp++)
432 if (*mp == c)
433 return (cp);
434 cp++;
435 }
436 return ((char *)0);
437 }
438
439 static struct hostent *
_gethtbyname(name)440 _gethtbyname(name)
441 char *name;
442 {
443 register struct hostent *p;
444 register char **cp;
445
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;
453 }
454 found:
455 _endhtent();
456 return (p);
457 }
458
459 static struct hostent *
_gethtbyaddr(addr,len,type)460 _gethtbyaddr(addr, len, type)
461 char *addr;
462 int len, type;
463 {
464 register struct hostent *p;
465
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);
476 }
477