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