1 /* $NetBSD: getnetnamadr.c,v 1.44 2015/10/26 19:41:19 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.44 2015/10/26 19:41:19 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 #define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \ 81 (ok)(nm) != 0) 82 #define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok) 83 #define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok) 84 85 86 extern int _net_stayopen; 87 88 #define BYADDR 0 89 #define BYNAME 1 90 #define MAXALIASES 35 91 92 #define MAXPACKET (64*1024) 93 94 typedef union { 95 HEADER hdr; 96 u_char buf[MAXPACKET]; 97 } querybuf; 98 99 typedef union { 100 long al; 101 char ac; 102 } align; 103 104 #ifdef YP 105 static char *__ypdomain; 106 static char *__ypcurrent; 107 static int __ypcurrentlen; 108 #endif 109 110 static struct netent net_entry; 111 static char *net_aliases[MAXALIASES]; 112 113 static int parse_reversed_addr(const char *, in_addr_t *); 114 static struct netent *getnetanswer(res_state, querybuf *, int, int); 115 static int _files_getnetbyaddr(void *, void *, va_list); 116 static int _files_getnetbyname(void *, void *, va_list); 117 static int _dns_getnetbyaddr(void *, void *, va_list); 118 static int _dns_getnetbyname(void *, void *, va_list); 119 #ifdef YP 120 static int _yp_getnetbyaddr(void *, void *, va_list); 121 static int _yp_getnetbyname(void *, void *, va_list); 122 static struct netent *_ypnetent(char *); 123 #endif 124 125 /* 126 * parse_reversed_addr -- 127 * parse str, which should be of the form 'd.c.b.a.IN-ADDR.ARPA' 128 * (a PTR as per RFC 1101) and convert into an in_addr_t of the 129 * address 'a.b.c.d'. 130 * returns 0 on success (storing in *result), or -1 on error. 131 */ 132 static int 133 parse_reversed_addr(const char *str, in_addr_t *result) 134 { 135 unsigned long octet[4]; 136 const char *sp; 137 char *ep; 138 int octidx; 139 140 sp = str; 141 /* find the four octets 'd.b.c.a.' */ 142 for (octidx = 0; octidx < 4; octidx++) { 143 /* ensure it's a number */ 144 if (!isdigit((unsigned char)*sp)) 145 return -1; 146 octet[octidx] = strtoul(sp, &ep, 10); 147 /* with a trailing '.' */ 148 if (*ep != '.') 149 return -1; 150 /* and is 0 <= octet <= 255 */ 151 if (octet[octidx] > 255) 152 return -1; 153 sp = ep + 1; 154 } 155 /* ensure trailer is correct */ 156 if (strcasecmp(sp, "IN-ADDR.ARPA") != 0) 157 return -1; 158 *result = 0; 159 /* build result from octets in reverse */ 160 for (octidx = 3; octidx >= 0; octidx--) { 161 *result <<= 8; 162 *result |= (in_addr_t)(octet[octidx] & 0xff); 163 } 164 return 0; 165 } 166 167 static struct netent * 168 getnetanswer(res_state res, querybuf *answer, int anslen, int net_i) 169 { 170 static char n_name[MAXDNAME]; 171 static char netbuf[PACKETSZ]; 172 173 HEADER *hp; 174 u_char *cp; 175 int n; 176 u_char *eom; 177 int type, class, ancount, qdcount, haveanswer; 178 char *in, *bp, **ap, *ep; 179 180 _DIAGASSERT(answer != NULL); 181 _DIAGASSERT(res != NULL); 182 183 /* 184 * find first satisfactory answer 185 * 186 * answer --> +------------+ ( MESSAGE ) 187 * | Header | 188 * +------------+ 189 * | Question | the question for the name server 190 * +------------+ 191 * | Answer | RRs answering the question 192 * +------------+ 193 * | Authority | RRs pointing toward an authority 194 * | Additional | RRs holding additional information 195 * +------------+ 196 */ 197 eom = answer->buf + anslen; 198 hp = &answer->hdr; 199 ancount = ntohs(hp->ancount); /* #/records in the answer section */ 200 qdcount = ntohs(hp->qdcount); /* #/entries in the question section */ 201 bp = netbuf; 202 ep = netbuf + sizeof(netbuf); 203 cp = answer->buf + HFIXEDSZ; 204 if (!qdcount) { 205 if (hp->aa) 206 h_errno = HOST_NOT_FOUND; 207 else 208 h_errno = TRY_AGAIN; 209 return NULL; 210 } 211 while (qdcount-- > 0) { 212 n = __dn_skipname(cp, eom); 213 if (n < 0 || (cp + n + QFIXEDSZ) > eom) { 214 h_errno = NO_RECOVERY; 215 return(NULL); 216 } 217 cp += n + QFIXEDSZ; 218 } 219 ap = net_aliases; 220 *ap = NULL; 221 net_entry.n_aliases = net_aliases; 222 haveanswer = 0; 223 n_name[0] = '\0'; 224 while (--ancount >= 0 && cp < eom) { 225 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); 226 if ((n < 0) || !maybe_dnok(res, bp)) 227 break; 228 cp += n; 229 (void)strlcpy(n_name, bp, sizeof(n_name)); 230 GETSHORT(type, cp); 231 GETSHORT(class, cp); 232 cp += INT32SZ; /* TTL */ 233 GETSHORT(n, cp); 234 if (class == C_IN && type == T_PTR) { 235 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); 236 if ((n < 0) || !maybe_hnok(res, bp)) { 237 cp += n; 238 return NULL; 239 } 240 cp += n; 241 *ap++ = bp; 242 bp += strlen(bp) + 1; 243 net_entry.n_addrtype = 244 (class == C_IN) ? AF_INET : AF_UNSPEC; 245 haveanswer++; 246 } 247 } 248 if (haveanswer) { 249 *ap = NULL; 250 switch (net_i) { 251 case BYADDR: 252 net_entry.n_name = *net_entry.n_aliases; 253 net_entry.n_net = 0L; 254 break; 255 case BYNAME: 256 ap = net_entry.n_aliases; 257 next_alias: 258 in = *ap++; 259 if (in == NULL) { 260 h_errno = HOST_NOT_FOUND; 261 return NULL; 262 } 263 net_entry.n_name = n_name; 264 if (parse_reversed_addr(in, &net_entry.n_net) == -1) 265 goto next_alias; 266 break; 267 } 268 net_entry.n_aliases++; 269 #if (defined(__sparc__) && defined(_LP64)) || \ 270 defined(__alpha__) || \ 271 (defined(__i386__) && defined(_LP64)) || \ 272 (defined(__sh__) && defined(_LP64)) 273 net_entry.__n_pad0 = 0; 274 #endif 275 return &net_entry; 276 } 277 h_errno = TRY_AGAIN; 278 return NULL; 279 } 280 281 /*ARGSUSED*/ 282 static int 283 _files_getnetbyaddr(void *cbrv, void *cbdata, va_list ap) 284 { 285 struct netent **retval = va_arg(ap, struct netent **); 286 uint32_t net = va_arg(ap, uint32_t); 287 int type = va_arg(ap, int); 288 289 struct netent *np; 290 291 setnetent(_net_stayopen); 292 while ((np = getnetent()) != NULL) 293 if (np->n_addrtype == type && np->n_net == net) 294 break; 295 if (!_net_stayopen) 296 endnetent(); 297 298 if (np != NULL) { 299 *retval = np; 300 return NS_SUCCESS; 301 } else { 302 h_errno = HOST_NOT_FOUND; 303 return NS_NOTFOUND; 304 } 305 } 306 307 /*ARGSUSED*/ 308 static int 309 _dns_getnetbyaddr(void *cbrv, void *cbdata, va_list ap) 310 { 311 struct netent **retval = va_arg(ap, struct netent **); 312 uint32_t net = va_arg(ap, uint32_t); 313 int type = va_arg(ap, int); 314 315 unsigned int netbr[4]; 316 int nn, anslen; 317 querybuf *buf; 318 char qbuf[MAXDNAME]; 319 uint32_t net2; 320 struct netent *np; 321 res_state res; 322 323 if (type != AF_INET) 324 return NS_UNAVAIL; 325 326 for (nn = 4, net2 = net; net2; net2 >>= 8) 327 netbr[--nn] = (unsigned int)(net2 & 0xff); 328 switch (nn) { 329 default: 330 return NS_UNAVAIL; 331 case 3: /* Class A */ 332 snprintf(qbuf, sizeof(qbuf), "0.0.0.%u.in-addr.arpa", netbr[3]); 333 break; 334 case 2: /* Class B */ 335 snprintf(qbuf, sizeof(qbuf), "0.0.%u.%u.in-addr.arpa", 336 netbr[3], netbr[2]); 337 break; 338 case 1: /* Class C */ 339 snprintf(qbuf, sizeof(qbuf), "0.%u.%u.%u.in-addr.arpa", 340 netbr[3], netbr[2], netbr[1]); 341 break; 342 case 0: /* Class D - E */ 343 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", 344 netbr[3], netbr[2], netbr[1], netbr[0]); 345 break; 346 } 347 buf = malloc(sizeof(*buf)); 348 if (buf == NULL) { 349 h_errno = NETDB_INTERNAL; 350 return NS_NOTFOUND; 351 } 352 res = __res_get_state(); 353 if (res == NULL) { 354 free(buf); 355 return NS_NOTFOUND; 356 } 357 anslen = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, 358 (int)sizeof(buf->buf)); 359 if (anslen < 0) { 360 free(buf); 361 #ifdef DEBUG 362 if (res->options & RES_DEBUG) 363 printf("res_query failed\n"); 364 #endif 365 __res_put_state(res); 366 return NS_NOTFOUND; 367 } 368 np = getnetanswer(res, buf, anslen, BYADDR); 369 __res_put_state(res); 370 free(buf); 371 if (np) { 372 /* maybe net should be unsigned? */ 373 uint32_t u_net = net; 374 375 /* Strip trailing zeros */ 376 while ((u_net & 0xff) == 0 && u_net != 0) 377 u_net >>= 8; 378 np->n_net = u_net; 379 } 380 381 if (np != NULL) { 382 *retval = np; 383 return NS_SUCCESS; 384 } else { 385 h_errno = HOST_NOT_FOUND; 386 return NS_NOTFOUND; 387 } 388 } 389 390 struct netent * 391 getnetbyaddr(uint32_t net, int net_type) 392 { 393 int rv; 394 struct netent *retval; 395 396 static const ns_dtab dtab[] = { 397 NS_FILES_CB(_files_getnetbyaddr, NULL) 398 { NSSRC_DNS, _dns_getnetbyaddr, NULL }, /* force -DHESIOD */ 399 NS_NIS_CB(_yp_getnetbyaddr, NULL) 400 NS_NULL_CB 401 }; 402 403 retval = NULL; 404 h_errno = NETDB_INTERNAL; 405 rv = nsdispatch(NULL, dtab, NSDB_NETWORKS, "getnetbyaddr", 406 __nsdefaultsrc, &retval, net, net_type); 407 if (rv == NS_SUCCESS) { 408 h_errno = NETDB_SUCCESS; 409 return retval; 410 } 411 return NULL; 412 } 413 414 /*ARGSUSED*/ 415 static int 416 _files_getnetbyname(void *cbrv, void *cbdata, va_list ap) 417 { 418 struct netent **retval = va_arg(ap, struct netent **); 419 const char *name = va_arg(ap, const char *); 420 421 struct netent *np; 422 char **cp; 423 424 setnetent(_net_stayopen); 425 while ((np = getnetent()) != NULL) { 426 if (strcasecmp(np->n_name, name) == 0) 427 break; 428 for (cp = np->n_aliases; *cp != 0; cp++) 429 if (strcasecmp(*cp, name) == 0) 430 goto found; 431 } 432 found: 433 if (!_net_stayopen) 434 endnetent(); 435 436 if (np != NULL) { 437 *retval = np; 438 return NS_SUCCESS; 439 } else { 440 h_errno = HOST_NOT_FOUND; 441 return NS_NOTFOUND; 442 } 443 } 444 445 /*ARGSUSED*/ 446 static int 447 _dns_getnetbyname(void *cbrv, void *cbdata, va_list ap) 448 { 449 struct netent **retval = va_arg(ap, struct netent **); 450 const char *name = va_arg(ap, const char *); 451 452 int anslen; 453 querybuf *buf; 454 char qbuf[MAXDNAME]; 455 struct netent *np; 456 res_state res; 457 458 strlcpy(&qbuf[0], name, sizeof(qbuf)); 459 buf = malloc(sizeof(*buf)); 460 if (buf == NULL) { 461 h_errno = NETDB_INTERNAL; 462 return NS_NOTFOUND; 463 } 464 res = __res_get_state(); 465 if (res == NULL) { 466 free(buf); 467 return NS_NOTFOUND; 468 } 469 anslen = res_nsearch(res, qbuf, C_IN, T_PTR, buf->buf, 470 (int)sizeof(buf->buf)); 471 if (anslen < 0) { 472 free(buf); 473 #ifdef DEBUG 474 if (res->options & RES_DEBUG) 475 printf("res_search failed\n"); 476 #endif 477 __res_put_state(res); 478 return NS_NOTFOUND; 479 } 480 np = getnetanswer(res, buf, anslen, BYNAME); 481 __res_put_state(res); 482 free(buf); 483 484 if (np != NULL) { 485 *retval = np; 486 return NS_SUCCESS; 487 } else { 488 h_errno = HOST_NOT_FOUND; 489 return NS_NOTFOUND; 490 } 491 } 492 493 struct netent * 494 getnetbyname(const char *name) 495 { 496 int rv; 497 struct netent *retval; 498 499 static const ns_dtab dtab[] = { 500 NS_FILES_CB(_files_getnetbyname, NULL) 501 { NSSRC_DNS, _dns_getnetbyname, NULL }, /* force -DHESIOD */ 502 NS_NIS_CB(_yp_getnetbyname, NULL) 503 NS_NULL_CB 504 }; 505 506 _DIAGASSERT(name != NULL); 507 508 retval = NULL; 509 h_errno = NETDB_INTERNAL; 510 rv = nsdispatch(NULL, dtab, NSDB_NETWORKS, "getnetbyname", 511 __nsdefaultsrc, &retval, name); 512 if (rv == NS_SUCCESS) { 513 h_errno = NETDB_SUCCESS; 514 return retval; 515 } 516 return NULL; 517 } 518 519 #ifdef YP 520 /*ARGSUSED*/ 521 static int 522 _yp_getnetbyaddr(void *cbrv, void *cb_data, va_list ap) 523 { 524 struct netent **retval = va_arg(ap, struct netent **); 525 uint32_t net = va_arg(ap, uint32_t); 526 int type = va_arg(ap, int); 527 528 struct netent *np; 529 char qbuf[MAXDNAME]; 530 unsigned int netbr[4]; 531 uint32_t net2; 532 int r; 533 534 if (type != AF_INET) 535 return NS_UNAVAIL; 536 537 if (!__ypdomain) { 538 if (_yp_check(&__ypdomain) == 0) 539 return NS_UNAVAIL; 540 } 541 np = NULL; 542 if (__ypcurrent) 543 free(__ypcurrent); 544 __ypcurrent = NULL; 545 for (r = 4, net2 = net; net2; net2 >>= 8) 546 netbr[--r] = (unsigned int)(net2 & 0xff); 547 switch (r) { 548 default: 549 return NS_UNAVAIL; 550 case 3: /* Class A */ 551 snprintf(qbuf, sizeof(qbuf), "%u", netbr[3]); 552 break; 553 case 2: /* Class B */ 554 snprintf(qbuf, sizeof(qbuf), "%u.%u", netbr[2], netbr[3]); 555 break; 556 case 1: /* Class C */ 557 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u", netbr[1], netbr[2], 558 netbr[3]); 559 break; 560 case 0: /* Class D - E */ 561 snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u", netbr[0], netbr[1], 562 netbr[2], netbr[3]); 563 break; 564 } 565 r = yp_match(__ypdomain, "networks.byaddr", qbuf, (int)strlen(qbuf), 566 &__ypcurrent, &__ypcurrentlen); 567 if (r == 0) 568 np = _ypnetent(__ypcurrent); 569 570 if (np != NULL) { 571 *retval = np; 572 return NS_SUCCESS; 573 } else { 574 h_errno = HOST_NOT_FOUND; 575 return NS_NOTFOUND; 576 } 577 } 578 579 /*ARGSUSED*/ 580 static int 581 _yp_getnetbyname(void *cbrv, void *cbdata, va_list ap) 582 { 583 struct netent **retval = va_arg(ap, struct netent **); 584 const char *name = va_arg(ap, const char *); 585 586 struct netent *np; 587 int r; 588 589 if (!__ypdomain) { 590 if (_yp_check(&__ypdomain) == 0) 591 return NS_UNAVAIL; 592 } 593 np = NULL; 594 if (__ypcurrent) 595 free(__ypcurrent); 596 __ypcurrent = NULL; 597 r = yp_match(__ypdomain, "networks.byname", name, (int)strlen(name), 598 &__ypcurrent, &__ypcurrentlen); 599 if (r == 0) 600 np = _ypnetent(__ypcurrent); 601 602 if (np != NULL) { 603 *retval = np; 604 return NS_SUCCESS; 605 } else { 606 h_errno = HOST_NOT_FOUND; 607 return NS_NOTFOUND; 608 } 609 } 610 611 static struct netent * 612 _ypnetent(char *line) 613 { 614 char *cp, *p, **q; 615 616 _DIAGASSERT(line != NULL); 617 618 net_entry.n_name = line; 619 cp = strpbrk(line, " \t"); 620 if (cp == NULL) 621 return NULL; 622 *cp++ = '\0'; 623 while (*cp == ' ' || *cp == '\t') 624 cp++; 625 p = strpbrk(cp, " \t"); 626 if (p != NULL) 627 *p++ = '\0'; 628 net_entry.n_net = inet_network(cp); 629 #if (defined(__sparc__) && defined(_LP64)) || \ 630 defined(__alpha__) || \ 631 (defined(__i386__) && defined(_LP64)) || \ 632 (defined(__sh__) && defined(_LP64)) 633 net_entry.__n_pad0 = 0; 634 #endif 635 net_entry.n_addrtype = AF_INET; 636 q = net_entry.n_aliases = net_aliases; 637 if (p != NULL) { 638 cp = p; 639 while (cp && *cp) { 640 if (*cp == ' ' || *cp == '\t') { 641 cp++; 642 continue; 643 } 644 if (q < &net_aliases[MAXALIASES - 1]) 645 *q++ = cp; 646 cp = strpbrk(cp, " \t"); 647 if (cp != NULL) 648 *cp++ = '\0'; 649 } 650 } 651 *q = NULL; 652 653 return &net_entry; 654 } 655 #endif 656