1 /* 2 * Copyright (c) 1985 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #if defined(LIBC_SCCS) && !defined(lint) 8 static char sccsid[] = "@(#)gethostnamadr.c 6.14 (Berkeley) 10/30/86"; 9 #endif LIBC_SCCS and not lint 10 11 #include <sys/types.h> 12 #include <sys/socket.h> 13 #include <netinet/in.h> 14 #include <ctype.h> 15 #include <netdb.h> 16 #include <stdio.h> 17 #include <errno.h> 18 #include <arpa/inet.h> 19 #include <arpa/nameser.h> 20 #include <resolv.h> 21 22 #define MAXALIASES 35 23 #define MAXADDRS 35 24 25 static char *h_addr_ptrs[MAXADDRS + 1]; 26 27 static struct hostent host; 28 static char *host_aliases[MAXALIASES]; 29 static char hostbuf[BUFSIZ+1]; 30 static struct in_addr host_addr; 31 static char HOSTDB[] = "/etc/hosts"; 32 static FILE *hostf = NULL; 33 static char line[BUFSIZ+1]; 34 static char hostaddr[MAXADDRS]; 35 static char *host_addrs[2]; 36 static int stayopen = 0; 37 static char *any(); 38 39 typedef union { 40 HEADER qb1; 41 char qb2[PACKETSZ]; 42 } querybuf; 43 44 static union { 45 long al; 46 char ac; 47 } align; 48 49 50 int h_errno; 51 extern errno; 52 53 static struct hostent * 54 getanswer(msg, msglen, iquery) 55 char *msg; 56 int msglen, iquery; 57 { 58 register HEADER *hp; 59 register char *cp; 60 register int n; 61 querybuf answer; 62 char *eom, *bp, **ap; 63 int type, class, buflen, ancount, qdcount; 64 int haveanswer, getclass = C_ANY; 65 char **hap; 66 67 n = res_send(msg, msglen, (char *)&answer, sizeof(answer)); 68 if (n < 0) { 69 #ifdef DEBUG 70 int terrno; 71 terrno = errno; 72 if (_res.options & RES_DEBUG) 73 printf("res_send failed\n"); 74 errno = terrno; 75 #endif 76 h_errno = TRY_AGAIN; 77 return (NULL); 78 } 79 eom = (char *)&answer + n; 80 /* 81 * find first satisfactory answer 82 */ 83 hp = (HEADER *) &answer; 84 ancount = ntohs(hp->ancount); 85 qdcount = ntohs(hp->qdcount); 86 if (hp->rcode != NOERROR || ancount == 0) { 87 #ifdef DEBUG 88 if (_res.options & RES_DEBUG) 89 printf("rcode = %d, ancount=%d\n", hp->rcode, ancount); 90 #endif 91 switch (hp->rcode) { 92 case NXDOMAIN: 93 /* Check if it's an authoritive answer */ 94 if (hp->aa) 95 h_errno = HOST_NOT_FOUND; 96 else 97 h_errno = TRY_AGAIN; 98 break; 99 case SERVFAIL: 100 h_errno = TRY_AGAIN; 101 break; 102 case NOERROR: 103 h_errno = NO_ADDRESS; 104 break; 105 case FORMERR: 106 case NOTIMP: 107 case REFUSED: 108 h_errno = NO_RECOVERY; 109 } 110 return (NULL); 111 } 112 bp = hostbuf; 113 buflen = sizeof(hostbuf); 114 cp = (char *)&answer + sizeof(HEADER); 115 if (qdcount) { 116 if (iquery) { 117 if ((n = dn_expand((char *)&answer, eom, 118 cp, bp, buflen)) < 0) { 119 h_errno = NO_RECOVERY; 120 return (NULL); 121 } 122 cp += n + QFIXEDSZ; 123 host.h_name = bp; 124 n = strlen(bp) + 1; 125 bp += n; 126 buflen -= n; 127 } else 128 cp += dn_skip(cp) + QFIXEDSZ; 129 while (--qdcount > 0) 130 cp += dn_skip(cp) + QFIXEDSZ; 131 } else if (iquery) { 132 if (hp->aa) 133 h_errno = HOST_NOT_FOUND; 134 else 135 h_errno = TRY_AGAIN; 136 return (NULL); 137 } 138 ap = host_aliases; 139 host.h_aliases = host_aliases; 140 hap = h_addr_ptrs; 141 host.h_addr_list = h_addr_ptrs; 142 haveanswer = 0; 143 while (--ancount >= 0 && cp < eom) { 144 if ((n = dn_expand((char *)&answer, eom, cp, bp, buflen)) < 0) 145 break; 146 cp += n; 147 type = getshort(cp); 148 cp += sizeof(u_short); 149 class = getshort(cp); 150 cp += sizeof(u_short) + sizeof(u_long); 151 n = getshort(cp); 152 cp += sizeof(u_short); 153 if (type == T_CNAME) { 154 cp += n; 155 if (ap >= &host_aliases[MAXALIASES-1]) 156 continue; 157 *ap++ = bp; 158 n = strlen(bp) + 1; 159 bp += n; 160 buflen -= n; 161 continue; 162 } 163 if (type == T_PTR) { 164 if ((n = dn_expand((char *)&answer, eom, 165 cp, bp, buflen)) < 0) { 166 cp += n; 167 continue; 168 } 169 cp += n; 170 host.h_name = bp; 171 return(&host); 172 } 173 if (type != T_A) { 174 #ifdef DEBUG 175 if (_res.options & RES_DEBUG) 176 printf("unexpected answer type %d, size %d\n", 177 type, n); 178 #endif 179 cp += n; 180 continue; 181 } 182 if (haveanswer) { 183 if (n != host.h_length) { 184 cp += n; 185 continue; 186 } 187 if (class != getclass) { 188 cp += n; 189 continue; 190 } 191 } else { 192 host.h_length = n; 193 getclass = class; 194 host.h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC; 195 if (!iquery) { 196 host.h_name = bp; 197 bp += strlen(bp) + 1; 198 } 199 } 200 201 bp += (sizeof(align) - ((u_long)bp % sizeof(align))) &~ 202 sizeof(align); 203 204 if (bp + n >= &hostbuf[sizeof(hostbuf)]) { 205 #ifdef DEBUG 206 if (_res.options & RES_DEBUG) 207 printf("size (%d) too big\n", n); 208 #endif 209 break; 210 } 211 bcopy(cp, *hap++ = bp, n); 212 bp +=n; 213 cp += n; 214 haveanswer++; 215 } 216 if (haveanswer) { 217 *ap = NULL; 218 *hap = NULL; 219 return (&host); 220 } else { 221 h_errno = TRY_AGAIN; 222 return (NULL); 223 } 224 } 225 226 struct hostent * 227 gethostbyname(name) 228 char *name; 229 { 230 int n; 231 querybuf buf; 232 register struct hostent *hp; 233 extern struct hostent *_gethtbyname(); 234 235 errno = 0; 236 n = res_mkquery(QUERY, name, C_IN, T_A, (char *)NULL, 0, NULL, 237 (char *)&buf, sizeof(buf)); 238 if (n < 0) { 239 #ifdef DEBUG 240 if (_res.options & RES_DEBUG) 241 printf("res_mkquery failed\n"); 242 #endif 243 return (NULL); 244 } 245 hp = getanswer((char *)&buf, n, 0); 246 if (hp == NULL && errno == ECONNREFUSED) 247 hp = _gethtbyname(name); 248 return(hp); 249 } 250 251 struct hostent * 252 gethostbyaddr(addr, len, type) 253 char *addr; 254 int len, type; 255 { 256 int n; 257 querybuf buf; 258 register struct hostent *hp; 259 char qbuf[MAXDNAME]; 260 extern struct hostent *_gethtbyaddr(); 261 262 if (type != AF_INET) 263 return (NULL); 264 (void)sprintf(qbuf, "%d.%d.%d.%d.in-addr.arpa", 265 ((unsigned)addr[3] & 0xff), 266 ((unsigned)addr[2] & 0xff), 267 ((unsigned)addr[1] & 0xff), 268 ((unsigned)addr[0] & 0xff)); 269 n = res_mkquery(QUERY, qbuf, C_IN, T_PTR, (char *)NULL, 0, NULL, 270 (char *)&buf, sizeof(buf)); 271 if (n < 0) { 272 #ifdef DEBUG 273 if (_res.options & RES_DEBUG) 274 printf("res_mkquery failed\n"); 275 #endif 276 return (NULL); 277 } 278 hp = getanswer((char *)&buf, n, 1); 279 if (hp == NULL && errno == ECONNREFUSED) 280 hp = _gethtbyaddr(addr, len, type); 281 if (hp == NULL) 282 return(NULL); 283 hp->h_addrtype = type; 284 hp->h_length = len; 285 h_addr_ptrs[0] = (char *)&host_addr; 286 h_addr_ptrs[1] = (char *)0; 287 host_addr = *(struct in_addr *)addr; 288 return(hp); 289 } 290 291 292 _sethtent(f) 293 int f; 294 { 295 if (hostf == NULL) 296 hostf = fopen(HOSTDB, "r" ); 297 else 298 rewind(hostf); 299 stayopen |= f; 300 } 301 302 _endhtent() 303 { 304 if (hostf && !stayopen) { 305 (void) fclose(hostf); 306 hostf = NULL; 307 } 308 } 309 310 struct hostent * 311 _gethtent() 312 { 313 char *p; 314 register char *cp, **q; 315 316 if (hostf == NULL && (hostf = fopen(HOSTDB, "r" )) == NULL) 317 return (NULL); 318 again: 319 if ((p = fgets(line, BUFSIZ, hostf)) == NULL) 320 return (NULL); 321 if (*p == '#') 322 goto again; 323 cp = any(p, "#\n"); 324 if (cp == NULL) 325 goto again; 326 *cp = '\0'; 327 cp = any(p, " \t"); 328 if (cp == NULL) 329 goto again; 330 *cp++ = '\0'; 331 /* THIS STUFF IS INTERNET SPECIFIC */ 332 host.h_addr_list = host_addrs; 333 host.h_addr = hostaddr; 334 *((u_long *)host.h_addr) = inet_addr(p); 335 host.h_length = sizeof (u_long); 336 host.h_addrtype = AF_INET; 337 while (*cp == ' ' || *cp == '\t') 338 cp++; 339 host.h_name = cp; 340 q = host.h_aliases = host_aliases; 341 cp = any(cp, " \t"); 342 if (cp != NULL) 343 *cp++ = '\0'; 344 while (cp && *cp) { 345 if (*cp == ' ' || *cp == '\t') { 346 cp++; 347 continue; 348 } 349 if (q < &host_aliases[MAXALIASES - 1]) 350 *q++ = cp; 351 cp = any(cp, " \t"); 352 if (cp != NULL) 353 *cp++ = '\0'; 354 } 355 *q = NULL; 356 return (&host); 357 } 358 359 static char * 360 any(cp, match) 361 register char *cp; 362 char *match; 363 { 364 register char *mp, c; 365 366 while (c = *cp) { 367 for (mp = match; *mp; mp++) 368 if (*mp == c) 369 return (cp); 370 cp++; 371 } 372 return ((char *)0); 373 } 374 375 struct hostent * 376 _gethtbyname(name) 377 char *name; 378 { 379 register struct hostent *p; 380 register char **cp; 381 char lowname[128]; 382 register char *lp = lowname; 383 384 while (*name) 385 if (isupper(*name)) 386 *lp++ = tolower(*name++); 387 else 388 *lp++ = *name++; 389 *lp = '\0'; 390 391 _sethtent(0); 392 while (p = _gethtent()) { 393 if (strcmp(p->h_name, lowname) == 0) 394 break; 395 for (cp = p->h_aliases; *cp != 0; cp++) 396 if (strcmp(*cp, lowname) == 0) 397 goto found; 398 } 399 found: 400 _endhtent(); 401 return (p); 402 } 403 404 struct hostent * 405 _gethtbyaddr(addr, len, type) 406 char *addr; 407 int len, type; 408 { 409 register struct hostent *p; 410 411 _sethtent(0); 412 while (p = _gethtent()) 413 if (p->h_addrtype == type && !bcmp(p->h_addr, addr, len)) 414 break; 415 _endhtent(); 416 return (p); 417 } 418