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