1 /* $NetBSD: getnetnamadr.c,v 1.42 2012/03/13 21:13:41 christos 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.42 2012/03/13 21:13:41 christos 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 |= (in_addr_t)(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, (int)(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, (int)(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, 351 (int)sizeof(buf->buf)); 352 if (anslen < 0) { 353 free(buf); 354 #ifdef DEBUG 355 if (res->options & RES_DEBUG) 356 printf("res_query failed\n"); 357 #endif 358 __res_put_state(res); 359 return NS_NOTFOUND; 360 } 361 __res_put_state(res); 362 np = getnetanswer(buf, anslen, BYADDR); 363 free(buf); 364 if (np) { 365 /* maybe net should be unsigned? */ 366 uint32_t u_net = net; 367 368 /* Strip trailing zeros */ 369 while ((u_net & 0xff) == 0 && u_net != 0) 370 u_net >>= 8; 371 np->n_net = u_net; 372 } 373 374 if (np != NULL) { 375 *retval = np; 376 return NS_SUCCESS; 377 } else { 378 h_errno = HOST_NOT_FOUND; 379 return NS_NOTFOUND; 380 } 381 } 382 383 struct netent * 384 getnetbyaddr(uint32_t net, int net_type) 385 { 386 int rv; 387 struct netent *retval; 388 389 static const ns_dtab dtab[] = { 390 NS_FILES_CB(_files_getnetbyaddr, NULL) 391 { NSSRC_DNS, _dns_getnetbyaddr, NULL }, /* force -DHESIOD */ 392 NS_NIS_CB(_yp_getnetbyaddr, NULL) 393 NS_NULL_CB 394 }; 395 396 retval = NULL; 397 h_errno = NETDB_INTERNAL; 398 rv = nsdispatch(NULL, dtab, NSDB_NETWORKS, "getnetbyaddr", 399 __nsdefaultsrc, &retval, net, net_type); 400 if (rv == NS_SUCCESS) { 401 h_errno = NETDB_SUCCESS; 402 return retval; 403 } 404 return NULL; 405 } 406 407 /*ARGSUSED*/ 408 static int 409 _files_getnetbyname(void *cbrv, void *cbdata, va_list ap) 410 { 411 struct netent **retval = va_arg(ap, struct netent **); 412 const char *name = va_arg(ap, const char *); 413 414 struct netent *np; 415 char **cp; 416 417 setnetent(_net_stayopen); 418 while ((np = getnetent()) != NULL) { 419 if (strcasecmp(np->n_name, name) == 0) 420 break; 421 for (cp = np->n_aliases; *cp != 0; cp++) 422 if (strcasecmp(*cp, name) == 0) 423 goto found; 424 } 425 found: 426 if (!_net_stayopen) 427 endnetent(); 428 429 if (np != NULL) { 430 *retval = np; 431 return NS_SUCCESS; 432 } else { 433 h_errno = HOST_NOT_FOUND; 434 return NS_NOTFOUND; 435 } 436 } 437 438 /*ARGSUSED*/ 439 static int 440 _dns_getnetbyname(void *cbrv, void *cbdata, va_list ap) 441 { 442 struct netent **retval = va_arg(ap, struct netent **); 443 const char *name = va_arg(ap, const char *); 444 445 int anslen; 446 querybuf *buf; 447 char qbuf[MAXDNAME]; 448 struct netent *np; 449 res_state res; 450 451 strlcpy(&qbuf[0], name, sizeof(qbuf)); 452 buf = malloc(sizeof(*buf)); 453 if (buf == NULL) { 454 h_errno = NETDB_INTERNAL; 455 return NS_NOTFOUND; 456 } 457 res = __res_get_state(); 458 if (res == NULL) { 459 free(buf); 460 return NS_NOTFOUND; 461 } 462 anslen = res_nsearch(res, qbuf, C_IN, T_PTR, buf->buf, 463 (int)sizeof(buf->buf)); 464 if (anslen < 0) { 465 free(buf); 466 #ifdef DEBUG 467 if (res->options & RES_DEBUG) 468 printf("res_search failed\n"); 469 #endif 470 __res_put_state(res); 471 return NS_NOTFOUND; 472 } 473 __res_put_state(res); 474 np = getnetanswer(buf, anslen, BYNAME); 475 free(buf); 476 477 if (np != NULL) { 478 *retval = np; 479 return NS_SUCCESS; 480 } else { 481 h_errno = HOST_NOT_FOUND; 482 return NS_NOTFOUND; 483 } 484 } 485 486 struct netent * 487 getnetbyname(const char *name) 488 { 489 int rv; 490 struct netent *retval; 491 492 static const ns_dtab dtab[] = { 493 NS_FILES_CB(_files_getnetbyname, NULL) 494 { NSSRC_DNS, _dns_getnetbyname, NULL }, /* force -DHESIOD */ 495 NS_NIS_CB(_yp_getnetbyname, NULL) 496 NS_NULL_CB 497 }; 498 499 _DIAGASSERT(name != NULL); 500 501 retval = NULL; 502 h_errno = NETDB_INTERNAL; 503 rv = nsdispatch(NULL, dtab, NSDB_NETWORKS, "getnetbyname", 504 __nsdefaultsrc, &retval, name); 505 if (rv == NS_SUCCESS) { 506 h_errno = NETDB_SUCCESS; 507 return retval; 508 } 509 return NULL; 510 } 511 512 #ifdef YP 513 /*ARGSUSED*/ 514 static int 515 _yp_getnetbyaddr(void *cbrv, void *cb_data, va_list ap) 516 { 517 struct netent **retval = va_arg(ap, struct netent **); 518 uint32_t net = va_arg(ap, uint32_t); 519 int type = va_arg(ap, int); 520 521 struct netent *np; 522 char qbuf[MAXDNAME]; 523 unsigned int netbr[4]; 524 uint32_t net2; 525 int r; 526 527 if (type != AF_INET) 528 return NS_UNAVAIL; 529 530 if (!__ypdomain) { 531 if (_yp_check(&__ypdomain) == 0) 532 return NS_UNAVAIL; 533 } 534 np = NULL; 535 if (__ypcurrent) 536 free(__ypcurrent); 537 __ypcurrent = NULL; 538 for (r = 4, net2 = net; net2; net2 >>= 8) 539 netbr[--r] = (unsigned int)(net2 & 0xff); 540 switch (r) { 541 default: 542 return NS_UNAVAIL; 543 case 3: /* Class A */ 544 snprintf(qbuf, sizeof(qbuf), "%u", netbr[3]); 545 break; 546 case 2: /* Class B */ 547 snprintf(qbuf, sizeof(qbuf), "%u.%u", netbr[2], netbr[3]); 548 break; 549 case 1: /* Class C */ 550 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u", netbr[1], netbr[2], 551 netbr[3]); 552 break; 553 case 0: /* Class D - E */ 554 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u", netbr[0], netbr[1], 555 netbr[2], netbr[3]); 556 break; 557 } 558 r = yp_match(__ypdomain, "networks.byaddr", qbuf, (int)strlen(qbuf), 559 &__ypcurrent, &__ypcurrentlen); 560 if (r == 0) 561 np = _ypnetent(__ypcurrent); 562 563 if (np != NULL) { 564 *retval = np; 565 return NS_SUCCESS; 566 } else { 567 h_errno = HOST_NOT_FOUND; 568 return NS_NOTFOUND; 569 } 570 } 571 572 /*ARGSUSED*/ 573 static int 574 _yp_getnetbyname(void *cbrv, void *cbdata, va_list ap) 575 { 576 struct netent **retval = va_arg(ap, struct netent **); 577 const char *name = va_arg(ap, const char *); 578 579 struct netent *np; 580 int r; 581 582 if (!__ypdomain) { 583 if (_yp_check(&__ypdomain) == 0) 584 return NS_UNAVAIL; 585 } 586 np = NULL; 587 if (__ypcurrent) 588 free(__ypcurrent); 589 __ypcurrent = NULL; 590 r = yp_match(__ypdomain, "networks.byname", name, (int)strlen(name), 591 &__ypcurrent, &__ypcurrentlen); 592 if (r == 0) 593 np = _ypnetent(__ypcurrent); 594 595 if (np != NULL) { 596 *retval = np; 597 return NS_SUCCESS; 598 } else { 599 h_errno = HOST_NOT_FOUND; 600 return NS_NOTFOUND; 601 } 602 } 603 604 static struct netent * 605 _ypnetent(char *line) 606 { 607 char *cp, *p, **q; 608 609 _DIAGASSERT(line != NULL); 610 611 net_entry.n_name = line; 612 cp = strpbrk(line, " \t"); 613 if (cp == NULL) 614 return NULL; 615 *cp++ = '\0'; 616 while (*cp == ' ' || *cp == '\t') 617 cp++; 618 p = strpbrk(cp, " \t"); 619 if (p != NULL) 620 *p++ = '\0'; 621 net_entry.n_net = inet_network(cp); 622 #if (defined(__sparc__) && defined(_LP64)) || \ 623 defined(__alpha__) || \ 624 (defined(__i386__) && defined(_LP64)) || \ 625 (defined(__sh__) && defined(_LP64)) 626 net_entry.__n_pad0 = 0; 627 #endif 628 net_entry.n_addrtype = AF_INET; 629 q = net_entry.n_aliases = net_aliases; 630 if (p != NULL) { 631 cp = p; 632 while (cp && *cp) { 633 if (*cp == ' ' || *cp == '\t') { 634 cp++; 635 continue; 636 } 637 if (q < &net_aliases[MAXALIASES - 1]) 638 *q++ = cp; 639 cp = strpbrk(cp, " \t"); 640 if (cp != NULL) 641 *cp++ = '\0'; 642 } 643 } 644 *q = NULL; 645 646 return &net_entry; 647 } 648 #endif 649