xref: /freebsd/lib/libcasper/services/cap_dns/cap_dns.c (revision 5c2bc3db201a4fe8d7911cf816bea104d5dc2138)
1c501d73cSMariusz Zaborski /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
328b6f7c8SMariusz Zaborski  *
4c501d73cSMariusz Zaborski  * Copyright (c) 2012-2013 The FreeBSD Foundation
5c501d73cSMariusz Zaborski  *
6c501d73cSMariusz Zaborski  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7c501d73cSMariusz Zaborski  * the FreeBSD Foundation.
8c501d73cSMariusz Zaborski  *
9c501d73cSMariusz Zaborski  * Redistribution and use in source and binary forms, with or without
10c501d73cSMariusz Zaborski  * modification, are permitted provided that the following conditions
11c501d73cSMariusz Zaborski  * are met:
12c501d73cSMariusz Zaborski  * 1. Redistributions of source code must retain the above copyright
13c501d73cSMariusz Zaborski  *    notice, this list of conditions and the following disclaimer.
14c501d73cSMariusz Zaborski  * 2. Redistributions in binary form must reproduce the above copyright
15c501d73cSMariusz Zaborski  *    notice, this list of conditions and the following disclaimer in the
16c501d73cSMariusz Zaborski  *    documentation and/or other materials provided with the distribution.
17c501d73cSMariusz Zaborski  *
18c501d73cSMariusz Zaborski  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19c501d73cSMariusz Zaborski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20c501d73cSMariusz Zaborski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21c501d73cSMariusz Zaborski  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22c501d73cSMariusz Zaborski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23c501d73cSMariusz Zaborski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24c501d73cSMariusz Zaborski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25c501d73cSMariusz Zaborski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26c501d73cSMariusz Zaborski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27c501d73cSMariusz Zaborski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28c501d73cSMariusz Zaborski  * SUCH DAMAGE.
29c501d73cSMariusz Zaborski  */
30c501d73cSMariusz Zaborski 
31c501d73cSMariusz Zaborski #include <sys/cdefs.h>
32c501d73cSMariusz Zaborski #include <sys/dnv.h>
33c501d73cSMariusz Zaborski #include <sys/nv.h>
34c501d73cSMariusz Zaborski #include <netinet/in.h>
35c501d73cSMariusz Zaborski 
36c501d73cSMariusz Zaborski #include <assert.h>
37c501d73cSMariusz Zaborski #include <errno.h>
38c501d73cSMariusz Zaborski #include <netdb.h>
39c501d73cSMariusz Zaborski #include <stdlib.h>
40c501d73cSMariusz Zaborski #include <string.h>
41c501d73cSMariusz Zaborski #include <unistd.h>
42c501d73cSMariusz Zaborski 
43c501d73cSMariusz Zaborski #include <libcasper.h>
44c501d73cSMariusz Zaborski #include <libcasper_service.h>
45c501d73cSMariusz Zaborski 
46c501d73cSMariusz Zaborski #include "cap_dns.h"
47c501d73cSMariusz Zaborski 
48c501d73cSMariusz Zaborski static struct hostent hent;
49c501d73cSMariusz Zaborski 
50c501d73cSMariusz Zaborski static void
51c501d73cSMariusz Zaborski hostent_free(struct hostent *hp)
52c501d73cSMariusz Zaborski {
53c501d73cSMariusz Zaborski 	unsigned int ii;
54c501d73cSMariusz Zaborski 
55c501d73cSMariusz Zaborski 	free(hp->h_name);
56c501d73cSMariusz Zaborski 	hp->h_name = NULL;
57c501d73cSMariusz Zaborski 	if (hp->h_aliases != NULL) {
58c501d73cSMariusz Zaborski 		for (ii = 0; hp->h_aliases[ii] != NULL; ii++)
59c501d73cSMariusz Zaborski 			free(hp->h_aliases[ii]);
60c501d73cSMariusz Zaborski 		free(hp->h_aliases);
61c501d73cSMariusz Zaborski 		hp->h_aliases = NULL;
62c501d73cSMariusz Zaborski 	}
63c501d73cSMariusz Zaborski 	if (hp->h_addr_list != NULL) {
64c501d73cSMariusz Zaborski 		for (ii = 0; hp->h_addr_list[ii] != NULL; ii++)
65c501d73cSMariusz Zaborski 			free(hp->h_addr_list[ii]);
66c501d73cSMariusz Zaborski 		free(hp->h_addr_list);
67c501d73cSMariusz Zaborski 		hp->h_addr_list = NULL;
68c501d73cSMariusz Zaborski 	}
69c501d73cSMariusz Zaborski }
70c501d73cSMariusz Zaborski 
71c501d73cSMariusz Zaborski static struct hostent *
72c501d73cSMariusz Zaborski hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
73c501d73cSMariusz Zaborski {
74c501d73cSMariusz Zaborski 	unsigned int ii, nitems;
75c501d73cSMariusz Zaborski 	char nvlname[64];
76c501d73cSMariusz Zaborski 	int n;
77c501d73cSMariusz Zaborski 
78c501d73cSMariusz Zaborski 	hostent_free(hp);
79c501d73cSMariusz Zaborski 
80c501d73cSMariusz Zaborski 	hp->h_name = strdup(nvlist_get_string(nvl, "name"));
81c501d73cSMariusz Zaborski 	if (hp->h_name == NULL)
82c501d73cSMariusz Zaborski 		goto fail;
83c501d73cSMariusz Zaborski 	hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype");
84c501d73cSMariusz Zaborski 	hp->h_length = (int)nvlist_get_number(nvl, "length");
85c501d73cSMariusz Zaborski 
86c501d73cSMariusz Zaborski 	nitems = (unsigned int)nvlist_get_number(nvl, "naliases");
87*5275d1ddSJohn Baldwin 	hp->h_aliases = calloc(nitems + 1, sizeof(hp->h_aliases[0]));
88c501d73cSMariusz Zaborski 	if (hp->h_aliases == NULL)
89c501d73cSMariusz Zaborski 		goto fail;
90c501d73cSMariusz Zaborski 	for (ii = 0; ii < nitems; ii++) {
91c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
92c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
93c501d73cSMariusz Zaborski 		hp->h_aliases[ii] =
94c501d73cSMariusz Zaborski 		    strdup(nvlist_get_string(nvl, nvlname));
95c501d73cSMariusz Zaborski 		if (hp->h_aliases[ii] == NULL)
96c501d73cSMariusz Zaborski 			goto fail;
97c501d73cSMariusz Zaborski 	}
98c501d73cSMariusz Zaborski 	hp->h_aliases[ii] = NULL;
99c501d73cSMariusz Zaborski 
100c501d73cSMariusz Zaborski 	nitems = (unsigned int)nvlist_get_number(nvl, "naddrs");
101*5275d1ddSJohn Baldwin 	hp->h_addr_list = calloc(nitems + 1, sizeof(hp->h_addr_list[0]));
102c501d73cSMariusz Zaborski 	if (hp->h_addr_list == NULL)
103c501d73cSMariusz Zaborski 		goto fail;
104c501d73cSMariusz Zaborski 	for (ii = 0; ii < nitems; ii++) {
105c501d73cSMariusz Zaborski 		hp->h_addr_list[ii] = malloc(hp->h_length);
106c501d73cSMariusz Zaborski 		if (hp->h_addr_list[ii] == NULL)
107c501d73cSMariusz Zaborski 			goto fail;
108c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
109c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
110c501d73cSMariusz Zaborski 		bcopy(nvlist_get_binary(nvl, nvlname, NULL),
111c501d73cSMariusz Zaborski 		    hp->h_addr_list[ii], hp->h_length);
112c501d73cSMariusz Zaborski 	}
113c501d73cSMariusz Zaborski 	hp->h_addr_list[ii] = NULL;
114c501d73cSMariusz Zaborski 
115c501d73cSMariusz Zaborski 	return (hp);
116c501d73cSMariusz Zaborski fail:
117c501d73cSMariusz Zaborski 	hostent_free(hp);
118c501d73cSMariusz Zaborski 	h_errno = NO_RECOVERY;
119c501d73cSMariusz Zaborski 	return (NULL);
120c501d73cSMariusz Zaborski }
121c501d73cSMariusz Zaborski 
122c501d73cSMariusz Zaborski struct hostent *
123c501d73cSMariusz Zaborski cap_gethostbyname(cap_channel_t *chan, const char *name)
124c501d73cSMariusz Zaborski {
125c501d73cSMariusz Zaborski 
126c501d73cSMariusz Zaborski 	return (cap_gethostbyname2(chan, name, AF_INET));
127c501d73cSMariusz Zaborski }
128c501d73cSMariusz Zaborski 
129c501d73cSMariusz Zaborski struct hostent *
130c501d73cSMariusz Zaborski cap_gethostbyname2(cap_channel_t *chan, const char *name, int type)
131c501d73cSMariusz Zaborski {
132c501d73cSMariusz Zaborski 	struct hostent *hp;
133c501d73cSMariusz Zaborski 	nvlist_t *nvl;
134c501d73cSMariusz Zaborski 
135c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
136c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "gethostbyname");
137c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "family", (uint64_t)type);
138c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "name", name);
1394fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
140c501d73cSMariusz Zaborski 	if (nvl == NULL) {
141c501d73cSMariusz Zaborski 		h_errno = NO_RECOVERY;
142c501d73cSMariusz Zaborski 		return (NULL);
143c501d73cSMariusz Zaborski 	}
144c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
145c501d73cSMariusz Zaborski 		h_errno = (int)nvlist_get_number(nvl, "error");
146c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
147c501d73cSMariusz Zaborski 		return (NULL);
148c501d73cSMariusz Zaborski 	}
149c501d73cSMariusz Zaborski 
150c501d73cSMariusz Zaborski 	hp = hostent_unpack(nvl, &hent);
151c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
152c501d73cSMariusz Zaborski 	return (hp);
153c501d73cSMariusz Zaborski }
154c501d73cSMariusz Zaborski 
155c501d73cSMariusz Zaborski struct hostent *
156c501d73cSMariusz Zaborski cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
157c501d73cSMariusz Zaborski     int type)
158c501d73cSMariusz Zaborski {
159c501d73cSMariusz Zaborski 	struct hostent *hp;
160c501d73cSMariusz Zaborski 	nvlist_t *nvl;
161c501d73cSMariusz Zaborski 
162c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
163c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "gethostbyaddr");
164c501d73cSMariusz Zaborski 	nvlist_add_binary(nvl, "addr", addr, (size_t)len);
165c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "family", (uint64_t)type);
1664fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
167c501d73cSMariusz Zaborski 	if (nvl == NULL) {
168c501d73cSMariusz Zaborski 		h_errno = NO_RECOVERY;
169c501d73cSMariusz Zaborski 		return (NULL);
170c501d73cSMariusz Zaborski 	}
171c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
172c501d73cSMariusz Zaborski 		h_errno = (int)nvlist_get_number(nvl, "error");
173c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
174c501d73cSMariusz Zaborski 		return (NULL);
175c501d73cSMariusz Zaborski 	}
176c501d73cSMariusz Zaborski 	hp = hostent_unpack(nvl, &hent);
177c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
178c501d73cSMariusz Zaborski 	return (hp);
179c501d73cSMariusz Zaborski }
180c501d73cSMariusz Zaborski 
181c501d73cSMariusz Zaborski static struct addrinfo *
182c501d73cSMariusz Zaborski addrinfo_unpack(const nvlist_t *nvl)
183c501d73cSMariusz Zaborski {
184c501d73cSMariusz Zaborski 	struct addrinfo *ai;
185c501d73cSMariusz Zaborski 	const void *addr;
186c501d73cSMariusz Zaborski 	size_t addrlen;
187c501d73cSMariusz Zaborski 	const char *canonname;
188c501d73cSMariusz Zaborski 
189c501d73cSMariusz Zaborski 	addr = nvlist_get_binary(nvl, "ai_addr", &addrlen);
190c501d73cSMariusz Zaborski 	ai = malloc(sizeof(*ai) + addrlen);
191c501d73cSMariusz Zaborski 	if (ai == NULL)
192c501d73cSMariusz Zaborski 		return (NULL);
193c501d73cSMariusz Zaborski 	ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags");
194c501d73cSMariusz Zaborski 	ai->ai_family = (int)nvlist_get_number(nvl, "ai_family");
195c501d73cSMariusz Zaborski 	ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype");
196c501d73cSMariusz Zaborski 	ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol");
197c501d73cSMariusz Zaborski 	ai->ai_addrlen = (socklen_t)addrlen;
198c501d73cSMariusz Zaborski 	canonname = dnvlist_get_string(nvl, "ai_canonname", NULL);
199c501d73cSMariusz Zaborski 	if (canonname != NULL) {
200c501d73cSMariusz Zaborski 		ai->ai_canonname = strdup(canonname);
201c501d73cSMariusz Zaborski 		if (ai->ai_canonname == NULL) {
202c501d73cSMariusz Zaborski 			free(ai);
203c501d73cSMariusz Zaborski 			return (NULL);
204c501d73cSMariusz Zaborski 		}
205c501d73cSMariusz Zaborski 	} else {
206c501d73cSMariusz Zaborski 		ai->ai_canonname = NULL;
207c501d73cSMariusz Zaborski 	}
208c501d73cSMariusz Zaborski 	ai->ai_addr = (void *)(ai + 1);
209c501d73cSMariusz Zaborski 	bcopy(addr, ai->ai_addr, addrlen);
210c501d73cSMariusz Zaborski 	ai->ai_next = NULL;
211c501d73cSMariusz Zaborski 
212c501d73cSMariusz Zaborski 	return (ai);
213c501d73cSMariusz Zaborski }
214c501d73cSMariusz Zaborski 
215c501d73cSMariusz Zaborski int
216c501d73cSMariusz Zaborski cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
217c501d73cSMariusz Zaborski     const struct addrinfo *hints, struct addrinfo **res)
218c501d73cSMariusz Zaborski {
219c501d73cSMariusz Zaborski 	struct addrinfo *firstai, *prevai, *curai;
220c501d73cSMariusz Zaborski 	unsigned int ii;
221c501d73cSMariusz Zaborski 	const nvlist_t *nvlai;
222c501d73cSMariusz Zaborski 	char nvlname[64];
223c501d73cSMariusz Zaborski 	nvlist_t *nvl;
224c501d73cSMariusz Zaborski 	int error, n;
225c501d73cSMariusz Zaborski 
226c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
227c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "getaddrinfo");
228c501d73cSMariusz Zaborski 	if (hostname != NULL)
229c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "hostname", hostname);
230c501d73cSMariusz Zaborski 	if (servname != NULL)
231c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "servname", servname);
232c501d73cSMariusz Zaborski 	if (hints != NULL) {
233c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_flags",
234c501d73cSMariusz Zaborski 		    (uint64_t)hints->ai_flags);
235c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_family",
236c501d73cSMariusz Zaborski 		    (uint64_t)hints->ai_family);
237c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_socktype",
238c501d73cSMariusz Zaborski 		    (uint64_t)hints->ai_socktype);
239c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_protocol",
240c501d73cSMariusz Zaborski 		    (uint64_t)hints->ai_protocol);
241c501d73cSMariusz Zaborski 	}
2424fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
243c501d73cSMariusz Zaborski 	if (nvl == NULL)
244c501d73cSMariusz Zaborski 		return (EAI_MEMORY);
245c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
246c501d73cSMariusz Zaborski 		error = (int)nvlist_get_number(nvl, "error");
247c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
248c501d73cSMariusz Zaborski 		return (error);
249c501d73cSMariusz Zaborski 	}
250c501d73cSMariusz Zaborski 
251c501d73cSMariusz Zaborski 	nvlai = NULL;
252c501d73cSMariusz Zaborski 	firstai = prevai = curai = NULL;
253c501d73cSMariusz Zaborski 	for (ii = 0; ; ii++) {
254c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
255c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
256c501d73cSMariusz Zaborski 		if (!nvlist_exists_nvlist(nvl, nvlname))
257c501d73cSMariusz Zaborski 			break;
258c501d73cSMariusz Zaborski 		nvlai = nvlist_get_nvlist(nvl, nvlname);
259c501d73cSMariusz Zaborski 		curai = addrinfo_unpack(nvlai);
260c501d73cSMariusz Zaborski 		if (curai == NULL)
261c501d73cSMariusz Zaborski 			break;
262c501d73cSMariusz Zaborski 		if (prevai != NULL)
263c501d73cSMariusz Zaborski 			prevai->ai_next = curai;
264c501d73cSMariusz Zaborski 		else if (firstai == NULL)
265c501d73cSMariusz Zaborski 			firstai = curai;
266c501d73cSMariusz Zaborski 		prevai = curai;
267c501d73cSMariusz Zaborski 	}
268c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
269c501d73cSMariusz Zaborski 	if (curai == NULL && nvlai != NULL) {
270c501d73cSMariusz Zaborski 		if (firstai == NULL)
271c501d73cSMariusz Zaborski 			freeaddrinfo(firstai);
272c501d73cSMariusz Zaborski 		return (EAI_MEMORY);
273c501d73cSMariusz Zaborski 	}
274c501d73cSMariusz Zaborski 
275c501d73cSMariusz Zaborski 	*res = firstai;
276c501d73cSMariusz Zaborski 	return (0);
277c501d73cSMariusz Zaborski }
278c501d73cSMariusz Zaborski 
279c501d73cSMariusz Zaborski int
280c501d73cSMariusz Zaborski cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
281c501d73cSMariusz Zaborski     char *host, size_t hostlen, char *serv, size_t servlen, int flags)
282c501d73cSMariusz Zaborski {
283c501d73cSMariusz Zaborski 	nvlist_t *nvl;
284c501d73cSMariusz Zaborski 	int error;
285c501d73cSMariusz Zaborski 
286c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
287c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "getnameinfo");
288c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen);
289c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
290c501d73cSMariusz Zaborski 	nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
291c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "flags", (uint64_t)flags);
2924fc0a279SMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
293c501d73cSMariusz Zaborski 	if (nvl == NULL)
294c501d73cSMariusz Zaborski 		return (EAI_MEMORY);
295c501d73cSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
296c501d73cSMariusz Zaborski 		error = (int)nvlist_get_number(nvl, "error");
297c501d73cSMariusz Zaborski 		nvlist_destroy(nvl);
298c501d73cSMariusz Zaborski 		return (error);
299c501d73cSMariusz Zaborski 	}
300c501d73cSMariusz Zaborski 
301c501d73cSMariusz Zaborski 	if (host != NULL && nvlist_exists_string(nvl, "host"))
302179bffddSEric van Gyzen 		strlcpy(host, nvlist_get_string(nvl, "host"), hostlen);
303c501d73cSMariusz Zaborski 	if (serv != NULL && nvlist_exists_string(nvl, "serv"))
304179bffddSEric van Gyzen 		strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen);
305c501d73cSMariusz Zaborski 	nvlist_destroy(nvl);
306c501d73cSMariusz Zaborski 	return (0);
307c501d73cSMariusz Zaborski }
308c501d73cSMariusz Zaborski 
309c501d73cSMariusz Zaborski static void
310c501d73cSMariusz Zaborski limit_remove(nvlist_t *limits, const char *prefix)
311c501d73cSMariusz Zaborski {
312c501d73cSMariusz Zaborski 	const char *name;
313c501d73cSMariusz Zaborski 	size_t prefixlen;
314c501d73cSMariusz Zaborski 	void *cookie;
315c501d73cSMariusz Zaborski 
316c501d73cSMariusz Zaborski 	prefixlen = strlen(prefix);
317c501d73cSMariusz Zaborski again:
318c501d73cSMariusz Zaborski 	cookie = NULL;
319c501d73cSMariusz Zaborski 	while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
320c501d73cSMariusz Zaborski 		if (strncmp(name, prefix, prefixlen) == 0) {
321c501d73cSMariusz Zaborski 			nvlist_free(limits, name);
322c501d73cSMariusz Zaborski 			goto again;
323c501d73cSMariusz Zaborski 		}
324c501d73cSMariusz Zaborski 	}
325c501d73cSMariusz Zaborski }
326c501d73cSMariusz Zaborski 
327c501d73cSMariusz Zaborski int
328c501d73cSMariusz Zaborski cap_dns_type_limit(cap_channel_t *chan, const char * const *types,
329c501d73cSMariusz Zaborski     size_t ntypes)
330c501d73cSMariusz Zaborski {
331c501d73cSMariusz Zaborski 	nvlist_t *limits;
332c501d73cSMariusz Zaborski 	unsigned int i;
333c501d73cSMariusz Zaborski 	char nvlname[64];
334c501d73cSMariusz Zaborski 	int n;
335c501d73cSMariusz Zaborski 
336c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
337c501d73cSMariusz Zaborski 		return (-1);
338c501d73cSMariusz Zaborski 	if (limits == NULL)
339c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
340c501d73cSMariusz Zaborski 	else
341c501d73cSMariusz Zaborski 		limit_remove(limits, "type");
342c501d73cSMariusz Zaborski 	for (i = 0; i < ntypes; i++) {
343c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "type%u", i);
344c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
345c501d73cSMariusz Zaborski 		nvlist_add_string(limits, nvlname, types[i]);
346c501d73cSMariusz Zaborski 	}
347c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
348c501d73cSMariusz Zaborski }
349c501d73cSMariusz Zaborski 
350c501d73cSMariusz Zaborski int
351c501d73cSMariusz Zaborski cap_dns_family_limit(cap_channel_t *chan, const int *families,
352c501d73cSMariusz Zaborski     size_t nfamilies)
353c501d73cSMariusz Zaborski {
354c501d73cSMariusz Zaborski 	nvlist_t *limits;
355c501d73cSMariusz Zaborski 	unsigned int i;
356c501d73cSMariusz Zaborski 	char nvlname[64];
357c501d73cSMariusz Zaborski 	int n;
358c501d73cSMariusz Zaborski 
359c501d73cSMariusz Zaborski 	if (cap_limit_get(chan, &limits) < 0)
360c501d73cSMariusz Zaborski 		return (-1);
361c501d73cSMariusz Zaborski 	if (limits == NULL)
362c501d73cSMariusz Zaborski 		limits = nvlist_create(0);
363c501d73cSMariusz Zaborski 	else
364c501d73cSMariusz Zaborski 		limit_remove(limits, "family");
365c501d73cSMariusz Zaborski 	for (i = 0; i < nfamilies; i++) {
366c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "family%u", i);
367c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
368c501d73cSMariusz Zaborski 		nvlist_add_number(limits, nvlname, (uint64_t)families[i]);
369c501d73cSMariusz Zaborski 	}
370c501d73cSMariusz Zaborski 	return (cap_limit_set(chan, limits));
371c501d73cSMariusz Zaborski }
372c501d73cSMariusz Zaborski 
373c501d73cSMariusz Zaborski /*
374c501d73cSMariusz Zaborski  * Service functions.
375c501d73cSMariusz Zaborski  */
376c501d73cSMariusz Zaborski static bool
377c501d73cSMariusz Zaborski dns_allowed_type(const nvlist_t *limits, const char *type)
378c501d73cSMariusz Zaborski {
379c501d73cSMariusz Zaborski 	const char *name;
380c501d73cSMariusz Zaborski 	bool notypes;
381c501d73cSMariusz Zaborski 	void *cookie;
382c501d73cSMariusz Zaborski 
383c501d73cSMariusz Zaborski 	if (limits == NULL)
384c501d73cSMariusz Zaborski 		return (true);
385c501d73cSMariusz Zaborski 
386c501d73cSMariusz Zaborski 	notypes = true;
387c501d73cSMariusz Zaborski 	cookie = NULL;
388c501d73cSMariusz Zaborski 	while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
389c501d73cSMariusz Zaborski 		if (strncmp(name, "type", sizeof("type") - 1) != 0)
390c501d73cSMariusz Zaborski 			continue;
391c501d73cSMariusz Zaborski 		notypes = false;
392c501d73cSMariusz Zaborski 		if (strcmp(nvlist_get_string(limits, name), type) == 0)
393c501d73cSMariusz Zaborski 			return (true);
394c501d73cSMariusz Zaborski 	}
395c501d73cSMariusz Zaborski 
396c501d73cSMariusz Zaborski 	/* If there are no types at all, allow any type. */
397c501d73cSMariusz Zaborski 	if (notypes)
398c501d73cSMariusz Zaborski 		return (true);
399c501d73cSMariusz Zaborski 
400c501d73cSMariusz Zaborski 	return (false);
401c501d73cSMariusz Zaborski }
402c501d73cSMariusz Zaborski 
403c501d73cSMariusz Zaborski static bool
404c501d73cSMariusz Zaborski dns_allowed_family(const nvlist_t *limits, int family)
405c501d73cSMariusz Zaborski {
406c501d73cSMariusz Zaborski 	const char *name;
407c501d73cSMariusz Zaborski 	bool nofamilies;
408c501d73cSMariusz Zaborski 	void *cookie;
409c501d73cSMariusz Zaborski 
410c501d73cSMariusz Zaborski 	if (limits == NULL)
411c501d73cSMariusz Zaborski 		return (true);
412c501d73cSMariusz Zaborski 
413c501d73cSMariusz Zaborski 	nofamilies = true;
414c501d73cSMariusz Zaborski 	cookie = NULL;
415c501d73cSMariusz Zaborski 	while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
416c501d73cSMariusz Zaborski 		if (strncmp(name, "family", sizeof("family") - 1) != 0)
417c501d73cSMariusz Zaborski 			continue;
418c501d73cSMariusz Zaborski 		nofamilies = false;
419c501d73cSMariusz Zaborski 		if (family == AF_UNSPEC)
420c501d73cSMariusz Zaborski 			continue;
421c501d73cSMariusz Zaborski 		if (nvlist_get_number(limits, name) == (uint64_t)family)
422c501d73cSMariusz Zaborski 			return (true);
423c501d73cSMariusz Zaborski 	}
424c501d73cSMariusz Zaborski 
425c501d73cSMariusz Zaborski 	/* If there are no families at all, allow any family. */
426c501d73cSMariusz Zaborski 	if (nofamilies)
427c501d73cSMariusz Zaborski 		return (true);
428c501d73cSMariusz Zaborski 
429c501d73cSMariusz Zaborski 	return (false);
430c501d73cSMariusz Zaborski }
431c501d73cSMariusz Zaborski 
432c501d73cSMariusz Zaborski static void
433c501d73cSMariusz Zaborski hostent_pack(const struct hostent *hp, nvlist_t *nvl)
434c501d73cSMariusz Zaborski {
435c501d73cSMariusz Zaborski 	unsigned int ii;
436c501d73cSMariusz Zaborski 	char nvlname[64];
437c501d73cSMariusz Zaborski 	int n;
438c501d73cSMariusz Zaborski 
439c501d73cSMariusz Zaborski 	nvlist_add_string(nvl, "name", hp->h_name);
440c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype);
441c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "length", (uint64_t)hp->h_length);
442c501d73cSMariusz Zaborski 
443c501d73cSMariusz Zaborski 	if (hp->h_aliases == NULL) {
444c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "naliases", 0);
445c501d73cSMariusz Zaborski 	} else {
446c501d73cSMariusz Zaborski 		for (ii = 0; hp->h_aliases[ii] != NULL; ii++) {
447c501d73cSMariusz Zaborski 			n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
448c501d73cSMariusz Zaborski 			assert(n > 0 && n < (int)sizeof(nvlname));
449c501d73cSMariusz Zaborski 			nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]);
450c501d73cSMariusz Zaborski 		}
451c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "naliases", (uint64_t)ii);
452c501d73cSMariusz Zaborski 	}
453c501d73cSMariusz Zaborski 
454c501d73cSMariusz Zaborski 	if (hp->h_addr_list == NULL) {
455c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "naddrs", 0);
456c501d73cSMariusz Zaborski 	} else {
457c501d73cSMariusz Zaborski 		for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) {
458c501d73cSMariusz Zaborski 			n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
459c501d73cSMariusz Zaborski 			assert(n > 0 && n < (int)sizeof(nvlname));
460c501d73cSMariusz Zaborski 			nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii],
461c501d73cSMariusz Zaborski 			    (size_t)hp->h_length);
462c501d73cSMariusz Zaborski 		}
463c501d73cSMariusz Zaborski 		nvlist_add_number(nvl, "naddrs", (uint64_t)ii);
464c501d73cSMariusz Zaborski 	}
465c501d73cSMariusz Zaborski }
466c501d73cSMariusz Zaborski 
467c501d73cSMariusz Zaborski static int
468c501d73cSMariusz Zaborski dns_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin,
469c501d73cSMariusz Zaborski     nvlist_t *nvlout)
470c501d73cSMariusz Zaborski {
471c501d73cSMariusz Zaborski 	struct hostent *hp;
472c501d73cSMariusz Zaborski 	int family;
473c501d73cSMariusz Zaborski 
4742863fd2fSMariusz Zaborski 	if (!dns_allowed_type(limits, "NAME2ADDR") &&
4752863fd2fSMariusz Zaborski 	    !dns_allowed_type(limits, "NAME"))
476c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
477c501d73cSMariusz Zaborski 
478c501d73cSMariusz Zaborski 	family = (int)nvlist_get_number(nvlin, "family");
479c501d73cSMariusz Zaborski 
480c501d73cSMariusz Zaborski 	if (!dns_allowed_family(limits, family))
481c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
482c501d73cSMariusz Zaborski 
483c501d73cSMariusz Zaborski 	hp = gethostbyname2(nvlist_get_string(nvlin, "name"), family);
484c501d73cSMariusz Zaborski 	if (hp == NULL)
485c501d73cSMariusz Zaborski 		return (h_errno);
486c501d73cSMariusz Zaborski 	hostent_pack(hp, nvlout);
487c501d73cSMariusz Zaborski 	return (0);
488c501d73cSMariusz Zaborski }
489c501d73cSMariusz Zaborski 
490c501d73cSMariusz Zaborski static int
491c501d73cSMariusz Zaborski dns_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin,
492c501d73cSMariusz Zaborski     nvlist_t *nvlout)
493c501d73cSMariusz Zaborski {
494c501d73cSMariusz Zaborski 	struct hostent *hp;
495c501d73cSMariusz Zaborski 	const void *addr;
496c501d73cSMariusz Zaborski 	size_t addrsize;
497c501d73cSMariusz Zaborski 	int family;
498c501d73cSMariusz Zaborski 
4992863fd2fSMariusz Zaborski 	if (!dns_allowed_type(limits, "ADDR2NAME") &&
5002863fd2fSMariusz Zaborski 	    !dns_allowed_type(limits, "ADDR"))
501c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
502c501d73cSMariusz Zaborski 
503c501d73cSMariusz Zaborski 	family = (int)nvlist_get_number(nvlin, "family");
504c501d73cSMariusz Zaborski 
505c501d73cSMariusz Zaborski 	if (!dns_allowed_family(limits, family))
506c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
507c501d73cSMariusz Zaborski 
508c501d73cSMariusz Zaborski 	addr = nvlist_get_binary(nvlin, "addr", &addrsize);
509c501d73cSMariusz Zaborski 	hp = gethostbyaddr(addr, (socklen_t)addrsize, family);
510c501d73cSMariusz Zaborski 	if (hp == NULL)
511c501d73cSMariusz Zaborski 		return (h_errno);
512c501d73cSMariusz Zaborski 	hostent_pack(hp, nvlout);
513c501d73cSMariusz Zaborski 	return (0);
514c501d73cSMariusz Zaborski }
515c501d73cSMariusz Zaborski 
516c501d73cSMariusz Zaborski static int
517c501d73cSMariusz Zaborski dns_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
518c501d73cSMariusz Zaborski {
519c501d73cSMariusz Zaborski 	struct sockaddr_storage sast;
520c501d73cSMariusz Zaborski 	const void *sabin;
521c501d73cSMariusz Zaborski 	char *host, *serv;
522c501d73cSMariusz Zaborski 	size_t sabinsize, hostlen, servlen;
523c501d73cSMariusz Zaborski 	socklen_t salen;
524c501d73cSMariusz Zaborski 	int error, flags;
525c501d73cSMariusz Zaborski 
5262863fd2fSMariusz Zaborski 	if (!dns_allowed_type(limits, "ADDR2NAME") &&
5272863fd2fSMariusz Zaborski 	    !dns_allowed_type(limits, "ADDR"))
528c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
529c501d73cSMariusz Zaborski 
530c501d73cSMariusz Zaborski 	error = 0;
531c501d73cSMariusz Zaborski 	host = serv = NULL;
532c501d73cSMariusz Zaborski 	memset(&sast, 0, sizeof(sast));
533c501d73cSMariusz Zaborski 
534c501d73cSMariusz Zaborski 	hostlen = (size_t)nvlist_get_number(nvlin, "hostlen");
535c501d73cSMariusz Zaborski 	servlen = (size_t)nvlist_get_number(nvlin, "servlen");
536c501d73cSMariusz Zaborski 
537c501d73cSMariusz Zaborski 	if (hostlen > 0) {
538179bffddSEric van Gyzen 		host = calloc(1, hostlen);
539c501d73cSMariusz Zaborski 		if (host == NULL) {
540c501d73cSMariusz Zaborski 			error = EAI_MEMORY;
541c501d73cSMariusz Zaborski 			goto out;
542c501d73cSMariusz Zaborski 		}
543c501d73cSMariusz Zaborski 	}
544c501d73cSMariusz Zaborski 	if (servlen > 0) {
545179bffddSEric van Gyzen 		serv = calloc(1, servlen);
546c501d73cSMariusz Zaborski 		if (serv == NULL) {
547c501d73cSMariusz Zaborski 			error = EAI_MEMORY;
548c501d73cSMariusz Zaborski 			goto out;
549c501d73cSMariusz Zaborski 		}
550c501d73cSMariusz Zaborski 	}
551c501d73cSMariusz Zaborski 
552c501d73cSMariusz Zaborski 	sabin = nvlist_get_binary(nvlin, "sa", &sabinsize);
553c501d73cSMariusz Zaborski 	if (sabinsize > sizeof(sast)) {
554c501d73cSMariusz Zaborski 		error = EAI_FAIL;
555c501d73cSMariusz Zaborski 		goto out;
556c501d73cSMariusz Zaborski 	}
557c501d73cSMariusz Zaborski 
558c501d73cSMariusz Zaborski 	memcpy(&sast, sabin, sabinsize);
559c501d73cSMariusz Zaborski 	salen = (socklen_t)sabinsize;
560c501d73cSMariusz Zaborski 
561c501d73cSMariusz Zaborski 	if ((sast.ss_family != AF_INET ||
562c501d73cSMariusz Zaborski 	     salen != sizeof(struct sockaddr_in)) &&
563c501d73cSMariusz Zaborski 	    (sast.ss_family != AF_INET6 ||
564c501d73cSMariusz Zaborski 	     salen != sizeof(struct sockaddr_in6))) {
565c501d73cSMariusz Zaborski 		error = EAI_FAIL;
566c501d73cSMariusz Zaborski 		goto out;
567c501d73cSMariusz Zaborski 	}
568c501d73cSMariusz Zaborski 
569c501d73cSMariusz Zaborski 	if (!dns_allowed_family(limits, (int)sast.ss_family)) {
570c501d73cSMariusz Zaborski 		error = NO_RECOVERY;
571c501d73cSMariusz Zaborski 		goto out;
572c501d73cSMariusz Zaborski 	}
573c501d73cSMariusz Zaborski 
574c501d73cSMariusz Zaborski 	flags = (int)nvlist_get_number(nvlin, "flags");
575c501d73cSMariusz Zaborski 
576c501d73cSMariusz Zaborski 	error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen,
577c501d73cSMariusz Zaborski 	    serv, servlen, flags);
578c501d73cSMariusz Zaborski 	if (error != 0)
579c501d73cSMariusz Zaborski 		goto out;
580c501d73cSMariusz Zaborski 
581c501d73cSMariusz Zaborski 	if (host != NULL)
582c501d73cSMariusz Zaborski 		nvlist_move_string(nvlout, "host", host);
583c501d73cSMariusz Zaborski 	if (serv != NULL)
584c501d73cSMariusz Zaborski 		nvlist_move_string(nvlout, "serv", serv);
585c501d73cSMariusz Zaborski out:
586c501d73cSMariusz Zaborski 	if (error != 0) {
587c501d73cSMariusz Zaborski 		free(host);
588c501d73cSMariusz Zaborski 		free(serv);
589c501d73cSMariusz Zaborski 	}
590c501d73cSMariusz Zaborski 	return (error);
591c501d73cSMariusz Zaborski }
592c501d73cSMariusz Zaborski 
593c501d73cSMariusz Zaborski static nvlist_t *
594c501d73cSMariusz Zaborski addrinfo_pack(const struct addrinfo *ai)
595c501d73cSMariusz Zaborski {
596c501d73cSMariusz Zaborski 	nvlist_t *nvl;
597c501d73cSMariusz Zaborski 
598c501d73cSMariusz Zaborski 	nvl = nvlist_create(0);
599c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags);
600c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family);
601c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype);
602c501d73cSMariusz Zaborski 	nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol);
603c501d73cSMariusz Zaborski 	nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen);
604c501d73cSMariusz Zaborski 	if (ai->ai_canonname != NULL)
605c501d73cSMariusz Zaborski 		nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname);
606c501d73cSMariusz Zaborski 
607c501d73cSMariusz Zaborski 	return (nvl);
608c501d73cSMariusz Zaborski }
609c501d73cSMariusz Zaborski 
610c501d73cSMariusz Zaborski static int
611c501d73cSMariusz Zaborski dns_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
612c501d73cSMariusz Zaborski {
613c501d73cSMariusz Zaborski 	struct addrinfo hints, *hintsp, *res, *cur;
614c501d73cSMariusz Zaborski 	const char *hostname, *servname;
615c501d73cSMariusz Zaborski 	char nvlname[64];
616c501d73cSMariusz Zaborski 	nvlist_t *elem;
617c501d73cSMariusz Zaborski 	unsigned int ii;
618c501d73cSMariusz Zaborski 	int error, family, n;
619c501d73cSMariusz Zaborski 
6202863fd2fSMariusz Zaborski 	if (!dns_allowed_type(limits, "NAME2ADDR") &&
6212863fd2fSMariusz Zaborski 	    !dns_allowed_type(limits, "NAME"))
622c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
623c501d73cSMariusz Zaborski 
624c501d73cSMariusz Zaborski 	hostname = dnvlist_get_string(nvlin, "hostname", NULL);
625c501d73cSMariusz Zaborski 	servname = dnvlist_get_string(nvlin, "servname", NULL);
626c501d73cSMariusz Zaborski 	if (nvlist_exists_number(nvlin, "hints.ai_flags")) {
627c501d73cSMariusz Zaborski 		hints.ai_flags = (int)nvlist_get_number(nvlin,
628c501d73cSMariusz Zaborski 		    "hints.ai_flags");
629c501d73cSMariusz Zaborski 		hints.ai_family = (int)nvlist_get_number(nvlin,
630c501d73cSMariusz Zaborski 		    "hints.ai_family");
631c501d73cSMariusz Zaborski 		hints.ai_socktype = (int)nvlist_get_number(nvlin,
632c501d73cSMariusz Zaborski 		    "hints.ai_socktype");
633c501d73cSMariusz Zaborski 		hints.ai_protocol = (int)nvlist_get_number(nvlin,
634c501d73cSMariusz Zaborski 		    "hints.ai_protocol");
635c501d73cSMariusz Zaborski 		hints.ai_addrlen = 0;
636c501d73cSMariusz Zaborski 		hints.ai_addr = NULL;
637c501d73cSMariusz Zaborski 		hints.ai_canonname = NULL;
6387f6a709bSMariusz Zaborski 		hints.ai_next = NULL;
639c501d73cSMariusz Zaborski 		hintsp = &hints;
640c501d73cSMariusz Zaborski 		family = hints.ai_family;
641c501d73cSMariusz Zaborski 	} else {
642c501d73cSMariusz Zaborski 		hintsp = NULL;
643c501d73cSMariusz Zaborski 		family = AF_UNSPEC;
644c501d73cSMariusz Zaborski 	}
645c501d73cSMariusz Zaborski 
646c501d73cSMariusz Zaborski 	if (!dns_allowed_family(limits, family))
647c501d73cSMariusz Zaborski 		return (NO_RECOVERY);
648c501d73cSMariusz Zaborski 
649c501d73cSMariusz Zaborski 	error = getaddrinfo(hostname, servname, hintsp, &res);
650c501d73cSMariusz Zaborski 	if (error != 0)
651c501d73cSMariusz Zaborski 		goto out;
652c501d73cSMariusz Zaborski 
653c501d73cSMariusz Zaborski 	for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) {
654c501d73cSMariusz Zaborski 		elem = addrinfo_pack(cur);
655c501d73cSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
656c501d73cSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
657c501d73cSMariusz Zaborski 		nvlist_move_nvlist(nvlout, nvlname, elem);
658c501d73cSMariusz Zaborski 	}
659c501d73cSMariusz Zaborski 
660c501d73cSMariusz Zaborski 	freeaddrinfo(res);
661c501d73cSMariusz Zaborski 	error = 0;
662c501d73cSMariusz Zaborski out:
663c501d73cSMariusz Zaborski 	return (error);
664c501d73cSMariusz Zaborski }
665c501d73cSMariusz Zaborski 
666c501d73cSMariusz Zaborski static bool
667c501d73cSMariusz Zaborski limit_has_entry(const nvlist_t *limits, const char *prefix)
668c501d73cSMariusz Zaborski {
669c501d73cSMariusz Zaborski 	const char *name;
670c501d73cSMariusz Zaborski 	size_t prefixlen;
671c501d73cSMariusz Zaborski 	void *cookie;
672c501d73cSMariusz Zaborski 
673c501d73cSMariusz Zaborski 	if (limits == NULL)
674c501d73cSMariusz Zaborski 		return (false);
675c501d73cSMariusz Zaborski 
676c501d73cSMariusz Zaborski 	prefixlen = strlen(prefix);
677c501d73cSMariusz Zaborski 
678c501d73cSMariusz Zaborski 	cookie = NULL;
679c501d73cSMariusz Zaborski 	while ((name = nvlist_next(limits, NULL, &cookie)) != NULL) {
680c501d73cSMariusz Zaborski 		if (strncmp(name, prefix, prefixlen) == 0)
681c501d73cSMariusz Zaborski 			return (true);
682c501d73cSMariusz Zaborski 	}
683c501d73cSMariusz Zaborski 
684c501d73cSMariusz Zaborski 	return (false);
685c501d73cSMariusz Zaborski }
686c501d73cSMariusz Zaborski 
687c501d73cSMariusz Zaborski static int
688c501d73cSMariusz Zaborski dns_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
689c501d73cSMariusz Zaborski {
690c501d73cSMariusz Zaborski 	const char *name;
691c501d73cSMariusz Zaborski 	void *cookie;
692c501d73cSMariusz Zaborski 	int nvtype;
693c501d73cSMariusz Zaborski 	bool hastype, hasfamily;
694c501d73cSMariusz Zaborski 
695c501d73cSMariusz Zaborski 	hastype = false;
696c501d73cSMariusz Zaborski 	hasfamily = false;
697c501d73cSMariusz Zaborski 
698c501d73cSMariusz Zaborski 	cookie = NULL;
699c501d73cSMariusz Zaborski 	while ((name = nvlist_next(newlimits, &nvtype, &cookie)) != NULL) {
700c501d73cSMariusz Zaborski 		if (nvtype == NV_TYPE_STRING) {
701c501d73cSMariusz Zaborski 			const char *type;
702c501d73cSMariusz Zaborski 
703c501d73cSMariusz Zaborski 			if (strncmp(name, "type", sizeof("type") - 1) != 0)
704c501d73cSMariusz Zaborski 				return (EINVAL);
705c501d73cSMariusz Zaborski 			type = nvlist_get_string(newlimits, name);
706752d135eSMariusz Zaborski 			if (strcmp(type, "ADDR2NAME") != 0 &&
7072863fd2fSMariusz Zaborski 			    strcmp(type, "NAME2ADDR") != 0 &&
7082863fd2fSMariusz Zaborski 			    strcmp(type, "ADDR") != 0 &&
7092863fd2fSMariusz Zaborski 			    strcmp(type, "NAME") != 0) {
710c501d73cSMariusz Zaborski 				return (EINVAL);
711c501d73cSMariusz Zaborski 			}
712c501d73cSMariusz Zaborski 			if (!dns_allowed_type(oldlimits, type))
713c501d73cSMariusz Zaborski 				return (ENOTCAPABLE);
714c501d73cSMariusz Zaborski 			hastype = true;
715c501d73cSMariusz Zaborski 		} else if (nvtype == NV_TYPE_NUMBER) {
716c501d73cSMariusz Zaborski 			int family;
717c501d73cSMariusz Zaborski 
718c501d73cSMariusz Zaborski 			if (strncmp(name, "family", sizeof("family") - 1) != 0)
719c501d73cSMariusz Zaborski 				return (EINVAL);
720c501d73cSMariusz Zaborski 			family = (int)nvlist_get_number(newlimits, name);
721c501d73cSMariusz Zaborski 			if (!dns_allowed_family(oldlimits, family))
722c501d73cSMariusz Zaborski 				return (ENOTCAPABLE);
723c501d73cSMariusz Zaborski 			hasfamily = true;
724c501d73cSMariusz Zaborski 		} else {
725c501d73cSMariusz Zaborski 			return (EINVAL);
726c501d73cSMariusz Zaborski 		}
727c501d73cSMariusz Zaborski 	}
728c501d73cSMariusz Zaborski 
729c501d73cSMariusz Zaborski 	/*
730c501d73cSMariusz Zaborski 	 * If the new limit doesn't mention type or family we have to
731c501d73cSMariusz Zaborski 	 * check if the current limit does have those. Missing type or
732c501d73cSMariusz Zaborski 	 * family in the limit means that all types or families are
733c501d73cSMariusz Zaborski 	 * allowed.
734c501d73cSMariusz Zaborski 	 */
735c501d73cSMariusz Zaborski 	if (!hastype) {
736c501d73cSMariusz Zaborski 		if (limit_has_entry(oldlimits, "type"))
737c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
738c501d73cSMariusz Zaborski 	}
739c501d73cSMariusz Zaborski 	if (!hasfamily) {
740c501d73cSMariusz Zaborski 		if (limit_has_entry(oldlimits, "family"))
741c501d73cSMariusz Zaborski 			return (ENOTCAPABLE);
742c501d73cSMariusz Zaborski 	}
743c501d73cSMariusz Zaborski 
744c501d73cSMariusz Zaborski 	return (0);
745c501d73cSMariusz Zaborski }
746c501d73cSMariusz Zaborski 
747c501d73cSMariusz Zaborski static int
748c501d73cSMariusz Zaborski dns_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
749c501d73cSMariusz Zaborski     nvlist_t *nvlout)
750c501d73cSMariusz Zaborski {
751c501d73cSMariusz Zaborski 	int error;
752c501d73cSMariusz Zaborski 
753c501d73cSMariusz Zaborski 	if (strcmp(cmd, "gethostbyname") == 0)
754c501d73cSMariusz Zaborski 		error = dns_gethostbyname(limits, nvlin, nvlout);
755c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "gethostbyaddr") == 0)
756c501d73cSMariusz Zaborski 		error = dns_gethostbyaddr(limits, nvlin, nvlout);
757c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "getnameinfo") == 0)
758c501d73cSMariusz Zaborski 		error = dns_getnameinfo(limits, nvlin, nvlout);
759c501d73cSMariusz Zaborski 	else if (strcmp(cmd, "getaddrinfo") == 0)
760c501d73cSMariusz Zaborski 		error = dns_getaddrinfo(limits, nvlin, nvlout);
761c501d73cSMariusz Zaborski 	else
762c501d73cSMariusz Zaborski 		error = NO_RECOVERY;
763c501d73cSMariusz Zaborski 
764c501d73cSMariusz Zaborski 	return (error);
765c501d73cSMariusz Zaborski }
766c501d73cSMariusz Zaborski 
767920be817SMariusz Zaborski CREATE_SERVICE("system.dns", dns_limit, dns_command, 0);
768