xref: /illumos-gate/usr/src/lib/libresolv2/common/irs/getnetent.c (revision 2983dda76a6d296fdb560c88114fe41caad1b84f)
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: 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 
51 struct pvt {
52 	struct netent	netent;
53 	char *		aliases[1];
54 	char		name[MAXDNAME + 1];
55 };
56 
57 /* Forward */
58 
59 static struct net_data *init(void);
60 static struct netent   *nw_to_net(struct nwent *, struct net_data *);
61 static void		freepvt(struct net_data *);
62 static 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 
72 struct netent *
73 getnetent() {
74 	struct net_data *net_data = init();
75 
76 	return (getnetent_p(net_data));
77 }
78 
79 struct netent *
80 getnetbyname(const char *name) {
81 	struct net_data *net_data = init();
82 
83 	return (getnetbyname_p(name, net_data));
84 }
85 
86 struct netent *
87 getnetbyaddr(unsigned long net, int type) {
88 	struct net_data *net_data = init();
89 
90 	return (getnetbyaddr_p(net, type, net_data));
91 }
92 
93 void
94 setnetent(int stayopen) {
95 	struct net_data *net_data = init();
96 
97 	setnetent_p(stayopen, net_data);
98 }
99 
100 
101 void
102 endnetent() {
103 	struct net_data *net_data = init();
104 
105 	endnetent_p(net_data);
106 }
107 
108 /* Shared private. */
109 
110 struct netent *
111 getnetent_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 
121 struct netent *
122 getnetbyname_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 
145 struct netent *
146 getnetbyaddr_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 
199 void
200 setnetent_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 
212 void
213 endnetent_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 
222 static struct net_data *
223 init() {
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 
242 static void
243 freepvt(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 
250 static struct netent *
251 fakeaddr(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 
303 static struct netent *
304 nw_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