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