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)
19static const char rcsid[] = "$Id: getnetent.c,v 1.7 2005/04/27 04:56:25 sra 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/socket.h>
30
31#include <netinet/in.h>
32#include <arpa/nameser.h>
33#include <arpa/inet.h>
34
35#include <ctype.h>
36#include <errno.h>
37#include <netdb.h>
38#include <resolv.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include <irs.h>
43
44#include "port_after.h"
45
46#include "irs_p.h"
47#include "irs_data.h"
48
49/* Definitions */
50
51struct pvt {
52	struct netent	netent;
53	char *		aliases[1];
54	char		name[MAXDNAME + 1];
55};
56
57/* Forward */
58
59static struct net_data *init(void);
60static struct netent   *nw_to_net(struct nwent *, struct net_data *);
61static void		freepvt(struct net_data *);
62static struct netent   *fakeaddr(const char *, int af, struct net_data *);
63
64/* Portability */
65
66#ifndef INADDR_NONE
67# define INADDR_NONE 0xffffffff
68#endif
69
70/* Public */
71
72struct netent *
73getnetent() {
74	struct net_data *net_data = init();
75
76	return (getnetent_p(net_data));
77}
78
79struct netent *
80getnetbyname(const char *name) {
81	struct net_data *net_data = init();
82
83	return (getnetbyname_p(name, net_data));
84}
85
86struct netent *
87getnetbyaddr(unsigned long net, int type) {
88	struct net_data *net_data = init();
89
90	return (getnetbyaddr_p(net, type, net_data));
91}
92
93void
94setnetent(int stayopen) {
95	struct net_data *net_data = init();
96
97	setnetent_p(stayopen, net_data);
98}
99
100
101void
102endnetent() {
103	struct net_data *net_data = init();
104
105	endnetent_p(net_data);
106}
107
108/* Shared private. */
109
110struct netent *
111getnetent_p(struct net_data *net_data) {
112	struct irs_nw *nw;
113
114	if (!net_data || !(nw = net_data->nw))
115		return (NULL);
116	net_data->nww_last = (*nw->next)(nw);
117	net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
118	return (net_data->nw_last);
119}
120
121struct netent *
122getnetbyname_p(const char *name, struct net_data *net_data) {
123	struct irs_nw *nw;
124	struct netent *np;
125	char **nap;
126
127	if (!net_data || !(nw = net_data->nw))
128		return (NULL);
129	if (net_data->nw_stayopen && net_data->nw_last) {
130		if (!strcmp(net_data->nw_last->n_name, name))
131			return (net_data->nw_last);
132		for (nap = net_data->nw_last->n_aliases; nap && *nap; nap++)
133			if (!strcmp(name, *nap))
134				return (net_data->nw_last);
135	}
136	if ((np = fakeaddr(name, AF_INET, net_data)) != NULL)
137		return (np);
138	net_data->nww_last = (*nw->byname)(nw, name, AF_INET);
139	net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
140	if (!net_data->nw_stayopen)
141		endnetent();
142	return (net_data->nw_last);
143}
144
145struct netent *
146getnetbyaddr_p(unsigned long net, int type, struct net_data *net_data) {
147	struct irs_nw *nw;
148	u_char addr[4];
149	int bits;
150
151	if (!net_data || !(nw = net_data->nw))
152		return (NULL);
153	if (net_data->nw_stayopen && net_data->nw_last)
154		if (type == net_data->nw_last->n_addrtype &&
155		    net == net_data->nw_last->n_net)
156			return (net_data->nw_last);
157
158	/* cannonize net(host order) */
159	if (net < 256UL) {
160		net <<= 24;
161		bits = 8;
162	} else if (net < 65536UL) {
163		net <<= 16;
164		bits = 16;
165	} else if (net < 16777216UL) {
166		net <<= 8;
167		bits = 24;
168	} else
169		bits = 32;
170
171	/* convert to net order */
172	addr[0] = (0xFF000000 & net) >> 24;
173	addr[1] = (0x00FF0000 & net) >> 16;
174	addr[2] = (0x0000FF00 & net) >> 8;
175	addr[3] = (0x000000FF & net);
176
177	/* reduce bits to as close to natural number as possible */
178	if ((bits == 32) && (addr[0] < 224) && (addr[3] == 0)) {
179		if ((addr[0] < 192) && (addr[2] == 0)) {
180			if ((addr[0] < 128) && (addr[1] == 0))
181				bits = 8;
182			else
183				bits = 16;
184		} else {
185			bits = 24;
186		}
187	}
188
189	net_data->nww_last = (*nw->byaddr)(nw, addr, bits, AF_INET);
190	net_data->nw_last = nw_to_net(net_data->nww_last, net_data);
191	if (!net_data->nw_stayopen)
192		endnetent();
193	return (net_data->nw_last);
194}
195
196
197
198
199void
200setnetent_p(int stayopen, struct net_data *net_data) {
201	struct irs_nw *nw;
202
203	if (!net_data || !(nw = net_data->nw))
204		return;
205	freepvt(net_data);
206	(*nw->rewind)(nw);
207	net_data->nw_stayopen = (stayopen != 0);
208	if (stayopen == 0)
209		net_data_minimize(net_data);
210}
211
212void
213endnetent_p(struct net_data *net_data) {
214	struct irs_nw *nw;
215
216	if ((net_data != NULL) && ((nw	= net_data->nw) != NULL))
217		(*nw->minimize)(nw);
218}
219
220/* Private */
221
222static struct net_data *
223init() {
224	struct net_data *net_data;
225
226	if (!(net_data = net_data_init(NULL)))
227		goto error;
228	if (!net_data->nw) {
229		net_data->nw = (*net_data->irs->nw_map)(net_data->irs);
230
231		if (!net_data->nw || !net_data->res) {
232 error:
233			errno = EIO;
234			return (NULL);
235		}
236		(*net_data->nw->res_set)(net_data->nw, net_data->res, NULL);
237	}
238
239	return (net_data);
240}
241
242static void
243freepvt(struct net_data *net_data) {
244	if (net_data->nw_data) {
245		free(net_data->nw_data);
246		net_data->nw_data = NULL;
247	}
248}
249
250static struct netent *
251fakeaddr(const char *name, int af, struct net_data *net_data) {
252	struct pvt *pvt;
253	const char *cp;
254	u_long tmp;
255
256	if (af != AF_INET) {
257		/* XXX should support IPv6 some day */
258		errno = EAFNOSUPPORT;
259		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
260		return (NULL);
261	}
262	if (!isascii((unsigned char)(name[0])) ||
263	    !isdigit((unsigned char)(name[0])))
264		return (NULL);
265	for (cp = name; *cp; ++cp)
266		if (!isascii(*cp) || (!isdigit((unsigned char)*cp) && *cp != '.'))
267			return (NULL);
268	if (*--cp == '.')
269		return (NULL);
270
271	/* All-numeric, no dot at the end. */
272
273	tmp = inet_network(name);
274	if (tmp == INADDR_NONE) {
275		RES_SET_H_ERRNO(net_data->res, HOST_NOT_FOUND);
276		return (NULL);
277	}
278
279	/* Valid network number specified.
280	 * Fake up a netent as if we'd actually
281	 * done a lookup.
282	 */
283	freepvt(net_data);
284	net_data->nw_data = malloc(sizeof (struct pvt));
285	if (!net_data->nw_data) {
286		errno = ENOMEM;
287		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
288		return (NULL);
289	}
290	pvt = net_data->nw_data;
291
292	strncpy(pvt->name, name, MAXDNAME);
293	pvt->name[MAXDNAME] = '\0';
294	pvt->netent.n_name = pvt->name;
295	pvt->netent.n_addrtype = AF_INET;
296	pvt->netent.n_aliases = pvt->aliases;
297	pvt->aliases[0] = NULL;
298	pvt->netent.n_net = tmp;
299
300	return (&pvt->netent);
301}
302
303static struct netent *
304nw_to_net(struct nwent *nwent, struct net_data *net_data) {
305	struct pvt *pvt;
306	u_long addr = 0;
307	int i;
308	int msbyte;
309
310	if (!nwent || nwent->n_addrtype != AF_INET)
311		return (NULL);
312	freepvt(net_data);
313	net_data->nw_data = malloc(sizeof (struct pvt));
314	if (!net_data->nw_data) {
315		errno = ENOMEM;
316		RES_SET_H_ERRNO(net_data->res, NETDB_INTERNAL);
317		return (NULL);
318	}
319	pvt = net_data->nw_data;
320	pvt->netent.n_name = nwent->n_name;
321	pvt->netent.n_aliases = nwent->n_aliases;
322	pvt->netent.n_addrtype = nwent->n_addrtype;
323
324/*%
325 * What this code does: Converts net addresses from network to host form.
326 *
327 * msbyte: the index of the most significant byte in the n_addr array.
328 *
329 * Shift bytes in significant order into addr. When all signicant
330 * bytes are in, zero out bits in the LSB that are not part of the network.
331 */
332	msbyte = nwent->n_length / 8 +
333		((nwent->n_length % 8) != 0 ? 1 : 0) - 1;
334	for (i = 0; i <= msbyte; i++)
335		addr = (addr << 8) | ((unsigned char *)nwent->n_addr)[i];
336	i = (32 - nwent->n_length) % 8;
337	if (i != 0)
338		addr &= ~((1 << (i + 1)) - 1);
339	pvt->netent.n_net = addr;
340	return (&pvt->netent);
341}
342
343#endif /*__BIND_NOSTATIC*/
344
345/*! \file */
346