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