1/*	$NetBSD: dns_pr.c,v 1.1.1.2 2012/09/09 16:07:51 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)
21static const char rcsid[] = "Id: dns_pr.c,v 1.5 2005/04/27 04:56:22 sra Exp ";
22#endif
23
24/* Imports */
25
26#include "port_before.h"
27
28#include <sys/types.h>
29#include <netinet/in.h>
30#include <arpa/nameser.h>
31#include <resolv.h>
32
33#include <stdio.h>
34#include <string.h>
35#include <netdb.h>
36#include <ctype.h>
37#include <stdlib.h>
38#include <errno.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 "hesiod.h"
47#include "dns_p.h"
48
49/* Types. */
50
51struct pvt {
52	struct dns_p *		dns;
53	struct protoent		proto;
54	char *			prbuf;
55};
56
57/* Forward. */
58
59static void 			pr_close(struct irs_pr *);
60static struct protoent *	pr_byname(struct irs_pr *, const char *);
61static struct protoent *	pr_bynumber(struct irs_pr *, int);
62static struct protoent *	pr_next(struct irs_pr *);
63static void			pr_rewind(struct irs_pr *);
64static void			pr_minimize(struct irs_pr *);
65static struct __res_state *	pr_res_get(struct irs_pr *);
66static void			pr_res_set(struct irs_pr *,
67					   struct __res_state *,
68					   void (*)(void *));
69
70static struct protoent *	parse_hes_list(struct irs_pr *, char **);
71
72/* Public. */
73
74struct irs_pr *
75irs_dns_pr(struct irs_acc *this) {
76	struct dns_p *dns = (struct dns_p *)this->private;
77	struct pvt *pvt;
78	struct irs_pr *pr;
79
80	if (!dns->hes_ctx) {
81		errno = ENODEV;
82		return (NULL);
83	}
84	if (!(pvt = memget(sizeof *pvt))) {
85		errno = ENOMEM;
86		return (NULL);
87	}
88	memset(pvt, 0, sizeof *pvt);
89	if (!(pr = memget(sizeof *pr))) {
90		memput(pvt, sizeof *pvt);
91		errno = ENOMEM;
92		return (NULL);
93	}
94	memset(pr, 0x5e, sizeof *pr);
95	pvt->dns = dns;
96	pr->private = pvt;
97	pr->byname = pr_byname;
98	pr->bynumber = pr_bynumber;
99	pr->next = pr_next;
100	pr->rewind = pr_rewind;
101	pr->close = pr_close;
102	pr->minimize = pr_minimize;
103	pr->res_get = pr_res_get;
104	pr->res_set = pr_res_set;
105	return (pr);
106}
107
108/* Methods. */
109
110static void
111pr_close(struct irs_pr *this) {
112	struct pvt *pvt = (struct pvt *)this->private;
113
114	if (pvt->proto.p_aliases)
115		free(pvt->proto.p_aliases);
116	if (pvt->prbuf)
117		free(pvt->prbuf);
118
119	memput(pvt, sizeof *pvt);
120	memput(this, sizeof *this);
121}
122
123static struct protoent *
124pr_byname(struct irs_pr *this, const char *name) {
125	struct pvt *pvt = (struct pvt *)this->private;
126	struct dns_p *dns = pvt->dns;
127	struct protoent *proto;
128	char **hes_list;
129
130	if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "protocol")))
131		return (NULL);
132
133	proto = parse_hes_list(this, hes_list);
134	hesiod_free_list(dns->hes_ctx, hes_list);
135	return (proto);
136}
137
138static struct protoent *
139pr_bynumber(struct irs_pr *this, int num) {
140	struct pvt *pvt = (struct pvt *)this->private;
141	struct dns_p *dns = pvt->dns;
142	struct protoent *proto;
143	char numstr[16];
144	char **hes_list;
145
146	sprintf(numstr, "%d", num);
147	if (!(hes_list = hesiod_resolve(dns->hes_ctx, numstr, "protonum")))
148		return (NULL);
149
150	proto = parse_hes_list(this, hes_list);
151	hesiod_free_list(dns->hes_ctx, hes_list);
152	return (proto);
153}
154
155static struct protoent *
156pr_next(struct irs_pr *this) {
157	UNUSED(this);
158	errno = ENODEV;
159	return (NULL);
160}
161
162static void
163pr_rewind(struct irs_pr *this) {
164	UNUSED(this);
165	/* NOOP */
166}
167
168static void
169pr_minimize(struct irs_pr *this) {
170	UNUSED(this);
171	/* NOOP */
172}
173
174static struct __res_state *
175pr_res_get(struct irs_pr *this) {
176	struct pvt *pvt = (struct pvt *)this->private;
177	struct dns_p *dns = pvt->dns;
178
179	return (__hesiod_res_get(dns->hes_ctx));
180}
181
182static void
183pr_res_set(struct irs_pr *this, struct __res_state * res,
184	   void (*free_res)(void *)) {
185	struct pvt *pvt = (struct pvt *)this->private;
186	struct dns_p *dns = pvt->dns;
187
188	__hesiod_res_set(dns->hes_ctx, res, free_res);
189}
190
191/* Private. */
192
193static struct protoent *
194parse_hes_list(struct irs_pr *this, char **hes_list) {
195	struct pvt *pvt = (struct pvt *)this->private;
196	char *p, *cp, **cpp, **new;
197	int num = 0;
198	int max = 0;
199
200	for (cpp = hes_list; *cpp; cpp++) {
201		cp = *cpp;
202
203		/* Strip away comments, if any. */
204		if ((p = strchr(cp, '#')))
205			*p = 0;
206
207		/* Skip blank lines. */
208		p = cp;
209		while (*p && !isspace((unsigned char)*p))
210			p++;
211		if (!*p)
212			continue;
213
214		/* OK, we've got a live one.  Let's parse it for real. */
215		if (pvt->prbuf)
216			free(pvt->prbuf);
217		pvt->prbuf = strdup(cp);
218
219		p = pvt->prbuf;
220		pvt->proto.p_name = p;
221		while (*p && !isspace((unsigned char)*p))
222			p++;
223		if (!*p)
224			continue;
225		*p++ = '\0';
226
227		pvt->proto.p_proto = atoi(p);
228		while (*p && !isspace((unsigned char)*p))
229			p++;
230		if (*p)
231			*p++ = '\0';
232
233		while (*p) {
234			if ((num + 1) >= max || !pvt->proto.p_aliases) {
235				max += 10;
236				new = realloc(pvt->proto.p_aliases,
237					      max * sizeof(char *));
238				if (!new) {
239					errno = ENOMEM;
240					goto cleanup;
241				}
242				pvt->proto.p_aliases = new;
243			}
244			pvt->proto.p_aliases[num++] = p;
245			while (*p && !isspace((unsigned char)*p))
246				p++;
247			if (*p)
248				*p++ = '\0';
249		}
250		if (!pvt->proto.p_aliases)
251			pvt->proto.p_aliases = malloc(sizeof(char *));
252		if (!pvt->proto.p_aliases)
253			goto cleanup;
254		pvt->proto.p_aliases[num] = NULL;
255		return (&pvt->proto);
256	}
257
258 cleanup:
259	if (pvt->proto.p_aliases) {
260		free(pvt->proto.p_aliases);
261		pvt->proto.p_aliases = NULL;
262	}
263	if (pvt->prbuf) {
264		free(pvt->prbuf);
265		pvt->prbuf = NULL;
266	}
267	return (NULL);
268}
269
270/*! \file */
271