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