xref: /netbsd-src/external/bsd/libbind/dist/irs/gen_ho.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: gen_ho.c,v 1.1.1.2 2012/09/09 16:07:54 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (c) 1996,1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid[] = "Id: gen_ho.c,v 1.5 2006/03/09 23:57:56 marka Exp ";
22 #endif /* LIBC_SCCS and not lint */
23 
24 /* Imports */
25 
26 #include "port_before.h"
27 
28 #include <sys/types.h>
29 
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
32 
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <netdb.h>
36 #include <resolv.h>
37 #include <stdio.h>
38 #include <string.h>
39 
40 #include <isc/memcluster.h>
41 #include <irs.h>
42 
43 #include "port_after.h"
44 
45 #include "irs_p.h"
46 #include "gen_p.h"
47 
48 /* Definitions */
49 
50 struct pvt {
51 	struct irs_rule *	rules;
52 	struct irs_rule *	rule;
53 	struct irs_ho *		ho;
54 	struct __res_state *	res;
55 	void			(*free_res)(void *);
56 };
57 
58 /* Forwards */
59 
60 static void		ho_close(struct irs_ho *this);
61 static struct hostent *	ho_byname(struct irs_ho *this, const char *name);
62 static struct hostent *	ho_byname2(struct irs_ho *this, const char *name,
63 				   int af);
64 static struct hostent *	ho_byaddr(struct irs_ho *this, const void *addr,
65 				  int len, int af);
66 static struct hostent *	ho_next(struct irs_ho *this);
67 static void		ho_rewind(struct irs_ho *this);
68 static void		ho_minimize(struct irs_ho *this);
69 static struct __res_state * ho_res_get(struct irs_ho *this);
70 static void		ho_res_set(struct irs_ho *this,
71 				   struct __res_state *res,
72 				   void (*free_res)(void *));
73 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
74 				     const struct addrinfo *pai);
75 
76 static int		init(struct irs_ho *this);
77 
78 /* Exports */
79 
80 struct irs_ho *
irs_gen_ho(struct irs_acc * this)81 irs_gen_ho(struct irs_acc *this) {
82 	struct gen_p *accpvt = (struct gen_p *)this->private;
83 	struct irs_ho *ho;
84 	struct pvt *pvt;
85 
86 	if (!(pvt = memget(sizeof *pvt))) {
87 		errno = ENOMEM;
88 		return (NULL);
89 	}
90 	memset(pvt, 0, sizeof *pvt);
91 	if (!(ho = memget(sizeof *ho))) {
92 		memput(pvt, sizeof *pvt);
93 		errno = ENOMEM;
94 		return (NULL);
95 	}
96 	memset(ho, 0x5e, sizeof *ho);
97 	pvt->rules = accpvt->map_rules[irs_ho];
98 	pvt->rule = pvt->rules;
99 	ho->private = pvt;
100 	ho->close = ho_close;
101 	ho->byname = ho_byname;
102 	ho->byname2 = ho_byname2;
103 	ho->byaddr = ho_byaddr;
104 	ho->next = ho_next;
105 	ho->rewind = ho_rewind;
106 	ho->minimize = ho_minimize;
107 	ho->res_get = ho_res_get;
108 	ho->res_set = ho_res_set;
109 	ho->addrinfo = ho_addrinfo;
110 	return (ho);
111 }
112 
113 /* Methods. */
114 
115 static void
ho_close(struct irs_ho * this)116 ho_close(struct irs_ho *this) {
117 	struct pvt *pvt = (struct pvt *)this->private;
118 
119 	ho_minimize(this);
120 	if (pvt->res && pvt->free_res)
121 		(*pvt->free_res)(pvt->res);
122 	memput(pvt, sizeof *pvt);
123 	memput(this, sizeof *this);
124 }
125 
126 static struct hostent *
ho_byname(struct irs_ho * this,const char * name)127 ho_byname(struct irs_ho *this, const char *name) {
128 	struct pvt *pvt = (struct pvt *)this->private;
129 	struct irs_rule *rule;
130 	struct hostent *rval;
131 	struct irs_ho *ho;
132 	int therrno = NETDB_INTERNAL;
133 	int softerror = 0;
134 
135 	if (init(this) == -1)
136 		return (NULL);
137 
138 	for (rule = pvt->rules; rule; rule = rule->next) {
139 		ho = rule->inst->ho;
140 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
141 		errno = 0;
142 		rval = (*ho->byname)(ho, name);
143 		if (rval != NULL)
144 			return (rval);
145 		if (softerror == 0 &&
146 		    pvt->res->res_h_errno != HOST_NOT_FOUND &&
147 		    pvt->res->res_h_errno != NETDB_INTERNAL) {
148 			softerror = 1;
149 			therrno = pvt->res->res_h_errno;
150 		}
151 		if (rule->flags & IRS_CONTINUE)
152 			continue;
153 		/*
154 		 * The value TRY_AGAIN can mean that the service
155 		 * is not available, or just that this particular name
156 		 * cannot be resolved now.  We use the errno ECONNREFUSED
157 		 * to distinguish.  If a lookup sets that errno when
158 		 * H_ERRNO is TRY_AGAIN, we continue to try other lookup
159 		 * functions, otherwise we return the TRY_AGAIN error.
160 		 */
161 		if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
162 			break;
163 	}
164 	if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
165 		RES_SET_H_ERRNO(pvt->res, therrno);
166 	return (NULL);
167 }
168 
169 static struct hostent *
ho_byname2(struct irs_ho * this,const char * name,int af)170 ho_byname2(struct irs_ho *this, const char *name, int af) {
171 	struct pvt *pvt = (struct pvt *)this->private;
172 	struct irs_rule *rule;
173 	struct hostent *rval;
174 	struct irs_ho *ho;
175 	int therrno = NETDB_INTERNAL;
176 	int softerror = 0;
177 
178 	if (init(this) == -1)
179 		return (NULL);
180 
181 	for (rule = pvt->rules; rule; rule = rule->next) {
182 		ho = rule->inst->ho;
183 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
184 		errno = 0;
185 		rval = (*ho->byname2)(ho, name, af);
186 		if (rval != NULL)
187 			return (rval);
188 		if (softerror == 0 &&
189 		    pvt->res->res_h_errno != HOST_NOT_FOUND &&
190 		    pvt->res->res_h_errno != NETDB_INTERNAL) {
191 			softerror = 1;
192 			therrno = pvt->res->res_h_errno;
193 		}
194 		if (rule->flags & IRS_CONTINUE)
195 			continue;
196 		/*
197 		 * See the comments in ho_byname() explaining
198 		 * the interpretation of TRY_AGAIN and ECONNREFUSED.
199 		 */
200 		if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
201 			break;
202 	}
203 	if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
204 		RES_SET_H_ERRNO(pvt->res, therrno);
205 	return (NULL);
206 }
207 
208 static struct hostent *
ho_byaddr(struct irs_ho * this,const void * addr,int len,int af)209 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
210 	struct pvt *pvt = (struct pvt *)this->private;
211 	struct irs_rule *rule;
212 	struct hostent *rval;
213 	struct irs_ho *ho;
214 	int therrno = NETDB_INTERNAL;
215 	int softerror = 0;
216 
217 
218 	if (init(this) == -1)
219 		return (NULL);
220 
221 	for (rule = pvt->rules; rule; rule = rule->next) {
222 		ho = rule->inst->ho;
223 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
224 		errno = 0;
225 		rval = (*ho->byaddr)(ho, addr, len, af);
226 		if (rval != NULL)
227 			return (rval);
228 		if (softerror == 0 &&
229 		    pvt->res->res_h_errno != HOST_NOT_FOUND &&
230 		    pvt->res->res_h_errno != NETDB_INTERNAL) {
231 			softerror = 1;
232 			therrno = pvt->res->res_h_errno;
233 		}
234 
235 		if (rule->flags & IRS_CONTINUE)
236 			continue;
237 		/*
238 		 * See the comments in ho_byname() explaining
239 		 * the interpretation of TRY_AGAIN and ECONNREFUSED.
240 		 */
241 		if (pvt->res->res_h_errno != TRY_AGAIN || errno != ECONNREFUSED)
242 			break;
243 	}
244 	if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
245 		RES_SET_H_ERRNO(pvt->res, therrno);
246 	return (NULL);
247 }
248 
249 static struct hostent *
ho_next(struct irs_ho * this)250 ho_next(struct irs_ho *this) {
251 	struct pvt *pvt = (struct pvt *)this->private;
252 	struct hostent *rval;
253 	struct irs_ho *ho;
254 
255 	while (pvt->rule) {
256 		ho = pvt->rule->inst->ho;
257 		rval = (*ho->next)(ho);
258 		if (rval)
259 			return (rval);
260 		if (!(pvt->rule->flags & IRS_CONTINUE))
261 			break;
262 		pvt->rule = pvt->rule->next;
263 		if (pvt->rule) {
264 			ho = pvt->rule->inst->ho;
265 			(*ho->rewind)(ho);
266 		}
267 	}
268 	return (NULL);
269 }
270 
271 static void
ho_rewind(struct irs_ho * this)272 ho_rewind(struct irs_ho *this) {
273 	struct pvt *pvt = (struct pvt *)this->private;
274 	struct irs_ho *ho;
275 
276 	pvt->rule = pvt->rules;
277 	if (pvt->rule) {
278 		ho = pvt->rule->inst->ho;
279 		(*ho->rewind)(ho);
280 	}
281 }
282 
283 static void
ho_minimize(struct irs_ho * this)284 ho_minimize(struct irs_ho *this) {
285 	struct pvt *pvt = (struct pvt *)this->private;
286 	struct irs_rule *rule;
287 
288 	if (pvt->res)
289 		res_nclose(pvt->res);
290 	for (rule = pvt->rules; rule != NULL; rule = rule->next) {
291 		struct irs_ho *ho = rule->inst->ho;
292 
293 		(*ho->minimize)(ho);
294 	}
295 }
296 
297 static struct __res_state *
ho_res_get(struct irs_ho * this)298 ho_res_get(struct irs_ho *this) {
299 	struct pvt *pvt = (struct pvt *)this->private;
300 
301 	if (!pvt->res) {
302 		struct __res_state *res;
303 		res = (struct __res_state *)malloc(sizeof *res);
304 		if (!res) {
305 			errno = ENOMEM;
306 			return (NULL);
307 		}
308 		memset(res, 0, sizeof *res);
309 		ho_res_set(this, res, free);
310 	}
311 
312 	return (pvt->res);
313 }
314 
315 static void
ho_res_set(struct irs_ho * this,struct __res_state * res,void (* free_res)(void *))316 ho_res_set(struct irs_ho *this, struct __res_state *res,
317 		void (*free_res)(void *)) {
318 	struct pvt *pvt = (struct pvt *)this->private;
319 	struct irs_rule *rule;
320 
321 	if (pvt->res && pvt->free_res) {
322 		res_nclose(pvt->res);
323 		(*pvt->free_res)(pvt->res);
324 	}
325 
326 	pvt->res = res;
327 	pvt->free_res = free_res;
328 
329 	for (rule = pvt->rules; rule != NULL; rule = rule->next) {
330 		struct irs_ho *ho = rule->inst->ho;
331 
332 		(*ho->res_set)(ho, pvt->res, NULL);
333 	}
334 }
335 
336 static struct addrinfo *
ho_addrinfo(struct irs_ho * this,const char * name,const struct addrinfo * pai)337 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
338 {
339 	struct pvt *pvt = (struct pvt *)this->private;
340 	struct irs_rule *rule;
341 	struct addrinfo *rval = NULL;
342 	struct irs_ho *ho;
343 	int therrno = NETDB_INTERNAL;
344 	int softerror = 0;
345 
346 	if (init(this) == -1)
347 		return (NULL);
348 
349 	for (rule = pvt->rules; rule; rule = rule->next) {
350 		ho = rule->inst->ho;
351 		RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
352 		errno = 0;
353 		if (ho->addrinfo == NULL) /*%< for safety */
354 			continue;
355 		rval = (*ho->addrinfo)(ho, name, pai);
356 		if (rval != NULL)
357 			return (rval);
358 		if (softerror == 0 &&
359 		    pvt->res->res_h_errno != HOST_NOT_FOUND &&
360 		    pvt->res->res_h_errno != NETDB_INTERNAL) {
361 			softerror = 1;
362 			therrno = pvt->res->res_h_errno;
363 		}
364 		if (rule->flags & IRS_CONTINUE)
365 			continue;
366 		/*
367 		 * See the comments in ho_byname() explaining
368 		 * the interpretation of TRY_AGAIN and ECONNREFUSED.
369 		 */
370 		if (pvt->res->res_h_errno != TRY_AGAIN ||
371 		    errno != ECONNREFUSED)
372 			break;
373 	}
374 	if (softerror != 0 && pvt->res->res_h_errno == HOST_NOT_FOUND)
375 		RES_SET_H_ERRNO(pvt->res, therrno);
376 	return (NULL);
377 }
378 
379 static int
init(struct irs_ho * this)380 init(struct irs_ho *this) {
381 	struct pvt *pvt = (struct pvt *)this->private;
382 
383         if (!pvt->res && !ho_res_get(this))
384                 return (-1);
385 
386         if (((pvt->res->options & RES_INIT) == 0U) &&
387             (res_ninit(pvt->res) == -1))
388                 return (-1);
389 
390         return (0);
391 }
392 
393 /*! \file */
394