1 /* 2 * Copyright (c) 1985, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 */ 13 14 /* 15 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 16 * Use is subject to license terms. 17 */ 18 19 #pragma ident "%Z%%M% %I% %E% SMI" /* SunOS 1.11; UCB 6.32 */ 20 21 #include "c_synonyms.h" 22 #include <sys/param.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <ctype.h> 26 #include <netdb.h> 27 #include <stdio.h> 28 #include <errno.h> 29 #include <arpa/inet.h> 30 #include <arpa/nameser.h> 31 #include <resolv.h> 32 #include <syslog.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((char *)answer->buf, eom, 110 cp, 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((char *)answer->buf, eom, 139 cp, 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((char *)answer->buf, eom, 160 cp, 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 struct hostent * 229 res_gethostbyname(name) 230 char *name; 231 { 232 querybuf buf; 233 register char *cp; 234 int n; 235 struct hostent *hp, *gethostdomain(); 236 static struct hostent *_gethtbyname(); 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 * 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 static struct hostent *_gethtbyaddr(); 277 278 if (type != AF_INET) 279 return ((struct hostent *) NULL); 280 (void) sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa", 281 ((unsigned)addr[3] & 0xff), 282 ((unsigned)addr[2] & 0xff), 283 ((unsigned)addr[1] & 0xff), 284 ((unsigned)addr[0] & 0xff)); 285 n = res_query(qbuf, C_IN, T_PTR, (char *)&buf, sizeof (buf)); 286 if (n < 0) { 287 #ifdef DEBUG 288 if (_res.options & RES_DEBUG) 289 printf("res_query failed\n"); 290 #endif 291 if (errno == ECONNREFUSED) 292 return (_gethtbyaddr(addr, len, type)); 293 return ((struct hostent *) NULL); 294 } 295 hp = getanswer(&buf, n, 1); 296 if (hp == NULL) 297 return ((struct hostent *) NULL); 298 hp->h_addrtype = type; 299 hp->h_length = len; 300 h_addr_ptrs[0] = (char *)&host_addr; 301 h_addr_ptrs[1] = (char *)0; 302 host_addr = *(struct in_addr *)addr; 303 return (hp); 304 } 305 306 /* 307 * First we get what the PTR record says, but do an extra call 308 * to gethostbyname() to make sure that someone is not trying to 309 * spoof us. Hopefully this is not done that often, so good 310 * performance is not really an issue. 311 */ 312 struct hostent * 313 res_gethostbyaddr(addr, len, type) 314 char *addr; 315 int len; 316 int type; 317 { 318 char **a, hbuf[MAXHOSTNAMELEN]; 319 struct hostent *hp, *hp2; 320 321 if ((hp = _getrhbyaddr(addr, len, type)) == (struct hostent *)NULL) 322 return ((struct hostent *)NULL); 323 324 /* hang on to what we got as an answer */ 325 (void) strcpy(hbuf, hp->h_name); 326 327 /* check to make sure by doing a forward query */ 328 if ((hp2 = res_gethostbyname(hbuf)) != (struct hostent *)NULL) 329 for (a = hp2->h_addr_list; *a; a++) 330 #ifdef SYSV 331 if (memcmp(*a, addr, hp2->h_length) == 0) 332 #else 333 if (bcmp(*a, addr, hp2->h_length) == 0) 334 #endif 335 return (hp2); 336 337 /* 338 * we've been spoofed, make sure to log it. 339 * XXX - syslog needs a security priority level. 340 */ 341 syslog(LOG_NOTICE, "gethostbyaddr: %s != %s", hbuf, 342 inet_ntoa(*(struct in_addr *)addr)); 343 return ((struct hostent *)NULL); 344 } 345 346 static void 347 _sethtent(int f) 348 { 349 if (__res_no_hosts_fallback()) return; 350 351 if (hostf == NULL) 352 hostf = fopen(HOSTDB, "r"); 353 else 354 rewind(hostf); 355 stayopen |= f; 356 } 357 358 static void 359 _endhtent(void) 360 { 361 if (__res_no_hosts_fallback()) return; 362 363 if (hostf && !stayopen) { 364 (void) fclose(hostf); 365 hostf = NULL; 366 } 367 } 368 369 static struct hostent * 370 _gethtent() 371 { 372 char *p; 373 register char *cp, **q; 374 375 if (__res_no_hosts_fallback()) return(NULL); 376 377 if (hostf == NULL && (hostf = fopen(HOSTDB, "r")) == NULL) 378 return (NULL); 379 again: 380 if ((p = fgets(hostbuf, BUFSIZ, hostf)) == NULL) 381 return (NULL); 382 if (*p == '#') 383 goto again; 384 cp = any(p, "#\n"); 385 if (cp == NULL) 386 goto again; 387 *cp = '\0'; 388 cp = any(p, " \t"); 389 if (cp == NULL) 390 goto again; 391 *cp++ = '\0'; 392 /* THIS STUFF IS INTERNET SPECIFIC */ 393 #if BSD >= 43 || defined(h_addr) /* new-style hostent structure */ 394 host.h_addr_list = host_addrs; 395 #endif 396 host.h_addr = hostaddr; 397 *((u_long *)host.h_addr) = inet_addr(p); 398 host.h_length = sizeof (u_long); 399 host.h_addrtype = AF_INET; 400 while (*cp == ' ' || *cp == '\t') 401 cp++; 402 host.h_name = cp; 403 q = host.h_aliases = host_aliases; 404 cp = any(cp, " \t"); 405 if (cp != NULL) 406 *cp++ = '\0'; 407 while (cp && *cp) { 408 if (*cp == ' ' || *cp == '\t') { 409 cp++; 410 continue; 411 } 412 if (q < &host_aliases[MAXALIASES - 1]) 413 *q++ = cp; 414 cp = any(cp, " \t"); 415 if (cp != NULL) 416 *cp++ = '\0'; 417 } 418 *q = NULL; 419 return (&host); 420 } 421 422 static char * 423 any(cp, match) 424 register char *cp; 425 char *match; 426 { 427 register char *mp, c; 428 429 while (c = *cp) { 430 for (mp = match; *mp; mp++) 431 if (*mp == c) 432 return (cp); 433 cp++; 434 } 435 return ((char *)0); 436 } 437 438 static struct hostent * 439 _gethtbyname(name) 440 char *name; 441 { 442 register struct hostent *p; 443 register char **cp; 444 445 _sethtent(0); 446 while (p = _gethtent()) { 447 if (strcasecmp(p->h_name, name) == 0) 448 break; 449 for (cp = p->h_aliases; *cp != 0; cp++) 450 if (strcasecmp(*cp, name) == 0) 451 goto found; 452 } 453 found: 454 _endhtent(); 455 return (p); 456 } 457 458 static struct hostent * 459 _gethtbyaddr(addr, len, type) 460 char *addr; 461 int len, type; 462 { 463 register struct hostent *p; 464 465 _sethtent(0); 466 while (p = _gethtent()) 467 #ifdef SYSV 468 if (p->h_addrtype == type && !memcmp(p->h_addr, addr, len)) 469 #else 470 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len)) 471 #endif 472 break; 473 _endhtent(); 474 return (p); 475 } 476