1 /* $NetBSD: getnetnamadr.c,v 1.41 2008/05/18 22:36:15 lukem Exp $ */ 2 3 /* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro 4 * Dep. Matematica Universidade de Coimbra, Portugal, Europe 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 */ 10 /* 11 * Copyright (c) 1983, 1993 12 * The Regents of the University of California. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 #if 0 42 static char sccsid[] = "@(#)getnetbyaddr.c 8.1 (Berkeley) 6/4/93"; 43 static char sccsid_[] = "from getnetnamadr.c 1.4 (Coimbra) 93/06/03"; 44 static char rcsid[] = "Id: getnetnamadr.c,v 8.8 1997/06/01 20:34:37 vixie Exp "; 45 #else 46 __RCSID("$NetBSD: getnetnamadr.c,v 1.41 2008/05/18 22:36:15 lukem Exp $"); 47 #endif 48 #endif /* LIBC_SCCS and not lint */ 49 50 #include "namespace.h" 51 #include <sys/types.h> 52 #include <sys/param.h> 53 #include <sys/socket.h> 54 #include <netinet/in.h> 55 #include <arpa/inet.h> 56 #include <arpa/nameser.h> 57 58 #include <assert.h> 59 #include <ctype.h> 60 #include <errno.h> 61 #include <netdb.h> 62 #include <nsswitch.h> 63 #include <resolv.h> 64 #include <stdarg.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 69 #ifdef YP 70 #include <rpc/rpc.h> 71 #include <rpcsvc/yp_prot.h> 72 #include <rpcsvc/ypclnt.h> 73 #endif 74 75 #ifdef __weak_alias 76 __weak_alias(getnetbyaddr,_getnetbyaddr) 77 __weak_alias(getnetbyname,_getnetbyname) 78 #endif 79 80 extern int _net_stayopen; 81 82 #define BYADDR 0 83 #define BYNAME 1 84 #define MAXALIASES 35 85 86 #define MAXPACKET (64*1024) 87 88 typedef union { 89 HEADER hdr; 90 u_char buf[MAXPACKET]; 91 } querybuf; 92 93 typedef union { 94 long al; 95 char ac; 96 } align; 97 98 #ifdef YP 99 static char *__ypdomain; 100 static char *__ypcurrent; 101 static int __ypcurrentlen; 102 #endif 103 104 static struct netent net_entry; 105 static char *net_aliases[MAXALIASES]; 106 107 static int parse_reversed_addr(const char *, in_addr_t *); 108 static struct netent *getnetanswer(querybuf *, int, int); 109 static int _files_getnetbyaddr(void *, void *, va_list); 110 static int _files_getnetbyname(void *, void *, va_list); 111 static int _dns_getnetbyaddr(void *, void *, va_list); 112 static int _dns_getnetbyname(void *, void *, va_list); 113 #ifdef YP 114 static int _yp_getnetbyaddr(void *, void *, va_list); 115 static int _yp_getnetbyname(void *, void *, va_list); 116 static struct netent *_ypnetent(char *); 117 #endif 118 119 /* 120 * parse_reversed_addr -- 121 * parse str, which should be of the form 'd.c.b.a.IN-ADDR.ARPA' 122 * (a PTR as per RFC 1101) and convert into an in_addr_t of the 123 * address 'a.b.c.d'. 124 * returns 0 on success (storing in *result), or -1 on error. 125 */ 126 static int 127 parse_reversed_addr(const char *str, in_addr_t *result) 128 { 129 unsigned long octet[4]; 130 const char *sp; 131 char *ep; 132 int octidx; 133 134 sp = str; 135 /* find the four octets 'd.b.c.a.' */ 136 for (octidx = 0; octidx < 4; octidx++) { 137 /* ensure it's a number */ 138 if (!isdigit((unsigned char)*sp)) 139 return -1; 140 octet[octidx] = strtoul(sp, &ep, 10); 141 /* with a trailing '.' */ 142 if (*ep != '.') 143 return -1; 144 /* and is 0 <= octet <= 255 */ 145 if (octet[octidx] > 255) 146 return -1; 147 sp = ep + 1; 148 } 149 /* ensure trailer is correct */ 150 if (strcasecmp(sp, "IN-ADDR.ARPA") != 0) 151 return -1; 152 *result = 0; 153 /* build result from octets in reverse */ 154 for (octidx = 3; octidx >= 0; octidx--) { 155 *result <<= 8; 156 *result |= (octet[octidx] & 0xff); 157 } 158 return 0; 159 } 160 161 static struct netent * 162 getnetanswer(querybuf *answer, int anslen, int net_i) 163 { 164 static char n_name[MAXDNAME]; 165 static char netbuf[PACKETSZ]; 166 167 HEADER *hp; 168 u_char *cp; 169 int n; 170 u_char *eom; 171 int type, class, ancount, qdcount, haveanswer; 172 char *in, *bp, **ap, *ep; 173 174 _DIAGASSERT(answer != NULL); 175 176 /* 177 * find first satisfactory answer 178 * 179 * answer --> +------------+ ( MESSAGE ) 180 * | Header | 181 * +------------+ 182 * | Question | the question for the name server 183 * +------------+ 184 * | Answer | RRs answering the question 185 * +------------+ 186 * | Authority | RRs pointing toward an authority 187 * | Additional | RRs holding additional information 188 * +------------+ 189 */ 190 eom = answer->buf + anslen; 191 hp = &answer->hdr; 192 ancount = ntohs(hp->ancount); /* #/records in the answer section */ 193 qdcount = ntohs(hp->qdcount); /* #/entries in the question section */ 194 bp = netbuf; 195 ep = netbuf + sizeof(netbuf); 196 cp = answer->buf + HFIXEDSZ; 197 if (!qdcount) { 198 if (hp->aa) 199 h_errno = HOST_NOT_FOUND; 200 else 201 h_errno = TRY_AGAIN; 202 return NULL; 203 } 204 while (qdcount-- > 0) { 205 n = __dn_skipname(cp, eom); 206 if (n < 0 || (cp + n + QFIXEDSZ) > eom) { 207 h_errno = NO_RECOVERY; 208 return(NULL); 209 } 210 cp += n + QFIXEDSZ; 211 } 212 ap = net_aliases; 213 *ap = NULL; 214 net_entry.n_aliases = net_aliases; 215 haveanswer = 0; 216 n_name[0] = '\0'; 217 while (--ancount >= 0 && cp < eom) { 218 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 219 if ((n < 0) || !res_dnok(bp)) 220 break; 221 cp += n; 222 (void)strlcpy(n_name, bp, sizeof(n_name)); 223 GETSHORT(type, cp); 224 GETSHORT(class, cp); 225 cp += INT32SZ; /* TTL */ 226 GETSHORT(n, cp); 227 if (class == C_IN && type == T_PTR) { 228 n = dn_expand(answer->buf, eom, cp, bp, ep - bp); 229 if ((n < 0) || !res_hnok(bp)) { 230 cp += n; 231 return NULL; 232 } 233 cp += n; 234 *ap++ = bp; 235 bp += strlen(bp) + 1; 236 net_entry.n_addrtype = 237 (class == C_IN) ? AF_INET : AF_UNSPEC; 238 haveanswer++; 239 } 240 } 241 if (haveanswer) { 242 *ap = NULL; 243 switch (net_i) { 244 case BYADDR: 245 net_entry.n_name = *net_entry.n_aliases; 246 net_entry.n_net = 0L; 247 break; 248 case BYNAME: 249 ap = net_entry.n_aliases; 250 next_alias: 251 in = *ap++; 252 if (in == NULL) { 253 h_errno = HOST_NOT_FOUND; 254 return NULL; 255 } 256 net_entry.n_name = n_name; 257 if (parse_reversed_addr(in, &net_entry.n_net) == -1) 258 goto next_alias; 259 break; 260 } 261 net_entry.n_aliases++; 262 #if (defined(__sparc__) && defined(_LP64)) || \ 263 defined(__alpha__) || \ 264 (defined(__i386__) && defined(_LP64)) || \ 265 (defined(__sh__) && defined(_LP64)) 266 net_entry.__n_pad0 = 0; 267 #endif 268 return &net_entry; 269 } 270 h_errno = TRY_AGAIN; 271 return NULL; 272 } 273 274 /*ARGSUSED*/ 275 static int 276 _files_getnetbyaddr(void *cbrv, void *cbdata, va_list ap) 277 { 278 struct netent **retval = va_arg(ap, struct netent **); 279 uint32_t net = va_arg(ap, uint32_t); 280 int type = va_arg(ap, int); 281 282 struct netent *np; 283 284 setnetent(_net_stayopen); 285 while ((np = getnetent()) != NULL) 286 if (np->n_addrtype == type && np->n_net == net) 287 break; 288 if (!_net_stayopen) 289 endnetent(); 290 291 if (np != NULL) { 292 *retval = np; 293 return NS_SUCCESS; 294 } else { 295 h_errno = HOST_NOT_FOUND; 296 return NS_NOTFOUND; 297 } 298 } 299 300 /*ARGSUSED*/ 301 static int 302 _dns_getnetbyaddr(void *cbrv, void *cbdata, va_list ap) 303 { 304 struct netent **retval = va_arg(ap, struct netent **); 305 uint32_t net = va_arg(ap, uint32_t); 306 int type = va_arg(ap, int); 307 308 unsigned int netbr[4]; 309 int nn, anslen; 310 querybuf *buf; 311 char qbuf[MAXDNAME]; 312 uint32_t net2; 313 struct netent *np; 314 res_state res; 315 316 if (type != AF_INET) 317 return NS_UNAVAIL; 318 319 for (nn = 4, net2 = net; net2; net2 >>= 8) 320 netbr[--nn] = (unsigned int)(net2 & 0xff); 321 switch (nn) { 322 default: 323 return NS_UNAVAIL; 324 case 3: /* Class A */ 325 snprintf(qbuf, sizeof(qbuf), "0.0.0.%u.in-addr.arpa", netbr[3]); 326 break; 327 case 2: /* Class B */ 328 snprintf(qbuf, sizeof(qbuf), "0.0.%u.%u.in-addr.arpa", 329 netbr[3], netbr[2]); 330 break; 331 case 1: /* Class C */ 332 snprintf(qbuf, sizeof(qbuf), "0.%u.%u.%u.in-addr.arpa", 333 netbr[3], netbr[2], netbr[1]); 334 break; 335 case 0: /* Class D - E */ 336 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 337 netbr[3], netbr[2], netbr[1], netbr[0]); 338 break; 339 } 340 buf = malloc(sizeof(*buf)); 341 if (buf == NULL) { 342 h_errno = NETDB_INTERNAL; 343 return NS_NOTFOUND; 344 } 345 res = __res_get_state(); 346 if (res == NULL) { 347 free(buf); 348 return NS_NOTFOUND; 349 } 350 anslen = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf)); 351 if (anslen < 0) { 352 free(buf); 353 #ifdef DEBUG 354 if (res->options & RES_DEBUG) 355 printf("res_query failed\n"); 356 #endif 357 __res_put_state(res); 358 return NS_NOTFOUND; 359 } 360 __res_put_state(res); 361 np = getnetanswer(buf, anslen, BYADDR); 362 free(buf); 363 if (np) { 364 /* maybe net should be unsigned? */ 365 uint32_t u_net = net; 366 367 /* Strip trailing zeros */ 368 while ((u_net & 0xff) == 0 && u_net != 0) 369 u_net >>= 8; 370 np->n_net = u_net; 371 } 372 373 if (np != NULL) { 374 *retval = np; 375 return NS_SUCCESS; 376 } else { 377 h_errno = HOST_NOT_FOUND; 378 return NS_NOTFOUND; 379 } 380 } 381 382 struct netent * 383 getnetbyaddr(uint32_t net, int net_type) 384 { 385 int rv; 386 struct netent *retval; 387 388 static const ns_dtab dtab[] = { 389 NS_FILES_CB(_files_getnetbyaddr, NULL) 390 { NSSRC_DNS, _dns_getnetbyaddr, NULL }, /* force -DHESIOD */ 391 NS_NIS_CB(_yp_getnetbyaddr, NULL) 392 NS_NULL_CB 393 }; 394 395 retval = NULL; 396 h_errno = NETDB_INTERNAL; 397 rv = nsdispatch(NULL, dtab, NSDB_NETWORKS, "getnetbyaddr", 398 __nsdefaultsrc, &retval, net, net_type); 399 if (rv == NS_SUCCESS) { 400 h_errno = NETDB_SUCCESS; 401 return retval; 402 } 403 return NULL; 404 } 405 406 /*ARGSUSED*/ 407 static int 408 _files_getnetbyname(void *cbrv, void *cbdata, va_list ap) 409 { 410 struct netent **retval = va_arg(ap, struct netent **); 411 const char *name = va_arg(ap, const char *); 412 413 struct netent *np; 414 char **cp; 415 416 setnetent(_net_stayopen); 417 while ((np = getnetent()) != NULL) { 418 if (strcasecmp(np->n_name, name) == 0) 419 break; 420 for (cp = np->n_aliases; *cp != 0; cp++) 421 if (strcasecmp(*cp, name) == 0) 422 goto found; 423 } 424 found: 425 if (!_net_stayopen) 426 endnetent(); 427 428 if (np != NULL) { 429 *retval = np; 430 return NS_SUCCESS; 431 } else { 432 h_errno = HOST_NOT_FOUND; 433 return NS_NOTFOUND; 434 } 435 } 436 437 /*ARGSUSED*/ 438 static int 439 _dns_getnetbyname(void *cbrv, void *cbdata, va_list ap) 440 { 441 struct netent **retval = va_arg(ap, struct netent **); 442 const char *name = va_arg(ap, const char *); 443 444 int anslen; 445 querybuf *buf; 446 char qbuf[MAXDNAME]; 447 struct netent *np; 448 res_state res; 449 450 strlcpy(&qbuf[0], name, sizeof(qbuf)); 451 buf = malloc(sizeof(*buf)); 452 if (buf == NULL) { 453 h_errno = NETDB_INTERNAL; 454 return NS_NOTFOUND; 455 } 456 res = __res_get_state(); 457 if (res == NULL) { 458 free(buf); 459 return NS_NOTFOUND; 460 } 461 anslen = res_nsearch(res, qbuf, C_IN, T_PTR, buf->buf, 462 sizeof(buf->buf)); 463 if (anslen < 0) { 464 free(buf); 465 #ifdef DEBUG 466 if (res->options & RES_DEBUG) 467 printf("res_search failed\n"); 468 #endif 469 __res_put_state(res); 470 return NS_NOTFOUND; 471 } 472 __res_put_state(res); 473 np = getnetanswer(buf, anslen, BYNAME); 474 free(buf); 475 476 if (np != NULL) { 477 *retval = np; 478 return NS_SUCCESS; 479 } else { 480 h_errno = HOST_NOT_FOUND; 481 return NS_NOTFOUND; 482 } 483 } 484 485 struct netent * 486 getnetbyname(const char *name) 487 { 488 int rv; 489 struct netent *retval; 490 491 static const ns_dtab dtab[] = { 492 NS_FILES_CB(_files_getnetbyname, NULL) 493 { NSSRC_DNS, _dns_getnetbyname, NULL }, /* force -DHESIOD */ 494 NS_NIS_CB(_yp_getnetbyname, NULL) 495 NS_NULL_CB 496 }; 497 498 _DIAGASSERT(name != NULL); 499 500 retval = NULL; 501 h_errno = NETDB_INTERNAL; 502 rv = nsdispatch(NULL, dtab, NSDB_NETWORKS, "getnetbyname", 503 __nsdefaultsrc, &retval, name); 504 if (rv == NS_SUCCESS) { 505 h_errno = NETDB_SUCCESS; 506 return retval; 507 } 508 return NULL; 509 } 510 511 #ifdef YP 512 /*ARGSUSED*/ 513 static int 514 _yp_getnetbyaddr(void *cbrv, void *cb_data, va_list ap) 515 { 516 struct netent **retval = va_arg(ap, struct netent **); 517 uint32_t net = va_arg(ap, uint32_t); 518 int type = va_arg(ap, int); 519 520 struct netent *np; 521 char qbuf[MAXDNAME]; 522 unsigned int netbr[4]; 523 uint32_t net2; 524 int r; 525 526 if (type != AF_INET) 527 return NS_UNAVAIL; 528 529 if (!__ypdomain) { 530 if (_yp_check(&__ypdomain) == 0) 531 return NS_UNAVAIL; 532 } 533 np = NULL; 534 if (__ypcurrent) 535 free(__ypcurrent); 536 __ypcurrent = NULL; 537 for (r = 4, net2 = net; net2; net2 >>= 8) 538 netbr[--r] = (unsigned int)(net2 & 0xff); 539 switch (r) { 540 default: 541 return NS_UNAVAIL; 542 case 3: /* Class A */ 543 snprintf(qbuf, sizeof(qbuf), "%u", netbr[3]); 544 break; 545 case 2: /* Class B */ 546 snprintf(qbuf, sizeof(qbuf), "%u.%u", netbr[2], netbr[3]); 547 break; 548 case 1: /* Class C */ 549 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u", netbr[1], netbr[2], 550 netbr[3]); 551 break; 552 case 0: /* Class D - E */ 553 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u", netbr[0], netbr[1], 554 netbr[2], netbr[3]); 555 break; 556 } 557 r = yp_match(__ypdomain, "networks.byaddr", qbuf, (int)strlen(qbuf), 558 &__ypcurrent, &__ypcurrentlen); 559 if (r == 0) 560 np = _ypnetent(__ypcurrent); 561 562 if (np != NULL) { 563 *retval = np; 564 return NS_SUCCESS; 565 } else { 566 h_errno = HOST_NOT_FOUND; 567 return NS_NOTFOUND; 568 } 569 } 570 571 /*ARGSUSED*/ 572 static int 573 _yp_getnetbyname(void *cbrv, void *cbdata, va_list ap) 574 { 575 struct netent **retval = va_arg(ap, struct netent **); 576 const char *name = va_arg(ap, const char *); 577 578 struct netent *np; 579 int r; 580 581 if (!__ypdomain) { 582 if (_yp_check(&__ypdomain) == 0) 583 return NS_UNAVAIL; 584 } 585 np = NULL; 586 if (__ypcurrent) 587 free(__ypcurrent); 588 __ypcurrent = NULL; 589 r = yp_match(__ypdomain, "networks.byname", name, (int)strlen(name), 590 &__ypcurrent, &__ypcurrentlen); 591 if (r == 0) 592 np = _ypnetent(__ypcurrent); 593 594 if (np != NULL) { 595 *retval = np; 596 return NS_SUCCESS; 597 } else { 598 h_errno = HOST_NOT_FOUND; 599 return NS_NOTFOUND; 600 } 601 } 602 603 static struct netent * 604 _ypnetent(char *line) 605 { 606 char *cp, *p, **q; 607 608 _DIAGASSERT(line != NULL); 609 610 net_entry.n_name = line; 611 cp = strpbrk(line, " \t"); 612 if (cp == NULL) 613 return NULL; 614 *cp++ = '\0'; 615 while (*cp == ' ' || *cp == '\t') 616 cp++; 617 p = strpbrk(cp, " \t"); 618 if (p != NULL) 619 *p++ = '\0'; 620 net_entry.n_net = inet_network(cp); 621 #if (defined(__sparc__) && defined(_LP64)) || \ 622 defined(__alpha__) || \ 623 (defined(__i386__) && defined(_LP64)) || \ 624 (defined(__sh__) && defined(_LP64)) 625 net_entry.__n_pad0 = 0; 626 #endif 627 net_entry.n_addrtype = AF_INET; 628 q = net_entry.n_aliases = net_aliases; 629 if (p != NULL) { 630 cp = p; 631 while (cp && *cp) { 632 if (*cp == ' ' || *cp == '\t') { 633 cp++; 634 continue; 635 } 636 if (q < &net_aliases[MAXALIASES - 1]) 637 *q++ = cp; 638 cp = strpbrk(cp, " \t"); 639 if (cp != NULL) 640 *cp++ = '\0'; 641 } 642 } 643 *q = NULL; 644 645 return &net_entry; 646 } 647 #endif 648