1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6
7 /*
8 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1996-1999 by Internet Software Consortium.
10 *
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24 /* Imports */
25
26 #include "port_before.h"
27
28 #if !defined(__BIND_NOSTATIC)
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #include <netinet/in.h>
35 #include <net/if.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
38
39 #include <ctype.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #include <netdb.h>
43 #include <resolv.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include <irs.h>
49 #include <isc/memcluster.h>
50
51 #include "port_after.h"
52
53 #include "irs_p.h"
54 #include "irs_data.h"
55
56 /* Definitions */
57
58 struct pvt {
59 char * aliases[1];
60 char * addrs[2];
61 char addr[NS_IN6ADDRSZ];
62 char name[NS_MAXDNAME + 1];
63 struct hostent host;
64 };
65
66 /* Forward */
67
68 static struct net_data *init(void);
69 static void freepvt(struct net_data *);
70 static struct hostent *fakeaddr(const char *, int, struct net_data *);
71
72 #ifdef SUNW_OVERRIDE_RETRY
73 extern int __res_retry(int);
74 extern int __res_retry_reset(void);
75 #endif /* SUNW_OVERRIDE_RETRY */
76
77
78 /* Public */
79
80 struct hostent *
gethostbyname(const char * name)81 gethostbyname(const char *name) {
82 struct net_data *net_data = init();
83
84 return (gethostbyname_p(name, net_data));
85 }
86
87 struct hostent *
gethostbyname2(const char * name,int af)88 gethostbyname2(const char *name, int af) {
89 struct net_data *net_data = init();
90
91 return (gethostbyname2_p(name, af, net_data));
92 }
93
94 struct hostent *
gethostbyaddr(const char * addr,int len,int af)95 gethostbyaddr(const char *addr, int len, int af) {
96 struct net_data *net_data = init();
97
98 return (gethostbyaddr_p(addr, len, af, net_data));
99 }
100
101 struct hostent *
gethostent()102 gethostent() {
103 struct net_data *net_data = init();
104
105 return (gethostent_p(net_data));
106 }
107
108 void
sethostent(int stayopen)109 sethostent(int stayopen) {
110 struct net_data *net_data = init();
111 sethostent_p(stayopen, net_data);
112 }
113
114
115 void
endhostent()116 endhostent() {
117 struct net_data *net_data = init();
118 endhostent_p(net_data);
119 }
120
121 /* Shared private. */
122
123 struct hostent *
gethostbyname_p(const char * name,struct net_data * net_data)124 gethostbyname_p(const char *name, struct net_data *net_data) {
125 struct hostent *hp;
126
127 if (!net_data)
128 return (NULL);
129
130 if (net_data->res->options & RES_USE_INET6) {
131 hp = gethostbyname2_p(name, AF_INET6, net_data);
132 if (hp)
133 return (hp);
134 }
135 return (gethostbyname2_p(name, AF_INET, net_data));
136 }
137
138 struct hostent *
gethostbyname2_p(const char * name,int af,struct net_data * net_data)139 gethostbyname2_p(const char *name, int af, struct net_data *net_data) {
140 struct irs_ho *ho;
141 char tmp[NS_MAXDNAME];
142 struct hostent *hp;
143 const char *cp;
144 char **hap;
145
146 if (!net_data || !(ho = net_data->ho))
147 return (NULL);
148 if (net_data->ho_stayopen && net_data->ho_last &&
149 net_data->ho_last->h_addrtype == af) {
150 if (ns_samename(name, net_data->ho_last->h_name) == 1)
151 return (net_data->ho_last);
152 for (hap = net_data->ho_last->h_aliases; hap && *hap; hap++)
153 if (ns_samename(name, *hap) == 1)
154 return (net_data->ho_last);
155 }
156 if (!strchr(name, '.') && (cp = res_hostalias(net_data->res, name,
157 tmp, sizeof tmp)))
158 name = cp;
159 if ((hp = fakeaddr(name, af, net_data)) != NULL)
160 return (hp);
161 #ifdef SUNW_OVERRIDE_RETRY
162 net_data->res->retry = __res_retry(net_data->res->retry);
163 #endif /* SUNW_OVERRIDE_RETRY */
164 net_data->ho_last = (*ho->byname2)(ho, name, af);
165 #ifdef SUNW_OVERRIDE_RETRY
166 net_data->res->retry = __res_retry_reset();
167 #endif /* SUNW_OVERRIDE_RETRY */
168 if (!net_data->ho_stayopen)
169 endhostent();
170 return (net_data->ho_last);
171 }
172
173 struct hostent *
gethostbyaddr_p(const char * addr,int len,int af,struct net_data * net_data)174 gethostbyaddr_p(const char *addr, int len, int af, struct net_data *net_data) {
175 struct irs_ho *ho;
176 char **hap;
177
178 if (!net_data || !(ho = net_data->ho))
179 return (NULL);
180 if (net_data->ho_stayopen && net_data->ho_last &&
181 net_data->ho_last->h_length == len)
182 for (hap = net_data->ho_last->h_addr_list;
183 hap && *hap;
184 hap++)
185 if (!memcmp(addr, *hap, len))
186 return (net_data->ho_last);
187 net_data->ho_last = (*ho->byaddr)(ho, addr, len, af);
188 if (!net_data->ho_stayopen)
189 endhostent();
190 return (net_data->ho_last);
191 }
192
193
194 struct hostent *
gethostent_p(struct net_data * net_data)195 gethostent_p(struct net_data *net_data) {
196 struct irs_ho *ho;
197 struct hostent *hp;
198
199 if (!net_data || !(ho = net_data->ho))
200 return (NULL);
201 while ((hp = (*ho->next)(ho)) != NULL &&
202 hp->h_addrtype == AF_INET6 &&
203 (net_data->res->options & RES_USE_INET6) == 0U)
204 continue;
205 net_data->ho_last = hp;
206 return (net_data->ho_last);
207 }
208
209
210 void
sethostent_p(int stayopen,struct net_data * net_data)211 sethostent_p(int stayopen, struct net_data *net_data) {
212 struct irs_ho *ho;
213
214 if (!net_data || !(ho = net_data->ho))
215 return;
216 freepvt(net_data);
217 (*ho->rewind)(ho);
218 net_data->ho_stayopen = (stayopen != 0);
219 if (stayopen == 0)
220 net_data_minimize(net_data);
221 }
222
223 void
endhostent_p(struct net_data * net_data)224 endhostent_p(struct net_data *net_data) {
225 struct irs_ho *ho;
226
227 if ((net_data != NULL) && ((ho = net_data->ho) != NULL))
228 (*ho->minimize)(ho);
229 }
230
231 #ifndef IN6_IS_ADDR_V4COMPAT
232 static const unsigned char in6addr_compat[12] = {
233 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
234 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
235 ((x)->s6_addr[12] != 0 || \
236 (x)->s6_addr[13] != 0 || \
237 (x)->s6_addr[14] != 0 || \
238 ((x)->s6_addr[15] != 0 && \
239 (x)->s6_addr[15] != 1)))
240 #endif
241 #ifndef IN6_IS_ADDR_V4MAPPED
242 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
243 #endif
244
245 static const unsigned char in6addr_mapped[12] = {
246 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
247
248 static int scan_interfaces(int *, int *);
249 static struct hostent *copyandmerge(struct hostent *, struct hostent *, int, int *);
250
251 /*%
252 * Public functions
253 */
254
255 /*%
256 * AI_V4MAPPED + AF_INET6
257 * If no IPv6 address then a query for IPv4 and map returned values.
258 *
259 * AI_ALL + AI_V4MAPPED + AF_INET6
260 * Return IPv6 and IPv4 mapped.
261 *
262 * AI_ADDRCONFIG
263 * Only return IPv6 / IPv4 address if there is an interface of that
264 * type active.
265 */
266
267 struct hostent *
getipnodebyname(const char * name,int af,int flags,int * error_num)268 getipnodebyname(const char *name, int af, int flags, int *error_num) {
269 int have_v4 = 1, have_v6 = 1;
270 struct in_addr in4;
271 struct in6_addr in6;
272 struct hostent he, *he1 = NULL, *he2 = NULL, *he3;
273 int v4 = 0, v6 = 0;
274 struct net_data *net_data = init();
275 u_long options;
276 int tmp_err;
277
278 if (net_data == NULL) {
279 *error_num = NO_RECOVERY;
280 return (NULL);
281 }
282
283 /* If we care about active interfaces then check. */
284 if ((flags & AI_ADDRCONFIG) != 0)
285 if (scan_interfaces(&have_v4, &have_v6) == -1) {
286 *error_num = NO_RECOVERY;
287 return (NULL);
288 }
289
290 /* Check for literal address. */
291 if ((v4 = inet_pton(AF_INET, name, &in4)) != 1)
292 v6 = inet_pton(AF_INET6, name, &in6);
293
294 /* Impossible combination? */
295
296 if ((af == AF_INET6 && (flags & AI_V4MAPPED) == 0 && v4 == 1) ||
297 (af == AF_INET && v6 == 1) ||
298 (have_v4 == 0 && v4 == 1) ||
299 (have_v6 == 0 && v6 == 1) ||
300 (have_v4 == 0 && af == AF_INET) ||
301 (have_v6 == 0 && af == AF_INET6)) {
302 *error_num = HOST_NOT_FOUND;
303 return (NULL);
304 }
305
306 /* Literal address? */
307 if (v4 == 1 || v6 == 1) {
308 char *addr_list[2];
309 char *aliases[1];
310
311 DE_CONST(name, he.h_name);
312 he.h_addr_list = addr_list;
313 he.h_addr_list[0] = (v4 == 1) ? (char *)&in4 : (char *)&in6;
314 he.h_addr_list[1] = NULL;
315 he.h_aliases = aliases;
316 he.h_aliases[0] = NULL;
317 he.h_length = (v4 == 1) ? INADDRSZ : IN6ADDRSZ;
318 he.h_addrtype = (v4 == 1) ? AF_INET : AF_INET6;
319 return (copyandmerge(&he, NULL, af, error_num));
320 }
321
322 options = net_data->res->options;
323 net_data->res->options &= ~RES_USE_INET6;
324
325 tmp_err = NO_RECOVERY;
326 if (have_v6 && af == AF_INET6) {
327 he2 = gethostbyname2_p(name, AF_INET6, net_data);
328 if (he2 != NULL) {
329 he1 = copyandmerge(he2, NULL, af, error_num);
330 if (he1 == NULL)
331 return (NULL);
332 he2 = NULL;
333 } else {
334 tmp_err = net_data->res->res_h_errno;
335 }
336 }
337
338 if (have_v4 &&
339 ((af == AF_INET) ||
340 (af == AF_INET6 && (flags & AI_V4MAPPED) != 0 &&
341 (he1 == NULL || (flags & AI_ALL) != 0)))) {
342 he2 = gethostbyname2_p(name, AF_INET, net_data);
343 if (he1 == NULL && he2 == NULL) {
344 *error_num = net_data->res->res_h_errno;
345 return (NULL);
346 }
347 } else
348 *error_num = tmp_err;
349
350 net_data->res->options = options;
351
352 he3 = copyandmerge(he1, he2, af, error_num);
353
354 if (he1 != NULL)
355 freehostent(he1);
356 return (he3);
357 }
358
359 struct hostent *
getipnodebyaddr(const void * src,size_t len,int af,int * error_num)360 getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
361 struct hostent *he1, *he2;
362 struct net_data *net_data = init();
363
364 /* Sanity Checks. */
365 #ifdef ORIGINAL_ISC_CODE
366 if (src == NULL) {
367 #else
368 /* this change was added circa May 2009, but not in ISC libbind 6.0 */
369 if (src == NULL|| net_data == NULL) {
370 #endif /* ORIGINAL_ISC_CODE */
371 *error_num = NO_RECOVERY;
372 return (NULL);
373 }
374
375 switch (af) {
376 case AF_INET:
377 if (len != (size_t)INADDRSZ) {
378 *error_num = NO_RECOVERY;
379 return (NULL);
380 }
381 break;
382 case AF_INET6:
383 if (len != (size_t)IN6ADDRSZ) {
384 *error_num = NO_RECOVERY;
385 return (NULL);
386 }
387 break;
388 default:
389 *error_num = NO_RECOVERY;
390 return (NULL);
391 }
392
393 /*
394 * Lookup IPv4 and IPv4 mapped/compatible addresses
395 */
396 if ((af == AF_INET6 &&
397 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
398 (af == AF_INET6 &&
399 IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
400 (af == AF_INET)) {
401 const char *cp = src;
402
403 if (af == AF_INET6)
404 cp += 12;
405 he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
406 if (he1 == NULL) {
407 *error_num = net_data->res->res_h_errno;
408 return (NULL);
409 }
410 he2 = copyandmerge(he1, NULL, af, error_num);
411 if (he2 == NULL)
412 return (NULL);
413 /*
414 * Restore original address if mapped/compatible.
415 */
416 if (af == AF_INET6)
417 memcpy(he1->h_addr, src, len);
418 return (he2);
419 }
420
421 /*
422 * Lookup IPv6 address.
423 */
424 if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
425 *error_num = HOST_NOT_FOUND;
426 return (NULL);
427 }
428
429 he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
430 if (he1 == NULL) {
431 *error_num = net_data->res->res_h_errno;
432 return (NULL);
433 }
434 return (copyandmerge(he1, NULL, af, error_num));
435 }
436
437 void
438 freehostent(struct hostent *he) {
439 char **cpp;
440 int names = 1;
441 int addresses = 1;
442
443 memput(he->h_name, strlen(he->h_name) + 1);
444
445 cpp = he->h_addr_list;
446 while (*cpp != NULL) {
447 memput(*cpp, (he->h_addrtype == AF_INET) ?
448 INADDRSZ : IN6ADDRSZ);
449 *cpp = NULL;
450 cpp++;
451 addresses++;
452 }
453
454 cpp = he->h_aliases;
455 while (*cpp != NULL) {
456 memput(*cpp, strlen(*cpp) + 1);
457 cpp++;
458 names++;
459 }
460
461 memput(he->h_aliases, sizeof(char *) * (names));
462 memput(he->h_addr_list, sizeof(char *) * (addresses));
463 memput(he, sizeof *he);
464 }
465
466 /*%
467 * Private
468 */
469
470 /*%
471 * Scan the interface table and set have_v4 and have_v6 depending
472 * upon whether there are IPv4 and IPv6 interface addresses.
473 *
474 * Returns:
475 * 0 on success
476 * -1 on failure.
477 */
478
479 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
480 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
481
482 #ifdef __hpux
483 #define lifc_len iflc_len
484 #define lifc_buf iflc_buf
485 #define lifc_req iflc_req
486 #define LIFCONF if_laddrconf
487 #else
488 #define SETFAMILYFLAGS
489 #define LIFCONF lifconf
490 #endif
491
492 #ifdef __hpux
493 #define lifr_addr iflr_addr
494 #define lifr_name iflr_name
495 #define lifr_dstaddr iflr_dstaddr
496 #define lifr_flags iflr_flags
497 #define ss_family sa_family
498 #define LIFREQ if_laddrreq
499 #else
500 #define LIFREQ lifreq
501 #endif
502
503 static void
504 scan_interfaces6(int *have_v4, int *have_v6) {
505 struct LIFCONF lifc;
506 struct LIFREQ lifreq;
507 struct in_addr in4;
508 struct in6_addr in6;
509 char *buf = NULL, *cp, *cplim;
510 static unsigned int bufsiz = 4095;
511 int s, cpsize, n;
512
513 /* Get interface list from system. */
514 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
515 goto cleanup;
516
517 /*
518 * Grow buffer until large enough to contain all interface
519 * descriptions.
520 */
521 for (;;) {
522 buf = memget(bufsiz);
523 if (buf == NULL)
524 goto cleanup;
525 #ifdef SETFAMILYFLAGS
526 lifc.lifc_family = AF_UNSPEC; /*%< request all families */
527 lifc.lifc_flags = 0;
528 #endif
529 lifc.lifc_len = bufsiz;
530 lifc.lifc_buf = buf;
531 if ((n = ioctl(s, SIOCGLIFCONF, (char *)&lifc)) != -1) {
532 /*
533 * Some OS's just return what will fit rather
534 * than set EINVAL if the buffer is too small
535 * to fit all the interfaces in. If
536 * lifc.lifc_len is too near to the end of the
537 * buffer we will grow it just in case and
538 * retry.
539 */
540 if (lifc.lifc_len + 2 * sizeof(lifreq) < bufsiz)
541 break;
542 }
543 if ((n == -1) && errno != EINVAL)
544 goto cleanup;
545
546 if (bufsiz > 1000000)
547 goto cleanup;
548
549 memput(buf, bufsiz);
550 bufsiz += 4096;
551 }
552
553 /* Parse system's interface list. */
554 cplim = buf + lifc.lifc_len; /*%< skip over if's with big ifr_addr's */
555 for (cp = buf;
556 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
557 cp += cpsize) {
558 memcpy(&lifreq, cp, sizeof lifreq);
559 #ifdef HAVE_SA_LEN
560 #ifdef FIX_ZERO_SA_LEN
561 if (lifreq.lifr_addr.sa_len == 0)
562 lifreq.lifr_addr.sa_len = 16;
563 #endif
564 #ifdef HAVE_MINIMUM_IFREQ
565 cpsize = sizeof lifreq;
566 if (lifreq.lifr_addr.sa_len > sizeof (struct sockaddr))
567 cpsize += (int)lifreq.lifr_addr.sa_len -
568 (int)(sizeof (struct sockaddr));
569 #else
570 cpsize = sizeof lifreq.lifr_name + lifreq.lifr_addr.sa_len;
571 #endif /* HAVE_MINIMUM_IFREQ */
572 #elif defined SIOCGIFCONF_ADDR
573 cpsize = sizeof lifreq;
574 #else
575 cpsize = sizeof lifreq.lifr_name;
576 /* XXX maybe this should be a hard error? */
577 if (ioctl(s, SIOCGLIFADDR, (char *)&lifreq) < 0)
578 continue;
579 #endif
580 switch (lifreq.lifr_addr.ss_family) {
581 case AF_INET:
582 if (*have_v4 == 0) {
583 memcpy(&in4,
584 &((struct sockaddr_in *)
585 &lifreq.lifr_addr)->sin_addr,
586 sizeof in4);
587 if (in4.s_addr == INADDR_ANY)
588 break;
589 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
590 if (n < 0)
591 break;
592 if ((lifreq.lifr_flags & IFF_UP) == 0)
593 break;
594 *have_v4 = 1;
595 }
596 break;
597 case AF_INET6:
598 if (*have_v6 == 0) {
599 memcpy(&in6,
600 &((struct sockaddr_in6 *)
601 &lifreq.lifr_addr)->sin6_addr, sizeof in6);
602 if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
603 break;
604 n = ioctl(s, SIOCGLIFFLAGS, (char *)&lifreq);
605 if (n < 0)
606 break;
607 if ((lifreq.lifr_flags & IFF_UP) == 0)
608 break;
609 *have_v6 = 1;
610 }
611 break;
612 }
613 }
614 if (buf != NULL)
615 memput(buf, bufsiz);
616 close(s);
617 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
618 return;
619 cleanup:
620 if (buf != NULL)
621 memput(buf, bufsiz);
622 if (s != -1)
623 close(s);
624 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
625 return;
626 }
627 #endif
628
629 #if ( defined(__linux__) || defined(__linux) || defined(LINUX) )
630 #ifndef IF_NAMESIZE
631 # ifdef IFNAMSIZ
632 # define IF_NAMESIZE IFNAMSIZ
633 # else
634 # define IF_NAMESIZE 16
635 # endif
636 #endif
637 static void
638 scan_linux6(int *have_v6) {
639 FILE *proc = NULL;
640 char address[33];
641 char name[IF_NAMESIZE+1];
642 int ifindex, prefix, flag3, flag4;
643
644 proc = fopen("/proc/net/if_inet6", "r");
645 if (proc == NULL)
646 return;
647
648 if (fscanf(proc, "%32[a-f0-9] %x %x %x %x %16s\n",
649 address, &ifindex, &prefix, &flag3, &flag4, name) == 6)
650 *have_v6 = 1;
651 fclose(proc);
652 return;
653 }
654 #endif
655
656 static int
657 scan_interfaces(int *have_v4, int *have_v6) {
658 struct ifconf ifc;
659 union {
660 char _pad[256]; /*%< leave space for IPv6 addresses */
661 struct ifreq ifreq;
662 } u;
663 struct in_addr in4;
664 struct in6_addr in6;
665 char *buf = NULL, *cp, *cplim;
666 static unsigned int bufsiz = 4095;
667 int s, n;
668 size_t cpsize;
669
670 /* Set to zero. Used as loop terminators below. */
671 *have_v4 = *have_v6 = 0;
672
673 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) && \
674 !defined(IRIX_EMUL_IOCTL_SIOCGIFCONF)
675 /*
676 * Try to scan the interfaces using IPv6 ioctls().
677 */
678 scan_interfaces6(have_v4, have_v6);
679 if (*have_v4 != 0 && *have_v6 != 0)
680 return (0);
681 #endif
682 #ifdef __linux
683 scan_linux6(have_v6);
684 #endif
685
686 /* Get interface list from system. */
687 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
688 goto err_ret;
689
690 /*
691 * Grow buffer until large enough to contain all interface
692 * descriptions.
693 */
694 for (;;) {
695 buf = memget(bufsiz);
696 if (buf == NULL)
697 goto err_ret;
698 ifc.ifc_len = bufsiz;
699 ifc.ifc_buf = buf;
700 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
701 /*
702 * This is a fix for IRIX OS in which the call to ioctl with
703 * the flag SIOCGIFCONF may not return an entry for all the
704 * interfaces like most flavors of Unix.
705 */
706 if (emul_ioctl(&ifc) >= 0)
707 break;
708 #else
709 if ((n = ioctl(s, SIOCGIFCONF, (char *)&ifc)) != -1) {
710 /*
711 * Some OS's just return what will fit rather
712 * than set EINVAL if the buffer is too small
713 * to fit all the interfaces in. If
714 * ifc.ifc_len is too near to the end of the
715 * buffer we will grow it just in case and
716 * retry.
717 */
718 if (ifc.ifc_len + 2 * sizeof(u.ifreq) < bufsiz)
719 break;
720 }
721 #endif
722 if ((n == -1) && errno != EINVAL)
723 goto err_ret;
724
725 if (bufsiz > 1000000)
726 goto err_ret;
727
728 memput(buf, bufsiz);
729 bufsiz += 4096;
730 }
731
732 /* Parse system's interface list. */
733 cplim = buf + ifc.ifc_len; /*%< skip over if's with big ifr_addr's */
734 for (cp = buf;
735 (*have_v4 == 0 || *have_v6 == 0) && cp < cplim;
736 cp += cpsize) {
737 memcpy(&u.ifreq, cp, sizeof u.ifreq);
738 #ifdef HAVE_SA_LEN
739 #ifdef FIX_ZERO_SA_LEN
740 if (u.ifreq.ifr_addr.sa_len == 0)
741 u.ifreq.ifr_addr.sa_len = 16;
742 #endif
743 #ifdef HAVE_MINIMUM_IFREQ
744 cpsize = sizeof u.ifreq;
745 if (u.ifreq.ifr_addr.sa_len > sizeof (struct sockaddr))
746 cpsize += (int)u.ifreq.ifr_addr.sa_len -
747 (int)(sizeof (struct sockaddr));
748 #else
749 cpsize = sizeof u.ifreq.ifr_name + u.ifreq.ifr_addr.sa_len;
750 #endif /* HAVE_MINIMUM_IFREQ */
751 if (cpsize > sizeof u.ifreq && cpsize <= sizeof u)
752 memcpy(&u.ifreq, cp, cpsize);
753 #elif defined SIOCGIFCONF_ADDR
754 cpsize = sizeof u.ifreq;
755 #else
756 cpsize = sizeof u.ifreq.ifr_name;
757 /* XXX maybe this should be a hard error? */
758 if (ioctl(s, SIOCGIFADDR, (char *)&u.ifreq) < 0)
759 continue;
760 #endif
761 switch (u.ifreq.ifr_addr.sa_family) {
762 case AF_INET:
763 if (*have_v4 == 0) {
764 memcpy(&in4,
765 &((struct sockaddr_in *)
766 &u.ifreq.ifr_addr)->sin_addr,
767 sizeof in4);
768 if (in4.s_addr == INADDR_ANY)
769 break;
770 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
771 if (n < 0)
772 break;
773 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
774 break;
775 *have_v4 = 1;
776 }
777 break;
778 case AF_INET6:
779 if (*have_v6 == 0) {
780 memcpy(&in6,
781 &((struct sockaddr_in6 *)
782 &u.ifreq.ifr_addr)->sin6_addr,
783 sizeof in6);
784 if (memcmp(&in6, &in6addr_any, sizeof in6) == 0)
785 break;
786 n = ioctl(s, SIOCGIFFLAGS, (char *)&u.ifreq);
787 if (n < 0)
788 break;
789 if ((u.ifreq.ifr_flags & IFF_UP) == 0)
790 break;
791 *have_v6 = 1;
792 }
793 break;
794 }
795 }
796 if (buf != NULL)
797 memput(buf, bufsiz);
798 close(s);
799 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
800 return (0);
801 err_ret:
802 if (buf != NULL)
803 memput(buf, bufsiz);
804 if (s != -1)
805 close(s);
806 /* printf("scan interface -> 4=%d 6=%d\n", *have_v4, *have_v6); */
807 return (-1);
808 }
809
810 static struct hostent *
811 copyandmerge(struct hostent *he1, struct hostent *he2, int af, int *error_num) {
812 struct hostent *he = NULL;
813 int addresses = 1; /*%< NULL terminator */
814 int names = 1; /*%< NULL terminator */
815 int len = 0;
816 char **cpp, **npp;
817
818 /*
819 * Work out array sizes;
820 */
821 if (he1 != NULL) {
822 cpp = he1->h_addr_list;
823 while (*cpp != NULL) {
824 addresses++;
825 cpp++;
826 }
827 cpp = he1->h_aliases;
828 while (*cpp != NULL) {
829 names++;
830 cpp++;
831 }
832 }
833
834 if (he2 != NULL) {
835 cpp = he2->h_addr_list;
836 while (*cpp != NULL) {
837 addresses++;
838 cpp++;
839 }
840 if (he1 == NULL) {
841 cpp = he2->h_aliases;
842 while (*cpp != NULL) {
843 names++;
844 cpp++;
845 }
846 }
847 }
848
849 if (addresses == 1) {
850 *error_num = NO_ADDRESS;
851 return (NULL);
852 }
853
854 he = memget(sizeof *he);
855 if (he == NULL)
856 goto no_recovery;
857
858 he->h_addr_list = memget(sizeof(char *) * (addresses));
859 if (he->h_addr_list == NULL)
860 goto cleanup0;
861 memset(he->h_addr_list, 0, sizeof(char *) * (addresses));
862
863 /* copy addresses */
864 npp = he->h_addr_list;
865 if (he1 != NULL) {
866 cpp = he1->h_addr_list;
867 while (*cpp != NULL) {
868 *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
869 if (*npp == NULL)
870 goto cleanup1;
871 /* convert to mapped if required */
872 if (af == AF_INET6 && he1->h_addrtype == AF_INET) {
873 memcpy(*npp, in6addr_mapped,
874 sizeof in6addr_mapped);
875 memcpy(*npp + sizeof in6addr_mapped, *cpp,
876 INADDRSZ);
877 } else {
878 memcpy(*npp, *cpp,
879 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
880 }
881 cpp++;
882 npp++;
883 }
884 }
885
886 if (he2 != NULL) {
887 cpp = he2->h_addr_list;
888 while (*cpp != NULL) {
889 *npp = memget((af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
890 if (*npp == NULL)
891 goto cleanup1;
892 /* convert to mapped if required */
893 if (af == AF_INET6 && he2->h_addrtype == AF_INET) {
894 memcpy(*npp, in6addr_mapped,
895 sizeof in6addr_mapped);
896 memcpy(*npp + sizeof in6addr_mapped, *cpp,
897 INADDRSZ);
898 } else {
899 memcpy(*npp, *cpp,
900 (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
901 }
902 cpp++;
903 npp++;
904 }
905 }
906
907 he->h_aliases = memget(sizeof(char *) * (names));
908 if (he->h_aliases == NULL)
909 goto cleanup1;
910 memset(he->h_aliases, 0, sizeof(char *) * (names));
911
912 /* copy aliases */
913 npp = he->h_aliases;
914 cpp = (he1 != NULL) ? he1->h_aliases : he2->h_aliases;
915 while (*cpp != NULL) {
916 len = strlen (*cpp) + 1;
917 *npp = memget(len);
918 if (*npp == NULL)
919 goto cleanup2;
920 strcpy(*npp, *cpp);
921 npp++;
922 cpp++;
923 }
924
925 /* copy hostname */
926 he->h_name = memget(strlen((he1 != NULL) ?
927 he1->h_name : he2->h_name) + 1);
928 if (he->h_name == NULL)
929 goto cleanup2;
930 strcpy(he->h_name, (he1 != NULL) ? he1->h_name : he2->h_name);
931
932 /* set address type and length */
933 he->h_addrtype = af;
934 he->h_length = (af == AF_INET) ? INADDRSZ : IN6ADDRSZ;
935 return(he);
936
937 cleanup2:
938 cpp = he->h_aliases;
939 while (*cpp != NULL) {
940 memput(*cpp, strlen(*cpp) + 1);
941 cpp++;
942 }
943 memput(he->h_aliases, sizeof(char *) * (names));
944
945 cleanup1:
946 cpp = he->h_addr_list;
947 while (*cpp != NULL) {
948 memput(*cpp, (af == AF_INET) ? INADDRSZ : IN6ADDRSZ);
949 *cpp = NULL;
950 cpp++;
951 }
952 memput(he->h_addr_list, sizeof(char *) * (addresses));
953
954 cleanup0:
955 memput(he, sizeof *he);
956
957 no_recovery:
958 *error_num = NO_RECOVERY;
959 return (NULL);
960 }
961
962 static struct net_data *
963 init() {
964 struct net_data *net_data;
965
966 if (!(net_data = net_data_init(NULL)))
967 goto error;
968 if (!net_data->ho) {
969 net_data->ho = (*net_data->irs->ho_map)(net_data->irs);
970 if (!net_data->ho || !net_data->res) {
971 error:
972 errno = EIO;
973
974 #ifdef SUNW_SETHERRNO
975 h_errno = NETDB_INTERNAL;
976 #endif /* SUNW_SETHERRNO */
977 if (net_data && net_data->res)
978 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
979 return (NULL);
980 }
981
982 (*net_data->ho->res_set)(net_data->ho, net_data->res, NULL);
983 }
984
985 return (net_data);
986 }
987
988 static void
989 freepvt(struct net_data *net_data) {
990 if (net_data->ho_data) {
991 free(net_data->ho_data);
992 net_data->ho_data = NULL;
993 }
994 }
995
996 static struct hostent *
997 fakeaddr(const char *name, int af, struct net_data *net_data) {
998 struct pvt *pvt;
999
1000 freepvt(net_data);
1001 net_data->ho_data = malloc(sizeof (struct pvt));
1002 if (!net_data->ho_data) {
1003 errno = ENOMEM;
1004 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
1005 return (NULL);
1006 }
1007 pvt = net_data->ho_data;
1008 #ifndef __bsdi__
1009 /*
1010 * Unlike its forebear(inet_aton), our friendly inet_pton() is strict
1011 * in its interpretation of its input, and it will only return "1" if
1012 * the input string is a formally valid(and thus unambiguous with
1013 * respect to host names) internet address specification for this AF.
1014 *
1015 * This means "telnet 0xdeadbeef" and "telnet 127.1" are dead now.
1016 */
1017 if (inet_pton(af, name, pvt->addr) != 1) {
1018 #else
1019 /* BSDI XXX
1020 * We put this back to inet_aton -- we really want the old behavior
1021 * Long live 127.1...
1022 */
1023 if ((af != AF_INET ||
1024 inet_aton(name, (struct in_addr *)pvt->addr) != 1) &&
1025 inet_pton(af, name, pvt->addr) != 1) {
1026 #endif
1027 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
1028 return (NULL);
1029 }
1030 strncpy(pvt->name, name, NS_MAXDNAME);
1031 pvt->name[NS_MAXDNAME] = '\0';
1032 if (af == AF_INET && (net_data->res->options & RES_USE_INET6) != 0U) {
1033 map_v4v6_address(pvt->addr, pvt->addr);
1034 af = AF_INET6;
1035 }
1036 pvt->host.h_addrtype = af;
1037 switch(af) {
1038 case AF_INET:
1039 pvt->host.h_length = NS_INADDRSZ;
1040 break;
1041 case AF_INET6:
1042 pvt->host.h_length = NS_IN6ADDRSZ;
1043 break;
1044 default:
1045 errno = EAFNOSUPPORT;
1046 RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
1047 return (NULL);
1048 }
1049 pvt->host.h_name = pvt->name;
1050 pvt->host.h_aliases = pvt->aliases;
1051 pvt->aliases[0] = NULL;
1052 pvt->addrs[0] = (char *)pvt->addr;
1053 pvt->addrs[1] = NULL;
1054 pvt->host.h_addr_list = pvt->addrs;
1055 RES_SET_H_ERRNO(net_data->res, NETDB_SUCCESS);
1056 return (&pvt->host);
1057 }
1058
1059 #ifdef grot /*%< for future use in gethostbyaddr(), for "SUNSECURITY" */
1060 struct hostent *rhp;
1061 char **haddr;
1062 u_long old_options;
1063 char hname2[MAXDNAME+1];
1064
1065 if (af == AF_INET) {
1066 /*
1067 * turn off search as the name should be absolute,
1068 * 'localhost' should be matched by defnames
1069 */
1070 strncpy(hname2, hp->h_name, MAXDNAME);
1071 hname2[MAXDNAME] = '\0';
1072 old_options = net_data->res->options;
1073 net_data->res->options &= ~RES_DNSRCH;
1074 net_data->res->options |= RES_DEFNAMES;
1075 if (!(rhp = gethostbyname(hname2))) {
1076 net_data->res->options = old_options;
1077 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
1078 return (NULL);
1079 }
1080 net_data->res->options = old_options;
1081 for (haddr = rhp->h_addr_list; *haddr; haddr++)
1082 if (!memcmp(*haddr, addr, INADDRSZ))
1083 break;
1084 if (!*haddr) {
1085 RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
1086 return (NULL);
1087 }
1088 }
1089 #endif /* grot */
1090 #endif /*__BIND_NOSTATIC*/
1091
1092 /*! \file */
1093