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