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