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