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