1 /* 2 * Copyright 2008 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 #pragma ident "%Z%%M% %I% %E% SMI" 20 21 #include <sys/param.h> 22 #include <sys/socket.h> 23 #include <netinet/in.h> 24 #include <ctype.h> 25 #include <netdb.h> 26 #include <stdio.h> 27 #include <errno.h> 28 #include <arpa/inet.h> 29 #include <arpa/nameser.h> 30 #include <resolv.h> 31 #include <syslog.h> 32 33 /* 34 * When the name service switch calls libresolv, it doesn't want fallback 35 * to /etc/hosts, so we provide a method to turn it off. 36 */ 37 static int no_hosts_fallback = 0; 38 39 void 40 __res_set_no_hosts_fallback(void) { 41 no_hosts_fallback = 1; 42 } 43 44 static int 45 __res_no_hosts_fallback(void) { 46 return(no_hosts_fallback); 47 } 48 49 static char *h_addr_ptrs[MAXADDRS + 1]; 50 51 static struct hostent host; 52 static char *host_aliases[MAXALIASES]; 53 static char hostbuf[BUFSIZ+1]; 54 static struct in_addr host_addr; 55 static char HOSTDB[] = "/etc/hosts"; 56 static FILE *hostf = NULL; 57 static char hostaddr[MAXADDRS]; 58 static char *host_addrs[2]; 59 static int stayopen = 0; 60 static char *any(); 61 62 #if PACKETSZ > 1024 63 #define MAXPACKET PACKETSZ 64 #else 65 #define MAXPACKET 1024 66 #endif 67 68 typedef union { 69 HEADER hdr; 70 u_char buf[MAXPACKET]; 71 } querybuf; 72 73 static union { 74 long al; 75 char ac; 76 } align; 77 78 79 int h_errno; 80 81 static struct hostent * 82 getanswer(answer, anslen, iquery) 83 querybuf *answer; 84 int anslen; 85 int iquery; 86 { 87 register HEADER *hp; 88 register u_char *cp; 89 register int n; 90 u_char *eom; 91 char *bp, **ap; 92 int type, class, buflen, ancount, qdcount; 93 int haveanswer, getclass = C_ANY; 94 char **hap; 95 96 eom = answer->buf + anslen; 97 /* 98 * find first satisfactory answer 99 */ 100 hp = &answer->hdr; 101 ancount = ntohs(hp->ancount); 102 qdcount = ntohs(hp->qdcount); 103 bp = hostbuf; 104 buflen = sizeof (hostbuf); 105 cp = answer->buf + sizeof (HEADER); 106 if (qdcount) { 107 if (iquery) { 108 if ((n = dn_expand((char *)answer->buf, eom, 109 cp, bp, buflen)) < 0) { 110 h_errno = NO_RECOVERY; 111 return ((struct hostent *) NULL); 112 } 113 cp += n + QFIXEDSZ; 114 host.h_name = bp; 115 n = strlen(bp) + 1; 116 bp += n; 117 buflen -= n; 118 } else 119 cp += dn_skipname(cp, eom) + QFIXEDSZ; 120 while (--qdcount > 0) 121 cp += dn_skipname(cp, eom) + QFIXEDSZ; 122 } else if (iquery) { 123 if (hp->aa) 124 h_errno = HOST_NOT_FOUND; 125 else 126 h_errno = TRY_AGAIN; 127 return ((struct hostent *) NULL); 128 } 129 ap = host_aliases; 130 host.h_aliases = host_aliases; 131 hap = h_addr_ptrs; 132 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ 133 host.h_addr_list = h_addr_ptrs; 134 #endif 135 haveanswer = 0; 136 while (--ancount >= 0 && cp < eom && haveanswer < MAXADDRS) { 137 if ((n = dn_expand((char *)answer->buf, eom, 138 cp, bp, buflen)) < 0) 139 break; 140 cp += n; 141 type = _getshort(cp); 142 cp += sizeof (u_short); 143 class = _getshort(cp); 144 cp += sizeof (u_short) + sizeof (u_long); 145 n = _getshort(cp); 146 cp += sizeof (u_short); 147 if (type == T_CNAME) { 148 cp += n; 149 if (ap >= &host_aliases[MAXALIASES-1]) 150 continue; 151 *ap++ = bp; 152 n = strlen(bp) + 1; 153 bp += n; 154 buflen -= n; 155 continue; 156 } 157 if (iquery && type == T_PTR) { 158 if ((n = dn_expand((char *)answer->buf, eom, 159 cp, bp, buflen)) < 0) { 160 cp += n; 161 continue; 162 } 163 cp += n; 164 host.h_name = bp; 165 return (&host); 166 } 167 if (iquery || type != T_A) { 168 #ifdef DEBUG 169 if (_res.options & RES_DEBUG) 170 printf("unexpected answer type %d, size %d\n", 171 type, n); 172 #endif 173 cp += n; 174 continue; 175 } 176 if (haveanswer) { 177 if (n != host.h_length) { 178 cp += n; 179 continue; 180 } 181 if (class != getclass) { 182 cp += n; 183 continue; 184 } 185 } else { 186 host.h_length = n; 187 getclass = class; 188 host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; 189 if (!iquery) { 190 host.h_name = bp; 191 bp += strlen(bp) + 1; 192 } 193 } 194 195 bp += sizeof (align) - ((u_long)bp % sizeof (align)); 196 197 if (bp + n >= &hostbuf[sizeof (hostbuf)]) { 198 #ifdef DEBUG 199 if (_res.options & RES_DEBUG) 200 printf("size (%d) too big\n", n); 201 #endif 202 break; 203 } 204 #ifdef SYSV 205 memcpy((void *)(*hap++ = bp), (void *)cp, n); 206 #else 207 bcopy(cp, *hap++ = bp, n); 208 #endif 209 bp += n; 210 cp += n; 211 haveanswer++; 212 } 213 if (haveanswer) { 214 *ap = NULL; 215 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ 216 *hap = NULL; 217 #else 218 host.h_addr = h_addr_ptrs[0]; 219 #endif 220 return (&host); 221 } else { 222 h_errno = TRY_AGAIN; 223 return ((struct hostent *) NULL); 224 } 225 } 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 static struct hostent *_gethtbyname(); 236 237 /* 238 * disallow names consisting only of digits/dots, unless 239 * they end in a dot. 240 */ 241 if (isdigit(name[0])) 242 for (cp = name; /*EMPTY*/; ++cp) { 243 if (!*cp) { 244 if (*--cp == '.') 245 break; 246 h_errno = HOST_NOT_FOUND; 247 return ((struct hostent *) NULL); 248 } 249 if (!isdigit(*cp) && *cp != '.') 250 break; 251 } 252 253 if ((n = res_search(name, C_IN, T_A, buf.buf, sizeof (buf))) < 0) { 254 #ifdef DEBUG 255 if (_res.options & RES_DEBUG) 256 printf("res_search failed\n"); 257 #endif 258 if (errno == ECONNREFUSED) 259 return (_gethtbyname(name)); 260 else 261 return ((struct hostent *) NULL); 262 } 263 return (getanswer(&buf, n, 0)); 264 } 265 266 static struct hostent * 267 _getrhbyaddr(addr, len, type) 268 char *addr; 269 int len, type; 270 { 271 int n; 272 querybuf buf; 273 register struct hostent *hp; 274 char qbuf[MAXDNAME]; 275 static struct hostent *_gethtbyaddr(); 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