xref: /illumos-gate/usr/src/lib/libresolv2/common/irs/dns_sv.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 1997-2002 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 1996,1999 by Internet Software Consortium.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20  * SOFTWARE.
21  */
22 
23 #pragma ident	"%Z%%M%	%I%	%E% SMI"
24 
25 #if defined(LIBC_SCCS) && !defined(lint)
26 static const char rcsid[] = "$Id: dns_sv.c,v 1.20 2001/05/29 05:48:33 marka Exp $";
27 #endif
28 
29 /* Imports */
30 
31 #include "port_before.h"
32 
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 
36 #include <stdio.h>
37 #include <string.h>
38 #include <netdb.h>
39 #include <ctype.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 
43 #include <sys/types.h>
44 #include <netinet/in.h>
45 #include <arpa/nameser.h>
46 #include <resolv.h>
47 
48 #include <isc/memcluster.h>
49 #include <irs.h>
50 
51 #include "port_after.h"
52 
53 #include "irs_p.h"
54 #include "hesiod.h"
55 #include "dns_p.h"
56 
57 /* Definitions */
58 
59 struct pvt {
60 	struct dns_p *		dns;
61 	struct servent		serv;
62 	char *			svbuf;
63 	struct __res_state *	res;
64 	void			(*free_res)(void *);
65 };
66 
67 /* Forward. */
68 
69 static void 			sv_close(struct irs_sv *);
70 static struct servent *		sv_byname(struct irs_sv *,
71 					  const char *, const char *);
72 static struct servent *		sv_byport(struct irs_sv *, int, const char *);
73 static struct servent *		sv_next(struct irs_sv *);
74 static void			sv_rewind(struct irs_sv *);
75 static void			sv_minimize(struct irs_sv *);
76 #ifdef SV_RES_SETGET
77 static struct __res_state *	sv_res_get(struct irs_sv *);
78 static void			sv_res_set(struct irs_sv *,
79 					   struct __res_state *,
80 					   void (*)(void *));
81 #endif
82 
83 static struct servent *		parse_hes_list(struct irs_sv *,
84 					       char **, const char *);
85 
86 /* Public */
87 
88 struct irs_sv *
89 irs_dns_sv(struct irs_acc *this) {
90 	struct dns_p *dns = (struct dns_p *)this->private;
91 	struct irs_sv *sv;
92 	struct pvt *pvt;
93 
94 	if (!dns || !dns->hes_ctx) {
95 		errno = ENODEV;
96 		return (NULL);
97 	}
98 	if (!(pvt = memget(sizeof *pvt))) {
99 		errno = ENOMEM;
100 		return (NULL);
101 	}
102 	memset(pvt, 0, sizeof *pvt);
103 	pvt->dns = dns;
104 	if (!(sv = memget(sizeof *sv))) {
105 		memput(pvt, sizeof *pvt);
106 		errno = ENOMEM;
107 		return (NULL);
108 	}
109 	memset(sv, 0x5e, sizeof *sv);
110 	sv->private = pvt;
111 	sv->byname = sv_byname;
112 	sv->byport = sv_byport;
113 	sv->next = sv_next;
114 	sv->rewind = sv_rewind;
115 	sv->close = sv_close;
116 	sv->minimize = sv_minimize;
117 #ifdef SV_RES_SETGET
118 	sv->res_get = sv_res_get;
119 	sv->res_set = sv_res_set;
120 #else
121 	sv->res_get = NULL; /* sv_res_get; */
122 	sv->res_set = NULL; /* sv_res_set; */
123 #endif
124 	return (sv);
125 }
126 
127 /* Methods */
128 
129 static void
130 sv_close(struct irs_sv *this) {
131 	struct pvt *pvt = (struct pvt *)this->private;
132 
133 	if (pvt->serv.s_aliases)
134 		free(pvt->serv.s_aliases);
135 	if (pvt->svbuf)
136 		free(pvt->svbuf);
137 
138 	if (pvt->res && pvt->free_res)
139 		(*pvt->free_res)(pvt->res);
140 	memput(pvt, sizeof *pvt);
141 	memput(this, sizeof *this);
142 }
143 
144 static struct servent *
145 sv_byname(struct irs_sv *this, const char *name, const char *proto) {
146 	struct pvt *pvt = (struct pvt *)this->private;
147 	struct dns_p *dns = pvt->dns;
148 	struct servent *s;
149 	char **hes_list;
150 
151 	if (!(hes_list = hesiod_resolve(dns->hes_ctx, name, "service")))
152 		return (NULL);
153 
154 	s = parse_hes_list(this, hes_list, proto);
155 	hesiod_free_list(dns->hes_ctx, hes_list);
156 	return (s);
157 }
158 
159 static struct servent *
160 sv_byport(struct irs_sv *this, int port, const char *proto) {
161 	struct pvt *pvt = (struct pvt *)this->private;
162 	struct dns_p *dns = pvt->dns;
163 	struct servent *s;
164 	char portstr[16];
165 	char **hes_list;
166 
167 	sprintf(portstr, "%d", ntohs(port));
168 	if (!(hes_list = hesiod_resolve(dns->hes_ctx, portstr, "port")))
169 		return (NULL);
170 
171 	s = parse_hes_list(this, hes_list, proto);
172 	hesiod_free_list(dns->hes_ctx, hes_list);
173 	return (s);
174 }
175 
176 static struct servent *
177 sv_next(struct irs_sv *this) {
178 	UNUSED(this);
179 	errno = ENODEV;
180 	return (NULL);
181 }
182 
183 static void
184 sv_rewind(struct irs_sv *this) {
185 	UNUSED(this);
186 	/* NOOP */
187 }
188 
189 /* Private */
190 
191 static struct servent *
192 parse_hes_list(struct irs_sv *this, char **hes_list, const char *proto) {
193 	struct pvt *pvt = (struct pvt *)this->private;
194 	char *p, *cp, **cpp, **new;
195 	int proto_len;
196 	int num = 0;
197 	int max = 0;
198 
199 	for (cpp = hes_list; *cpp; cpp++) {
200 		cp = *cpp;
201 
202 		/* Strip away comments, if any. */
203 		if ((p = strchr(cp, '#')))
204 			*p = 0;
205 
206 		/* Check to make sure the protocol matches. */
207 		p = cp;
208 		while (*p && !isspace((unsigned char)*p))
209 			p++;
210 		if (!*p)
211 			continue;
212 		if (proto) {
213 		     proto_len = strlen(proto);
214 		     if (strncasecmp(++p, proto, proto_len) != 0)
215 			  continue;
216 		     if (p[proto_len] && !isspace(p[proto_len]&0xff))
217 			  continue;
218 		}
219 		/* OK, we've got a live one.  Let's parse it for real. */
220 		if (pvt->svbuf)
221 			free(pvt->svbuf);
222 		pvt->svbuf = strdup(cp);
223 
224 		p = pvt->svbuf;
225 		pvt->serv.s_name = p;
226 		while (*p && !isspace(*p&0xff))
227 			p++;
228 		if (!*p)
229 			continue;
230 		*p++ = '\0';
231 
232 		pvt->serv.s_proto = p;
233 		while (*p && !isspace(*p&0xff))
234 			p++;
235 		if (!*p)
236 			continue;
237 		*p++ = '\0';
238 
239 		pvt->serv.s_port = htons((u_short) atoi(p));
240 		while (*p && !isspace(*p&0xff))
241 			p++;
242 		if (*p)
243 			*p++ = '\0';
244 
245 		while (*p) {
246 			if ((num + 1) >= max || !pvt->serv.s_aliases) {
247 				max += 10;
248 				new = realloc(pvt->serv.s_aliases,
249 					      max * sizeof(char *));
250 				if (!new) {
251 					errno = ENOMEM;
252 					goto cleanup;
253 				}
254 				pvt->serv.s_aliases = new;
255 			}
256 			pvt->serv.s_aliases[num++] = p;
257 			while (*p && !isspace(*p&0xff))
258 				p++;
259 			if (*p)
260 				*p++ = '\0';
261 		}
262 		if (!pvt->serv.s_aliases)
263 			pvt->serv.s_aliases = malloc(sizeof(char *));
264 		if (!pvt->serv.s_aliases)
265 			goto cleanup;
266 		pvt->serv.s_aliases[num] = NULL;
267 		return (&pvt->serv);
268 	}
269 
270  cleanup:
271 	if (pvt->serv.s_aliases) {
272 		free(pvt->serv.s_aliases);
273 		pvt->serv.s_aliases = NULL;
274 	}
275 	if (pvt->svbuf) {
276 		free(pvt->svbuf);
277 		pvt->svbuf = NULL;
278 	}
279 	return (NULL);
280 }
281 
282 static void
283 sv_minimize(struct irs_sv *this) {
284 	UNUSED(this);
285 	/* NOOP */
286 }
287 
288 #ifdef SV_RES_SETGET
289 static struct __res_state *
290 sv_res_get(struct irs_sv *this) {
291 	struct pvt *pvt = (struct pvt *)this->private;
292 	struct dns_p *dns = pvt->dns;
293 
294 	return (__hesiod_res_get(dns->hes_ctx));
295 }
296 
297 static void
298 sv_res_set(struct irs_sv *this, struct __res_state * res,
299 	   void (*free_res)(void *)) {
300 	struct pvt *pvt = (struct pvt *)this->private;
301 	struct dns_p *dns = pvt->dns;
302 
303 	__hesiod_res_set(dns->hes_ctx, res, free_res);
304 }
305 #endif
306