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