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 41 __res_set_no_hosts_fallback(void) { 42 no_hosts_fallback = 1; 43 } 44 45 static int 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 * 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 * 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 * 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 * 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 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 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 * 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 * 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 * 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 * 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 }