xref: /freebsd/lib/libcasper/services/cap_net/cap_net.c (revision 832dc76b6368fc1fa57b67f65d83c15cc646d2e4)
1*832dc76bSMariusz Zaborski /*-
2*832dc76bSMariusz Zaborski  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*832dc76bSMariusz Zaborski  *
4*832dc76bSMariusz Zaborski  * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org>
5*832dc76bSMariusz Zaborski  *
6*832dc76bSMariusz Zaborski  * Redistribution and use in source and binary forms, with or without
7*832dc76bSMariusz Zaborski  * modification, are permitted provided that the following conditions
8*832dc76bSMariusz Zaborski  * are met:
9*832dc76bSMariusz Zaborski  * 1. Redistributions of source code must retain the above copyright
10*832dc76bSMariusz Zaborski  *    notice, this list of conditions and the following disclaimer.
11*832dc76bSMariusz Zaborski  * 2. Redistributions in binary form must reproduce the above copyright
12*832dc76bSMariusz Zaborski  *    notice, this list of conditions and the following disclaimer in the
13*832dc76bSMariusz Zaborski  *    documentation and/or other materials provided with the distribution.
14*832dc76bSMariusz Zaborski  *
15*832dc76bSMariusz Zaborski  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16*832dc76bSMariusz Zaborski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*832dc76bSMariusz Zaborski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*832dc76bSMariusz Zaborski  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19*832dc76bSMariusz Zaborski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*832dc76bSMariusz Zaborski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*832dc76bSMariusz Zaborski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*832dc76bSMariusz Zaborski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*832dc76bSMariusz Zaborski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*832dc76bSMariusz Zaborski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*832dc76bSMariusz Zaborski  * SUCH DAMAGE.
26*832dc76bSMariusz Zaborski  */
27*832dc76bSMariusz Zaborski 
28*832dc76bSMariusz Zaborski #include <sys/cdefs.h>
29*832dc76bSMariusz Zaborski __FBSDID("$FreeBSD$");
30*832dc76bSMariusz Zaborski 
31*832dc76bSMariusz Zaborski #include <sys/cnv.h>
32*832dc76bSMariusz Zaborski #include <sys/dnv.h>
33*832dc76bSMariusz Zaborski #include <sys/nv.h>
34*832dc76bSMariusz Zaborski #include <sys/socket.h>
35*832dc76bSMariusz Zaborski #include <netinet/in.h>
36*832dc76bSMariusz Zaborski 
37*832dc76bSMariusz Zaborski #include <assert.h>
38*832dc76bSMariusz Zaborski #include <errno.h>
39*832dc76bSMariusz Zaborski #include <netdb.h>
40*832dc76bSMariusz Zaborski #include <stdio.h>
41*832dc76bSMariusz Zaborski #include <string.h>
42*832dc76bSMariusz Zaborski #include <unistd.h>
43*832dc76bSMariusz Zaborski 
44*832dc76bSMariusz Zaborski #include <libcasper.h>
45*832dc76bSMariusz Zaborski #include <libcasper_service.h>
46*832dc76bSMariusz Zaborski 
47*832dc76bSMariusz Zaborski #include "cap_net.h"
48*832dc76bSMariusz Zaborski 
49*832dc76bSMariusz Zaborski #define	CAPNET_MASK	(CAPNET_ADDR2NAME | CAPNET_NAME2ADDR	\
50*832dc76bSMariusz Zaborski     CAPNET_DEPRECATED_ADDR2NAME | CAPNET_DEPRECATED_NAME2ADDR | \
51*832dc76bSMariusz Zaborski     CAPNET_CONNECT | CAPNET_BIND | CAPNET_CONNECTDNS)
52*832dc76bSMariusz Zaborski 
53*832dc76bSMariusz Zaborski /*
54*832dc76bSMariusz Zaborski  * Defines for the names of the limits.
55*832dc76bSMariusz Zaborski  * XXX: we should convert all string constats to this to avoid typos.
56*832dc76bSMariusz Zaborski  */
57*832dc76bSMariusz Zaborski #define	LIMIT_NV_BIND			"bind"
58*832dc76bSMariusz Zaborski #define	LIMIT_NV_CONNECT		"connect"
59*832dc76bSMariusz Zaborski #define	LIMIT_NV_ADDR2NAME		"addr2name"
60*832dc76bSMariusz Zaborski #define	LIMIT_NV_NAME2ADDR		"name2addr"
61*832dc76bSMariusz Zaborski 
62*832dc76bSMariusz Zaborski struct cap_net_limit {
63*832dc76bSMariusz Zaborski 	cap_channel_t	*cnl_chan;
64*832dc76bSMariusz Zaborski 	uint64_t	 cnl_mode;
65*832dc76bSMariusz Zaborski 	nvlist_t	*cnl_addr2name;
66*832dc76bSMariusz Zaborski 	nvlist_t	*cnl_name2addr;
67*832dc76bSMariusz Zaborski 	nvlist_t	*cnl_connect;
68*832dc76bSMariusz Zaborski 	nvlist_t	*cnl_bind;
69*832dc76bSMariusz Zaborski };
70*832dc76bSMariusz Zaborski 
71*832dc76bSMariusz Zaborski static struct hostent hent;
72*832dc76bSMariusz Zaborski 
73*832dc76bSMariusz Zaborski static void
74*832dc76bSMariusz Zaborski hostent_free(struct hostent *hp)
75*832dc76bSMariusz Zaborski {
76*832dc76bSMariusz Zaborski 	unsigned int ii;
77*832dc76bSMariusz Zaborski 
78*832dc76bSMariusz Zaborski 	free(hp->h_name);
79*832dc76bSMariusz Zaborski 	hp->h_name = NULL;
80*832dc76bSMariusz Zaborski 	if (hp->h_aliases != NULL) {
81*832dc76bSMariusz Zaborski 		for (ii = 0; hp->h_aliases[ii] != NULL; ii++)
82*832dc76bSMariusz Zaborski 			free(hp->h_aliases[ii]);
83*832dc76bSMariusz Zaborski 		free(hp->h_aliases);
84*832dc76bSMariusz Zaborski 		hp->h_aliases = NULL;
85*832dc76bSMariusz Zaborski 	}
86*832dc76bSMariusz Zaborski 	if (hp->h_addr_list != NULL) {
87*832dc76bSMariusz Zaborski 		for (ii = 0; hp->h_addr_list[ii] != NULL; ii++)
88*832dc76bSMariusz Zaborski 			free(hp->h_addr_list[ii]);
89*832dc76bSMariusz Zaborski 		free(hp->h_addr_list);
90*832dc76bSMariusz Zaborski 		hp->h_addr_list = NULL;
91*832dc76bSMariusz Zaborski 	}
92*832dc76bSMariusz Zaborski }
93*832dc76bSMariusz Zaborski 
94*832dc76bSMariusz Zaborski static struct hostent *
95*832dc76bSMariusz Zaborski hostent_unpack(const nvlist_t *nvl, struct hostent *hp)
96*832dc76bSMariusz Zaborski {
97*832dc76bSMariusz Zaborski 	unsigned int ii, nitems;
98*832dc76bSMariusz Zaborski 	char nvlname[64];
99*832dc76bSMariusz Zaborski 	int n;
100*832dc76bSMariusz Zaborski 
101*832dc76bSMariusz Zaborski 	hostent_free(hp);
102*832dc76bSMariusz Zaborski 
103*832dc76bSMariusz Zaborski 	hp->h_name = strdup(nvlist_get_string(nvl, "name"));
104*832dc76bSMariusz Zaborski 	if (hp->h_name == NULL)
105*832dc76bSMariusz Zaborski 		goto fail;
106*832dc76bSMariusz Zaborski 	hp->h_addrtype = (int)nvlist_get_number(nvl, "addrtype");
107*832dc76bSMariusz Zaborski 	hp->h_length = (int)nvlist_get_number(nvl, "length");
108*832dc76bSMariusz Zaborski 
109*832dc76bSMariusz Zaborski 	nitems = (unsigned int)nvlist_get_number(nvl, "naliases");
110*832dc76bSMariusz Zaborski 	hp->h_aliases = calloc(sizeof(hp->h_aliases[0]), nitems + 1);
111*832dc76bSMariusz Zaborski 	if (hp->h_aliases == NULL)
112*832dc76bSMariusz Zaborski 		goto fail;
113*832dc76bSMariusz Zaborski 	for (ii = 0; ii < nitems; ii++) {
114*832dc76bSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
115*832dc76bSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
116*832dc76bSMariusz Zaborski 		hp->h_aliases[ii] =
117*832dc76bSMariusz Zaborski 		    strdup(nvlist_get_string(nvl, nvlname));
118*832dc76bSMariusz Zaborski 		if (hp->h_aliases[ii] == NULL)
119*832dc76bSMariusz Zaborski 			goto fail;
120*832dc76bSMariusz Zaborski 	}
121*832dc76bSMariusz Zaborski 	hp->h_aliases[ii] = NULL;
122*832dc76bSMariusz Zaborski 
123*832dc76bSMariusz Zaborski 	nitems = (unsigned int)nvlist_get_number(nvl, "naddrs");
124*832dc76bSMariusz Zaborski 	hp->h_addr_list = calloc(sizeof(hp->h_addr_list[0]), nitems + 1);
125*832dc76bSMariusz Zaborski 	if (hp->h_addr_list == NULL)
126*832dc76bSMariusz Zaborski 		goto fail;
127*832dc76bSMariusz Zaborski 	for (ii = 0; ii < nitems; ii++) {
128*832dc76bSMariusz Zaborski 		hp->h_addr_list[ii] = malloc(hp->h_length);
129*832dc76bSMariusz Zaborski 		if (hp->h_addr_list[ii] == NULL)
130*832dc76bSMariusz Zaborski 			goto fail;
131*832dc76bSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
132*832dc76bSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
133*832dc76bSMariusz Zaborski 		bcopy(nvlist_get_binary(nvl, nvlname, NULL),
134*832dc76bSMariusz Zaborski 		    hp->h_addr_list[ii], hp->h_length);
135*832dc76bSMariusz Zaborski 	}
136*832dc76bSMariusz Zaborski 	hp->h_addr_list[ii] = NULL;
137*832dc76bSMariusz Zaborski 
138*832dc76bSMariusz Zaborski 	return (hp);
139*832dc76bSMariusz Zaborski fail:
140*832dc76bSMariusz Zaborski 	hostent_free(hp);
141*832dc76bSMariusz Zaborski 	h_errno = NO_RECOVERY;
142*832dc76bSMariusz Zaborski 	return (NULL);
143*832dc76bSMariusz Zaborski }
144*832dc76bSMariusz Zaborski 
145*832dc76bSMariusz Zaborski static int
146*832dc76bSMariusz Zaborski request_cb(cap_channel_t *chan, const char *name, int s,
147*832dc76bSMariusz Zaborski     const struct sockaddr *saddr, socklen_t len)
148*832dc76bSMariusz Zaborski {
149*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
150*832dc76bSMariusz Zaborski 	int serrno;
151*832dc76bSMariusz Zaborski 
152*832dc76bSMariusz Zaborski 	nvl = nvlist_create(0);
153*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", name);
154*832dc76bSMariusz Zaborski 	nvlist_add_descriptor(nvl, "s", s);
155*832dc76bSMariusz Zaborski 	nvlist_add_binary(nvl, "saddr", saddr, len);
156*832dc76bSMariusz Zaborski 
157*832dc76bSMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
158*832dc76bSMariusz Zaborski 	if (nvl == NULL)
159*832dc76bSMariusz Zaborski 		return (-1);
160*832dc76bSMariusz Zaborski 
161*832dc76bSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
162*832dc76bSMariusz Zaborski 		serrno = (int)nvlist_get_number(nvl, "error");
163*832dc76bSMariusz Zaborski 		nvlist_destroy(nvl);
164*832dc76bSMariusz Zaborski 		errno = serrno;
165*832dc76bSMariusz Zaborski 		return (-1);
166*832dc76bSMariusz Zaborski 	}
167*832dc76bSMariusz Zaborski 
168*832dc76bSMariusz Zaborski 	s = dup2(s, nvlist_get_descriptor(nvl, "s"));
169*832dc76bSMariusz Zaborski 	nvlist_destroy(nvl);
170*832dc76bSMariusz Zaborski 
171*832dc76bSMariusz Zaborski 	return (s == -1 ? -1 : 0);
172*832dc76bSMariusz Zaborski }
173*832dc76bSMariusz Zaborski 
174*832dc76bSMariusz Zaborski int
175*832dc76bSMariusz Zaborski cap_bind(cap_channel_t *chan, int s, const struct sockaddr *addr,
176*832dc76bSMariusz Zaborski     socklen_t addrlen)
177*832dc76bSMariusz Zaborski {
178*832dc76bSMariusz Zaborski 
179*832dc76bSMariusz Zaborski 	return (request_cb(chan, LIMIT_NV_BIND, s, addr, addrlen));
180*832dc76bSMariusz Zaborski }
181*832dc76bSMariusz Zaborski 
182*832dc76bSMariusz Zaborski int
183*832dc76bSMariusz Zaborski cap_connect(cap_channel_t *chan, int s, const struct sockaddr *name,
184*832dc76bSMariusz Zaborski     socklen_t namelen)
185*832dc76bSMariusz Zaborski {
186*832dc76bSMariusz Zaborski 
187*832dc76bSMariusz Zaborski 	return (request_cb(chan, LIMIT_NV_CONNECT, s, name, namelen));
188*832dc76bSMariusz Zaborski }
189*832dc76bSMariusz Zaborski 
190*832dc76bSMariusz Zaborski 
191*832dc76bSMariusz Zaborski struct hostent *
192*832dc76bSMariusz Zaborski cap_gethostbyname(cap_channel_t *chan, const char *name)
193*832dc76bSMariusz Zaborski {
194*832dc76bSMariusz Zaborski 
195*832dc76bSMariusz Zaborski 	return (cap_gethostbyname2(chan, name, AF_INET));
196*832dc76bSMariusz Zaborski }
197*832dc76bSMariusz Zaborski 
198*832dc76bSMariusz Zaborski struct hostent *
199*832dc76bSMariusz Zaborski cap_gethostbyname2(cap_channel_t *chan, const char *name, int af)
200*832dc76bSMariusz Zaborski {
201*832dc76bSMariusz Zaborski 	struct hostent *hp;
202*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
203*832dc76bSMariusz Zaborski 
204*832dc76bSMariusz Zaborski 	nvl = nvlist_create(0);
205*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "gethostbyname");
206*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "family", (uint64_t)af);
207*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "name", name);
208*832dc76bSMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
209*832dc76bSMariusz Zaborski 	if (nvl == NULL) {
210*832dc76bSMariusz Zaborski 		h_errno = NO_RECOVERY;
211*832dc76bSMariusz Zaborski 		return (NULL);
212*832dc76bSMariusz Zaborski 	}
213*832dc76bSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
214*832dc76bSMariusz Zaborski 		h_errno = (int)nvlist_get_number(nvl, "error");
215*832dc76bSMariusz Zaborski 		nvlist_destroy(nvl);
216*832dc76bSMariusz Zaborski 		return (NULL);
217*832dc76bSMariusz Zaborski 	}
218*832dc76bSMariusz Zaborski 
219*832dc76bSMariusz Zaborski 	hp = hostent_unpack(nvl, &hent);
220*832dc76bSMariusz Zaborski 	nvlist_destroy(nvl);
221*832dc76bSMariusz Zaborski 	return (hp);
222*832dc76bSMariusz Zaborski }
223*832dc76bSMariusz Zaborski 
224*832dc76bSMariusz Zaborski struct hostent *
225*832dc76bSMariusz Zaborski cap_gethostbyaddr(cap_channel_t *chan, const void *addr, socklen_t len,
226*832dc76bSMariusz Zaborski     int af)
227*832dc76bSMariusz Zaborski {
228*832dc76bSMariusz Zaborski 	struct hostent *hp;
229*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
230*832dc76bSMariusz Zaborski 
231*832dc76bSMariusz Zaborski 	nvl = nvlist_create(0);
232*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "gethostbyaddr");
233*832dc76bSMariusz Zaborski 	nvlist_add_binary(nvl, "addr", addr, (size_t)len);
234*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "family", (uint64_t)af);
235*832dc76bSMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
236*832dc76bSMariusz Zaborski 	if (nvl == NULL) {
237*832dc76bSMariusz Zaborski 		h_errno = NO_RECOVERY;
238*832dc76bSMariusz Zaborski 		return (NULL);
239*832dc76bSMariusz Zaborski 	}
240*832dc76bSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
241*832dc76bSMariusz Zaborski 		h_errno = (int)nvlist_get_number(nvl, "error");
242*832dc76bSMariusz Zaborski 		nvlist_destroy(nvl);
243*832dc76bSMariusz Zaborski 		return (NULL);
244*832dc76bSMariusz Zaborski 	}
245*832dc76bSMariusz Zaborski 	hp = hostent_unpack(nvl, &hent);
246*832dc76bSMariusz Zaborski 	nvlist_destroy(nvl);
247*832dc76bSMariusz Zaborski 	return (hp);
248*832dc76bSMariusz Zaborski }
249*832dc76bSMariusz Zaborski 
250*832dc76bSMariusz Zaborski static struct addrinfo *
251*832dc76bSMariusz Zaborski addrinfo_unpack(const nvlist_t *nvl)
252*832dc76bSMariusz Zaborski {
253*832dc76bSMariusz Zaborski 	struct addrinfo *ai;
254*832dc76bSMariusz Zaborski 	const void *addr;
255*832dc76bSMariusz Zaborski 	size_t addrlen;
256*832dc76bSMariusz Zaborski 	const char *canonname;
257*832dc76bSMariusz Zaborski 
258*832dc76bSMariusz Zaborski 	addr = nvlist_get_binary(nvl, "ai_addr", &addrlen);
259*832dc76bSMariusz Zaborski 	ai = malloc(sizeof(*ai) + addrlen);
260*832dc76bSMariusz Zaborski 	if (ai == NULL)
261*832dc76bSMariusz Zaborski 		return (NULL);
262*832dc76bSMariusz Zaborski 	ai->ai_flags = (int)nvlist_get_number(nvl, "ai_flags");
263*832dc76bSMariusz Zaborski 	ai->ai_family = (int)nvlist_get_number(nvl, "ai_family");
264*832dc76bSMariusz Zaborski 	ai->ai_socktype = (int)nvlist_get_number(nvl, "ai_socktype");
265*832dc76bSMariusz Zaborski 	ai->ai_protocol = (int)nvlist_get_number(nvl, "ai_protocol");
266*832dc76bSMariusz Zaborski 	ai->ai_addrlen = (socklen_t)addrlen;
267*832dc76bSMariusz Zaborski 	canonname = dnvlist_get_string(nvl, "ai_canonname", NULL);
268*832dc76bSMariusz Zaborski 	if (canonname != NULL) {
269*832dc76bSMariusz Zaborski 		ai->ai_canonname = strdup(canonname);
270*832dc76bSMariusz Zaborski 		if (ai->ai_canonname == NULL) {
271*832dc76bSMariusz Zaborski 			free(ai);
272*832dc76bSMariusz Zaborski 			return (NULL);
273*832dc76bSMariusz Zaborski 		}
274*832dc76bSMariusz Zaborski 	} else {
275*832dc76bSMariusz Zaborski 		ai->ai_canonname = NULL;
276*832dc76bSMariusz Zaborski 	}
277*832dc76bSMariusz Zaborski 	ai->ai_addr = (void *)(ai + 1);
278*832dc76bSMariusz Zaborski 	bcopy(addr, ai->ai_addr, addrlen);
279*832dc76bSMariusz Zaborski 	ai->ai_next = NULL;
280*832dc76bSMariusz Zaborski 
281*832dc76bSMariusz Zaborski 	return (ai);
282*832dc76bSMariusz Zaborski }
283*832dc76bSMariusz Zaborski 
284*832dc76bSMariusz Zaborski int
285*832dc76bSMariusz Zaborski cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
286*832dc76bSMariusz Zaborski     const struct addrinfo *hints, struct addrinfo **res)
287*832dc76bSMariusz Zaborski {
288*832dc76bSMariusz Zaborski 	struct addrinfo *firstai, *prevai, *curai;
289*832dc76bSMariusz Zaborski 	unsigned int ii;
290*832dc76bSMariusz Zaborski 	const nvlist_t *nvlai;
291*832dc76bSMariusz Zaborski 	char nvlname[64];
292*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
293*832dc76bSMariusz Zaborski 	int error, n;
294*832dc76bSMariusz Zaborski 
295*832dc76bSMariusz Zaborski 	nvl = nvlist_create(0);
296*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "getaddrinfo");
297*832dc76bSMariusz Zaborski 	if (hostname != NULL)
298*832dc76bSMariusz Zaborski 		nvlist_add_string(nvl, "hostname", hostname);
299*832dc76bSMariusz Zaborski 	if (servname != NULL)
300*832dc76bSMariusz Zaborski 		nvlist_add_string(nvl, "servname", servname);
301*832dc76bSMariusz Zaborski 	if (hints != NULL) {
302*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_flags",
303*832dc76bSMariusz Zaborski 		    (uint64_t)hints->ai_flags);
304*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_family",
305*832dc76bSMariusz Zaborski 		    (uint64_t)hints->ai_family);
306*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_socktype",
307*832dc76bSMariusz Zaborski 		    (uint64_t)hints->ai_socktype);
308*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "hints.ai_protocol",
309*832dc76bSMariusz Zaborski 		    (uint64_t)hints->ai_protocol);
310*832dc76bSMariusz Zaborski 	}
311*832dc76bSMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
312*832dc76bSMariusz Zaborski 	if (nvl == NULL)
313*832dc76bSMariusz Zaborski 		return (EAI_MEMORY);
314*832dc76bSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
315*832dc76bSMariusz Zaborski 		error = (int)nvlist_get_number(nvl, "error");
316*832dc76bSMariusz Zaborski 		nvlist_destroy(nvl);
317*832dc76bSMariusz Zaborski 		return (error);
318*832dc76bSMariusz Zaborski 	}
319*832dc76bSMariusz Zaborski 
320*832dc76bSMariusz Zaborski 	nvlai = NULL;
321*832dc76bSMariusz Zaborski 	firstai = prevai = curai = NULL;
322*832dc76bSMariusz Zaborski 	for (ii = 0; ; ii++) {
323*832dc76bSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
324*832dc76bSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
325*832dc76bSMariusz Zaborski 		if (!nvlist_exists_nvlist(nvl, nvlname))
326*832dc76bSMariusz Zaborski 			break;
327*832dc76bSMariusz Zaborski 		nvlai = nvlist_get_nvlist(nvl, nvlname);
328*832dc76bSMariusz Zaborski 		curai = addrinfo_unpack(nvlai);
329*832dc76bSMariusz Zaborski 		if (curai == NULL)
330*832dc76bSMariusz Zaborski 			return (EAI_MEMORY);
331*832dc76bSMariusz Zaborski 		if (prevai != NULL)
332*832dc76bSMariusz Zaborski 			prevai->ai_next = curai;
333*832dc76bSMariusz Zaborski 		else
334*832dc76bSMariusz Zaborski 			firstai = curai;
335*832dc76bSMariusz Zaborski 		prevai = curai;
336*832dc76bSMariusz Zaborski 	}
337*832dc76bSMariusz Zaborski 	nvlist_destroy(nvl);
338*832dc76bSMariusz Zaborski 	if (curai == NULL && nvlai != NULL) {
339*832dc76bSMariusz Zaborski 		if (firstai == NULL)
340*832dc76bSMariusz Zaborski 			freeaddrinfo(firstai);
341*832dc76bSMariusz Zaborski 		return (EAI_MEMORY);
342*832dc76bSMariusz Zaborski 	}
343*832dc76bSMariusz Zaborski 
344*832dc76bSMariusz Zaborski 	*res = firstai;
345*832dc76bSMariusz Zaborski 	return (0);
346*832dc76bSMariusz Zaborski }
347*832dc76bSMariusz Zaborski 
348*832dc76bSMariusz Zaborski int
349*832dc76bSMariusz Zaborski cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
350*832dc76bSMariusz Zaborski     char *host, size_t hostlen, char *serv, size_t servlen, int flags)
351*832dc76bSMariusz Zaborski {
352*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
353*832dc76bSMariusz Zaborski 	int error;
354*832dc76bSMariusz Zaborski 
355*832dc76bSMariusz Zaborski 	nvl = nvlist_create(0);
356*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "cmd", "getnameinfo");
357*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "hostlen", (uint64_t)hostlen);
358*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "servlen", (uint64_t)servlen);
359*832dc76bSMariusz Zaborski 	nvlist_add_binary(nvl, "sa", sa, (size_t)salen);
360*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "flags", (uint64_t)flags);
361*832dc76bSMariusz Zaborski 	nvl = cap_xfer_nvlist(chan, nvl);
362*832dc76bSMariusz Zaborski 	if (nvl == NULL)
363*832dc76bSMariusz Zaborski 		return (EAI_MEMORY);
364*832dc76bSMariusz Zaborski 	if (nvlist_get_number(nvl, "error") != 0) {
365*832dc76bSMariusz Zaborski 		error = (int)nvlist_get_number(nvl, "error");
366*832dc76bSMariusz Zaborski 		nvlist_destroy(nvl);
367*832dc76bSMariusz Zaborski 		return (error);
368*832dc76bSMariusz Zaborski 	}
369*832dc76bSMariusz Zaborski 
370*832dc76bSMariusz Zaborski 	if (host != NULL && nvlist_exists_string(nvl, "host"))
371*832dc76bSMariusz Zaborski 		strlcpy(host, nvlist_get_string(nvl, "host"), hostlen + 1);
372*832dc76bSMariusz Zaborski 	if (serv != NULL && nvlist_exists_string(nvl, "serv"))
373*832dc76bSMariusz Zaborski 		strlcpy(serv, nvlist_get_string(nvl, "serv"), servlen + 1);
374*832dc76bSMariusz Zaborski 	nvlist_destroy(nvl);
375*832dc76bSMariusz Zaborski 	return (0);
376*832dc76bSMariusz Zaborski }
377*832dc76bSMariusz Zaborski 
378*832dc76bSMariusz Zaborski cap_net_limit_t *
379*832dc76bSMariusz Zaborski cap_net_limit_init(cap_channel_t *chan, uint64_t mode)
380*832dc76bSMariusz Zaborski {
381*832dc76bSMariusz Zaborski 	cap_net_limit_t *limit;
382*832dc76bSMariusz Zaborski 
383*832dc76bSMariusz Zaborski 	limit = calloc(1, sizeof(*limit));
384*832dc76bSMariusz Zaborski 	if (limit != NULL) {
385*832dc76bSMariusz Zaborski 		limit->cnl_mode = mode;
386*832dc76bSMariusz Zaborski 		limit->cnl_chan = chan;
387*832dc76bSMariusz Zaborski 		limit->cnl_addr2name = nvlist_create(0);
388*832dc76bSMariusz Zaborski 		limit->cnl_name2addr = nvlist_create(0);
389*832dc76bSMariusz Zaborski 		limit->cnl_connect = nvlist_create(0);
390*832dc76bSMariusz Zaborski 		limit->cnl_bind = nvlist_create(0);
391*832dc76bSMariusz Zaborski 	}
392*832dc76bSMariusz Zaborski 
393*832dc76bSMariusz Zaborski 	return (limit);
394*832dc76bSMariusz Zaborski }
395*832dc76bSMariusz Zaborski 
396*832dc76bSMariusz Zaborski static void
397*832dc76bSMariusz Zaborski pack_limit(nvlist_t *lnvl, const char *name, nvlist_t *limit)
398*832dc76bSMariusz Zaborski {
399*832dc76bSMariusz Zaborski 
400*832dc76bSMariusz Zaborski 	if (!nvlist_empty(limit)) {
401*832dc76bSMariusz Zaborski 		nvlist_move_nvlist(lnvl, name, limit);
402*832dc76bSMariusz Zaborski 	} else {
403*832dc76bSMariusz Zaborski 		nvlist_destroy(limit);
404*832dc76bSMariusz Zaborski 	}
405*832dc76bSMariusz Zaborski }
406*832dc76bSMariusz Zaborski 
407*832dc76bSMariusz Zaborski int
408*832dc76bSMariusz Zaborski cap_net_limit(cap_net_limit_t *limit)
409*832dc76bSMariusz Zaborski {
410*832dc76bSMariusz Zaborski 	nvlist_t *lnvl;
411*832dc76bSMariusz Zaborski 	cap_channel_t *chan;
412*832dc76bSMariusz Zaborski 
413*832dc76bSMariusz Zaborski 	lnvl = nvlist_create(0);
414*832dc76bSMariusz Zaborski 	nvlist_add_number(lnvl, "mode", limit->cnl_mode);
415*832dc76bSMariusz Zaborski 
416*832dc76bSMariusz Zaborski 	pack_limit(lnvl, LIMIT_NV_ADDR2NAME, limit->cnl_addr2name);
417*832dc76bSMariusz Zaborski 	pack_limit(lnvl, LIMIT_NV_NAME2ADDR, limit->cnl_name2addr);
418*832dc76bSMariusz Zaborski 	pack_limit(lnvl, LIMIT_NV_CONNECT, limit->cnl_connect);
419*832dc76bSMariusz Zaborski 	pack_limit(lnvl, LIMIT_NV_BIND, limit->cnl_bind);
420*832dc76bSMariusz Zaborski 
421*832dc76bSMariusz Zaborski 	chan = limit->cnl_chan;
422*832dc76bSMariusz Zaborski 	free(limit);
423*832dc76bSMariusz Zaborski 
424*832dc76bSMariusz Zaborski 	return (cap_limit_set(chan, lnvl));
425*832dc76bSMariusz Zaborski }
426*832dc76bSMariusz Zaborski 
427*832dc76bSMariusz Zaborski void
428*832dc76bSMariusz Zaborski cap_net_free(cap_net_limit_t *limit)
429*832dc76bSMariusz Zaborski {
430*832dc76bSMariusz Zaborski 
431*832dc76bSMariusz Zaborski 	if (limit == NULL)
432*832dc76bSMariusz Zaborski 		return;
433*832dc76bSMariusz Zaborski 
434*832dc76bSMariusz Zaborski 	nvlist_destroy(limit->cnl_addr2name);
435*832dc76bSMariusz Zaborski 	nvlist_destroy(limit->cnl_name2addr);
436*832dc76bSMariusz Zaborski 	nvlist_destroy(limit->cnl_connect);
437*832dc76bSMariusz Zaborski 	nvlist_destroy(limit->cnl_bind);
438*832dc76bSMariusz Zaborski 
439*832dc76bSMariusz Zaborski 	free(limit);
440*832dc76bSMariusz Zaborski }
441*832dc76bSMariusz Zaborski 
442*832dc76bSMariusz Zaborski static void
443*832dc76bSMariusz Zaborski pack_family(nvlist_t *nvl, int *family, size_t size)
444*832dc76bSMariusz Zaborski {
445*832dc76bSMariusz Zaborski 	size_t i;
446*832dc76bSMariusz Zaborski 
447*832dc76bSMariusz Zaborski 	i = 0;
448*832dc76bSMariusz Zaborski 	if (!nvlist_exists_number_array(nvl, "family")) {
449*832dc76bSMariusz Zaborski 		uint64_t val;
450*832dc76bSMariusz Zaborski 
451*832dc76bSMariusz Zaborski 		val = family[0];
452*832dc76bSMariusz Zaborski 		nvlist_add_number_array(nvl, "family", &val, 1);
453*832dc76bSMariusz Zaborski 		i += 1;
454*832dc76bSMariusz Zaborski 	}
455*832dc76bSMariusz Zaborski 
456*832dc76bSMariusz Zaborski 	for (; i < size; i++) {
457*832dc76bSMariusz Zaborski 		nvlist_append_number_array(nvl, "family", family[i]);
458*832dc76bSMariusz Zaborski 	}
459*832dc76bSMariusz Zaborski }
460*832dc76bSMariusz Zaborski 
461*832dc76bSMariusz Zaborski static void
462*832dc76bSMariusz Zaborski pack_sockaddr(nvlist_t *res, const struct sockaddr *sa, socklen_t salen)
463*832dc76bSMariusz Zaborski {
464*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
465*832dc76bSMariusz Zaborski 
466*832dc76bSMariusz Zaborski 	if (!nvlist_exists_nvlist(res, "sockaddr")) {
467*832dc76bSMariusz Zaborski 		nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
468*832dc76bSMariusz Zaborski 	} else {
469*832dc76bSMariusz Zaborski 		nvl = nvlist_take_nvlist(res, "sockaddr");
470*832dc76bSMariusz Zaborski 	}
471*832dc76bSMariusz Zaborski 
472*832dc76bSMariusz Zaborski 	nvlist_add_binary(nvl, "", sa, salen);
473*832dc76bSMariusz Zaborski 	nvlist_move_nvlist(res, "sockaddr", nvl);
474*832dc76bSMariusz Zaborski }
475*832dc76bSMariusz Zaborski 
476*832dc76bSMariusz Zaborski cap_net_limit_t *
477*832dc76bSMariusz Zaborski cap_net_limit_addr2name_family(cap_net_limit_t *limit, int *family, size_t size)
478*832dc76bSMariusz Zaborski {
479*832dc76bSMariusz Zaborski 
480*832dc76bSMariusz Zaborski 	pack_family(limit->cnl_addr2name, family, size);
481*832dc76bSMariusz Zaborski 	return (limit);
482*832dc76bSMariusz Zaborski }
483*832dc76bSMariusz Zaborski 
484*832dc76bSMariusz Zaborski cap_net_limit_t *
485*832dc76bSMariusz Zaborski cap_net_limit_name2addr_family(cap_net_limit_t *limit, int *family, size_t size)
486*832dc76bSMariusz Zaborski {
487*832dc76bSMariusz Zaborski 
488*832dc76bSMariusz Zaborski 	pack_family(limit->cnl_name2addr, family, size);
489*832dc76bSMariusz Zaborski 	return (limit);
490*832dc76bSMariusz Zaborski }
491*832dc76bSMariusz Zaborski 
492*832dc76bSMariusz Zaborski cap_net_limit_t *
493*832dc76bSMariusz Zaborski cap_net_limit_name2addr(cap_net_limit_t *limit, const char *host,
494*832dc76bSMariusz Zaborski     const char *serv)
495*832dc76bSMariusz Zaborski {
496*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
497*832dc76bSMariusz Zaborski 
498*832dc76bSMariusz Zaborski 	if (!nvlist_exists_nvlist(limit->cnl_name2addr, "hosts")) {
499*832dc76bSMariusz Zaborski 		nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
500*832dc76bSMariusz Zaborski 	} else {
501*832dc76bSMariusz Zaborski 		nvl = nvlist_take_nvlist(limit->cnl_name2addr, "hosts");
502*832dc76bSMariusz Zaborski 	}
503*832dc76bSMariusz Zaborski 
504*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl,
505*832dc76bSMariusz Zaborski 	    host != NULL ? host : "",
506*832dc76bSMariusz Zaborski 	    serv != NULL ? serv : "");
507*832dc76bSMariusz Zaborski 
508*832dc76bSMariusz Zaborski 	nvlist_move_nvlist(limit->cnl_name2addr, "hosts", nvl);
509*832dc76bSMariusz Zaborski 	return (limit);
510*832dc76bSMariusz Zaborski }
511*832dc76bSMariusz Zaborski 
512*832dc76bSMariusz Zaborski cap_net_limit_t *
513*832dc76bSMariusz Zaborski cap_net_limit_addr2name(cap_net_limit_t *limit, const struct sockaddr *sa,
514*832dc76bSMariusz Zaborski     socklen_t salen)
515*832dc76bSMariusz Zaborski {
516*832dc76bSMariusz Zaborski 
517*832dc76bSMariusz Zaborski 	pack_sockaddr(limit->cnl_addr2name, sa, salen);
518*832dc76bSMariusz Zaborski 	return (limit);
519*832dc76bSMariusz Zaborski }
520*832dc76bSMariusz Zaborski 
521*832dc76bSMariusz Zaborski 
522*832dc76bSMariusz Zaborski cap_net_limit_t *
523*832dc76bSMariusz Zaborski cap_net_limit_connect(cap_net_limit_t *limit, const struct sockaddr *sa,
524*832dc76bSMariusz Zaborski     socklen_t salen)
525*832dc76bSMariusz Zaborski {
526*832dc76bSMariusz Zaborski 
527*832dc76bSMariusz Zaborski 	pack_sockaddr(limit->cnl_connect, sa, salen);
528*832dc76bSMariusz Zaborski 	return (limit);
529*832dc76bSMariusz Zaborski }
530*832dc76bSMariusz Zaborski 
531*832dc76bSMariusz Zaborski cap_net_limit_t *
532*832dc76bSMariusz Zaborski cap_net_limit_bind(cap_net_limit_t *limit, const struct sockaddr *sa,
533*832dc76bSMariusz Zaborski     socklen_t salen)
534*832dc76bSMariusz Zaborski {
535*832dc76bSMariusz Zaborski 
536*832dc76bSMariusz Zaborski 	pack_sockaddr(limit->cnl_bind, sa, salen);
537*832dc76bSMariusz Zaborski 	return (limit);
538*832dc76bSMariusz Zaborski }
539*832dc76bSMariusz Zaborski 
540*832dc76bSMariusz Zaborski /*
541*832dc76bSMariusz Zaborski  * Service functions.
542*832dc76bSMariusz Zaborski  */
543*832dc76bSMariusz Zaborski 
544*832dc76bSMariusz Zaborski static nvlist_t *capdnscache;
545*832dc76bSMariusz Zaborski 
546*832dc76bSMariusz Zaborski static void
547*832dc76bSMariusz Zaborski net_add_sockaddr_to_cache(struct sockaddr *sa, socklen_t salen, bool deprecated)
548*832dc76bSMariusz Zaborski {
549*832dc76bSMariusz Zaborski 	void *cookie;
550*832dc76bSMariusz Zaborski 
551*832dc76bSMariusz Zaborski 	if (capdnscache == NULL) {
552*832dc76bSMariusz Zaborski 		capdnscache = nvlist_create(NV_FLAG_NO_UNIQUE);
553*832dc76bSMariusz Zaborski 	} else {
554*832dc76bSMariusz Zaborski 		/* Lets keep it clean. Look for dups. */
555*832dc76bSMariusz Zaborski 		cookie = NULL;
556*832dc76bSMariusz Zaborski 		while (nvlist_next(capdnscache, NULL, &cookie) != NULL) {
557*832dc76bSMariusz Zaborski 			const void *data;
558*832dc76bSMariusz Zaborski 			size_t size;
559*832dc76bSMariusz Zaborski 
560*832dc76bSMariusz Zaborski 			assert(cnvlist_type(cookie) == NV_TYPE_BINARY);
561*832dc76bSMariusz Zaborski 
562*832dc76bSMariusz Zaborski 			data = cnvlist_get_binary(cookie, &size);
563*832dc76bSMariusz Zaborski 			if (salen != size)
564*832dc76bSMariusz Zaborski 				continue;
565*832dc76bSMariusz Zaborski 			if (memcmp(data, sa, size) == 0)
566*832dc76bSMariusz Zaborski 				return;
567*832dc76bSMariusz Zaborski 		}
568*832dc76bSMariusz Zaborski 	}
569*832dc76bSMariusz Zaborski 
570*832dc76bSMariusz Zaborski 	nvlist_add_binary(capdnscache, deprecated ? "d" : "", sa, salen);
571*832dc76bSMariusz Zaborski }
572*832dc76bSMariusz Zaborski 
573*832dc76bSMariusz Zaborski static void
574*832dc76bSMariusz Zaborski net_add_hostent_to_cache(const char *address, size_t asize, int family)
575*832dc76bSMariusz Zaborski {
576*832dc76bSMariusz Zaborski 
577*832dc76bSMariusz Zaborski 	if (family != AF_INET && family != AF_INET6)
578*832dc76bSMariusz Zaborski 		return;
579*832dc76bSMariusz Zaborski 
580*832dc76bSMariusz Zaborski 	if (family == AF_INET6) {
581*832dc76bSMariusz Zaborski 		struct sockaddr_in6 connaddr;
582*832dc76bSMariusz Zaborski 
583*832dc76bSMariusz Zaborski 		memset(&connaddr, 0, sizeof(connaddr));
584*832dc76bSMariusz Zaborski 		connaddr.sin6_family = AF_INET6;
585*832dc76bSMariusz Zaborski 		memcpy((char *)&connaddr.sin6_addr, address, asize);
586*832dc76bSMariusz Zaborski 		connaddr.sin6_port = 0;
587*832dc76bSMariusz Zaborski 
588*832dc76bSMariusz Zaborski 		net_add_sockaddr_to_cache((struct sockaddr *)&connaddr,
589*832dc76bSMariusz Zaborski 		    sizeof(connaddr), true);
590*832dc76bSMariusz Zaborski 	} else {
591*832dc76bSMariusz Zaborski 		struct sockaddr_in connaddr;
592*832dc76bSMariusz Zaborski 
593*832dc76bSMariusz Zaborski 		memset(&connaddr, 0, sizeof(connaddr));
594*832dc76bSMariusz Zaborski 		connaddr.sin_family = AF_INET;
595*832dc76bSMariusz Zaborski 		memcpy((char *)&connaddr.sin_addr.s_addr, address, asize);
596*832dc76bSMariusz Zaborski 		connaddr.sin_port = 0;
597*832dc76bSMariusz Zaborski 
598*832dc76bSMariusz Zaborski 		net_add_sockaddr_to_cache((struct sockaddr *)&connaddr,
599*832dc76bSMariusz Zaborski 		    sizeof(connaddr), true);
600*832dc76bSMariusz Zaborski 	}
601*832dc76bSMariusz Zaborski }
602*832dc76bSMariusz Zaborski 
603*832dc76bSMariusz Zaborski static bool
604*832dc76bSMariusz Zaborski net_allowed_mode(const nvlist_t *limits, uint64_t mode)
605*832dc76bSMariusz Zaborski {
606*832dc76bSMariusz Zaborski 
607*832dc76bSMariusz Zaborski 	if (limits == NULL)
608*832dc76bSMariusz Zaborski 		return (true);
609*832dc76bSMariusz Zaborski 
610*832dc76bSMariusz Zaborski 	return ((nvlist_get_number(limits, "mode") & mode) == mode);
611*832dc76bSMariusz Zaborski }
612*832dc76bSMariusz Zaborski 
613*832dc76bSMariusz Zaborski static bool
614*832dc76bSMariusz Zaborski net_allowed_family(const nvlist_t *limits, int family)
615*832dc76bSMariusz Zaborski {
616*832dc76bSMariusz Zaborski 	const uint64_t *allowedfamily;
617*832dc76bSMariusz Zaborski 	size_t i, allsize;
618*832dc76bSMariusz Zaborski 
619*832dc76bSMariusz Zaborski 	if (limits == NULL)
620*832dc76bSMariusz Zaborski 		return (true);
621*832dc76bSMariusz Zaborski 
622*832dc76bSMariusz Zaborski 	/* If there are no familes at all, allow any mode. */
623*832dc76bSMariusz Zaborski 	if (!nvlist_exists_number_array(limits, "family"))
624*832dc76bSMariusz Zaborski 		return (true);
625*832dc76bSMariusz Zaborski 
626*832dc76bSMariusz Zaborski 	allowedfamily = nvlist_get_number_array(limits, "family", &allsize);
627*832dc76bSMariusz Zaborski 	for (i = 0; i < allsize; i++) {
628*832dc76bSMariusz Zaborski 		/* XXX: what with AF_UNSPEC? */
629*832dc76bSMariusz Zaborski 		if (allowedfamily[i] == (uint64_t)family) {
630*832dc76bSMariusz Zaborski 			return (true);
631*832dc76bSMariusz Zaborski 		}
632*832dc76bSMariusz Zaborski 	}
633*832dc76bSMariusz Zaborski 
634*832dc76bSMariusz Zaborski 	return (false);
635*832dc76bSMariusz Zaborski }
636*832dc76bSMariusz Zaborski 
637*832dc76bSMariusz Zaborski static bool
638*832dc76bSMariusz Zaborski net_allowed_bsaddr_impl(const nvlist_t *salimits, const void *saddr,
639*832dc76bSMariusz Zaborski     size_t saddrsize)
640*832dc76bSMariusz Zaborski {
641*832dc76bSMariusz Zaborski 	void *cookie;
642*832dc76bSMariusz Zaborski 	const void *limit;
643*832dc76bSMariusz Zaborski 	size_t limitsize;
644*832dc76bSMariusz Zaborski 
645*832dc76bSMariusz Zaborski 	cookie = NULL;
646*832dc76bSMariusz Zaborski 	while (nvlist_next(salimits, NULL, &cookie) != NULL) {
647*832dc76bSMariusz Zaborski 		limit = cnvlist_get_binary(cookie, &limitsize);
648*832dc76bSMariusz Zaborski 
649*832dc76bSMariusz Zaborski 		if (limitsize != saddrsize) {
650*832dc76bSMariusz Zaborski 			continue;
651*832dc76bSMariusz Zaborski 		}
652*832dc76bSMariusz Zaborski 		if (memcmp(limit, saddr, limitsize) == 0) {
653*832dc76bSMariusz Zaborski 			return (true);
654*832dc76bSMariusz Zaborski 		}
655*832dc76bSMariusz Zaborski 
656*832dc76bSMariusz Zaborski 		/*
657*832dc76bSMariusz Zaborski 		 * In case of deprecated version (gethostbyname) we have to
658*832dc76bSMariusz Zaborski 		 * ignore port, because there is no such info in the hostent.
659*832dc76bSMariusz Zaborski 		 * Suporting only AF_INET and AF_INET6.
660*832dc76bSMariusz Zaborski 		 */
661*832dc76bSMariusz Zaborski 		if (strcmp(cnvlist_name(cookie), "d") != 0 ||
662*832dc76bSMariusz Zaborski 		    (saddrsize != sizeof(struct sockaddr_in) &&
663*832dc76bSMariusz Zaborski 		    saddrsize != sizeof(struct sockaddr_in6))) {
664*832dc76bSMariusz Zaborski 			continue;
665*832dc76bSMariusz Zaborski 		}
666*832dc76bSMariusz Zaborski 		if (saddrsize == sizeof(struct sockaddr_in)) {
667*832dc76bSMariusz Zaborski 			const struct sockaddr_in *saddrptr;
668*832dc76bSMariusz Zaborski 			struct sockaddr_in sockaddr;
669*832dc76bSMariusz Zaborski 
670*832dc76bSMariusz Zaborski 			saddrptr = (const struct sockaddr_in *)saddr;
671*832dc76bSMariusz Zaborski 			memcpy(&sockaddr, limit, sizeof(sockaddr));
672*832dc76bSMariusz Zaborski 			sockaddr.sin_port = saddrptr->sin_port;
673*832dc76bSMariusz Zaborski 
674*832dc76bSMariusz Zaborski 			if (memcmp(&sockaddr, saddr, saddrsize) == 0) {
675*832dc76bSMariusz Zaborski 				return (true);
676*832dc76bSMariusz Zaborski 			}
677*832dc76bSMariusz Zaborski 		} else if (saddrsize == sizeof(struct sockaddr_in6)) {
678*832dc76bSMariusz Zaborski 			const struct sockaddr_in6 *saddrptr;
679*832dc76bSMariusz Zaborski 			struct sockaddr_in6 sockaddr;
680*832dc76bSMariusz Zaborski 
681*832dc76bSMariusz Zaborski 			saddrptr = (const struct sockaddr_in6 *)saddr;
682*832dc76bSMariusz Zaborski 			memcpy(&sockaddr, limit, sizeof(sockaddr));
683*832dc76bSMariusz Zaborski 			sockaddr.sin6_port = saddrptr->sin6_port;
684*832dc76bSMariusz Zaborski 
685*832dc76bSMariusz Zaborski 			if (memcmp(&sockaddr, saddr, saddrsize) == 0) {
686*832dc76bSMariusz Zaborski 				return (true);
687*832dc76bSMariusz Zaborski 			}
688*832dc76bSMariusz Zaborski 		}
689*832dc76bSMariusz Zaborski 	}
690*832dc76bSMariusz Zaborski 
691*832dc76bSMariusz Zaborski 	return (false);
692*832dc76bSMariusz Zaborski }
693*832dc76bSMariusz Zaborski 
694*832dc76bSMariusz Zaborski static bool
695*832dc76bSMariusz Zaborski net_allowed_bsaddr(const nvlist_t *limits, const void *saddr, size_t saddrsize)
696*832dc76bSMariusz Zaborski {
697*832dc76bSMariusz Zaborski 
698*832dc76bSMariusz Zaborski 	if (limits == NULL)
699*832dc76bSMariusz Zaborski 		return (true);
700*832dc76bSMariusz Zaborski 
701*832dc76bSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "sockaddr"))
702*832dc76bSMariusz Zaborski 		return (true);
703*832dc76bSMariusz Zaborski 
704*832dc76bSMariusz Zaborski 	return (net_allowed_bsaddr_impl(nvlist_get_nvlist(limits, "sockaddr"),
705*832dc76bSMariusz Zaborski 	    saddr, saddrsize));
706*832dc76bSMariusz Zaborski }
707*832dc76bSMariusz Zaborski 
708*832dc76bSMariusz Zaborski static bool
709*832dc76bSMariusz Zaborski net_allowed_hosts(const nvlist_t *limits, const char *name, const char *srvname)
710*832dc76bSMariusz Zaborski {
711*832dc76bSMariusz Zaborski 	void *cookie;
712*832dc76bSMariusz Zaborski 	const nvlist_t *hlimits;
713*832dc76bSMariusz Zaborski 	const char *testname, *testsrvname;
714*832dc76bSMariusz Zaborski 
715*832dc76bSMariusz Zaborski 	if (limits == NULL) {
716*832dc76bSMariusz Zaborski 		return (true);
717*832dc76bSMariusz Zaborski 	}
718*832dc76bSMariusz Zaborski 
719*832dc76bSMariusz Zaborski 	/* If there are no hosts at all, allow any. */
720*832dc76bSMariusz Zaborski 	if (!nvlist_exists_nvlist(limits, "hosts")) {
721*832dc76bSMariusz Zaborski 		return (true);
722*832dc76bSMariusz Zaborski 	}
723*832dc76bSMariusz Zaborski 
724*832dc76bSMariusz Zaborski 	cookie = NULL;
725*832dc76bSMariusz Zaborski 	testname = (name == NULL ? "" : name);
726*832dc76bSMariusz Zaborski 	testsrvname = (srvname == NULL ? "" : srvname);
727*832dc76bSMariusz Zaborski 	hlimits = nvlist_get_nvlist(limits, "hosts");
728*832dc76bSMariusz Zaborski 	while (nvlist_next(hlimits, NULL, &cookie) != NULL) {
729*832dc76bSMariusz Zaborski 		if (strcmp(cnvlist_name(cookie), "") != 0 &&
730*832dc76bSMariusz Zaborski 		    strcmp(cnvlist_name(cookie), testname) != 0) {
731*832dc76bSMariusz Zaborski 			continue;
732*832dc76bSMariusz Zaborski 		}
733*832dc76bSMariusz Zaborski 
734*832dc76bSMariusz Zaborski 		if (strcmp(cnvlist_get_string(cookie), "") != 0 &&
735*832dc76bSMariusz Zaborski 		    strcmp(cnvlist_get_string(cookie), testsrvname) != 0) {
736*832dc76bSMariusz Zaborski 			continue;
737*832dc76bSMariusz Zaborski 		}
738*832dc76bSMariusz Zaborski 
739*832dc76bSMariusz Zaborski 		return (true);
740*832dc76bSMariusz Zaborski 	}
741*832dc76bSMariusz Zaborski 
742*832dc76bSMariusz Zaborski 	return (false);
743*832dc76bSMariusz Zaborski }
744*832dc76bSMariusz Zaborski 
745*832dc76bSMariusz Zaborski static void
746*832dc76bSMariusz Zaborski hostent_pack(const struct hostent *hp, nvlist_t *nvl, bool addtocache)
747*832dc76bSMariusz Zaborski {
748*832dc76bSMariusz Zaborski 	unsigned int ii;
749*832dc76bSMariusz Zaborski 	char nvlname[64];
750*832dc76bSMariusz Zaborski 	int n;
751*832dc76bSMariusz Zaborski 
752*832dc76bSMariusz Zaborski 	nvlist_add_string(nvl, "name", hp->h_name);
753*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "addrtype", (uint64_t)hp->h_addrtype);
754*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "length", (uint64_t)hp->h_length);
755*832dc76bSMariusz Zaborski 
756*832dc76bSMariusz Zaborski 	if (hp->h_aliases == NULL) {
757*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "naliases", 0);
758*832dc76bSMariusz Zaborski 	} else {
759*832dc76bSMariusz Zaborski 		for (ii = 0; hp->h_aliases[ii] != NULL; ii++) {
760*832dc76bSMariusz Zaborski 			n = snprintf(nvlname, sizeof(nvlname), "alias%u", ii);
761*832dc76bSMariusz Zaborski 			assert(n > 0 && n < (int)sizeof(nvlname));
762*832dc76bSMariusz Zaborski 			nvlist_add_string(nvl, nvlname, hp->h_aliases[ii]);
763*832dc76bSMariusz Zaborski 		}
764*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "naliases", (uint64_t)ii);
765*832dc76bSMariusz Zaborski 	}
766*832dc76bSMariusz Zaborski 
767*832dc76bSMariusz Zaborski 	if (hp->h_addr_list == NULL) {
768*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "naddrs", 0);
769*832dc76bSMariusz Zaborski 	} else {
770*832dc76bSMariusz Zaborski 		for (ii = 0; hp->h_addr_list[ii] != NULL; ii++) {
771*832dc76bSMariusz Zaborski 			n = snprintf(nvlname, sizeof(nvlname), "addr%u", ii);
772*832dc76bSMariusz Zaborski 			assert(n > 0 && n < (int)sizeof(nvlname));
773*832dc76bSMariusz Zaborski 			nvlist_add_binary(nvl, nvlname, hp->h_addr_list[ii],
774*832dc76bSMariusz Zaborski 			    (size_t)hp->h_length);
775*832dc76bSMariusz Zaborski 			if (addtocache) {
776*832dc76bSMariusz Zaborski 				net_add_hostent_to_cache(hp->h_addr_list[ii],
777*832dc76bSMariusz Zaborski 				    hp->h_length, hp->h_addrtype);
778*832dc76bSMariusz Zaborski 			}
779*832dc76bSMariusz Zaborski 		}
780*832dc76bSMariusz Zaborski 		nvlist_add_number(nvl, "naddrs", (uint64_t)ii);
781*832dc76bSMariusz Zaborski 	}
782*832dc76bSMariusz Zaborski }
783*832dc76bSMariusz Zaborski 
784*832dc76bSMariusz Zaborski static int
785*832dc76bSMariusz Zaborski net_gethostbyname(const nvlist_t *limits, const nvlist_t *nvlin,
786*832dc76bSMariusz Zaborski     nvlist_t *nvlout)
787*832dc76bSMariusz Zaborski {
788*832dc76bSMariusz Zaborski 	struct hostent *hp;
789*832dc76bSMariusz Zaborski 	int family;
790*832dc76bSMariusz Zaborski 	const nvlist_t *funclimit;
791*832dc76bSMariusz Zaborski 	const char *name;
792*832dc76bSMariusz Zaborski 	bool dnscache;
793*832dc76bSMariusz Zaborski 
794*832dc76bSMariusz Zaborski 	if (!net_allowed_mode(limits, CAPNET_DEPRECATED_NAME2ADDR))
795*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
796*832dc76bSMariusz Zaborski 
797*832dc76bSMariusz Zaborski 	dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS);
798*832dc76bSMariusz Zaborski 	funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, NULL);
799*832dc76bSMariusz Zaborski 
800*832dc76bSMariusz Zaborski 	family = (int)nvlist_get_number(nvlin, "family");
801*832dc76bSMariusz Zaborski 	if (!net_allowed_family(funclimit, family))
802*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
803*832dc76bSMariusz Zaborski 
804*832dc76bSMariusz Zaborski 	name = nvlist_get_string(nvlin, "name");
805*832dc76bSMariusz Zaborski 	if (!net_allowed_hosts(funclimit, name, ""))
806*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
807*832dc76bSMariusz Zaborski 
808*832dc76bSMariusz Zaborski 	hp = gethostbyname2(name, family);
809*832dc76bSMariusz Zaborski 	if (hp == NULL)
810*832dc76bSMariusz Zaborski 		return (h_errno);
811*832dc76bSMariusz Zaborski 	hostent_pack(hp, nvlout, dnscache);
812*832dc76bSMariusz Zaborski 	return (0);
813*832dc76bSMariusz Zaborski }
814*832dc76bSMariusz Zaborski 
815*832dc76bSMariusz Zaborski static int
816*832dc76bSMariusz Zaborski net_gethostbyaddr(const nvlist_t *limits, const nvlist_t *nvlin,
817*832dc76bSMariusz Zaborski     nvlist_t *nvlout)
818*832dc76bSMariusz Zaborski {
819*832dc76bSMariusz Zaborski 	struct hostent *hp;
820*832dc76bSMariusz Zaborski 	const void *addr;
821*832dc76bSMariusz Zaborski 	size_t addrsize;
822*832dc76bSMariusz Zaborski 	int family;
823*832dc76bSMariusz Zaborski 	const nvlist_t *funclimit;
824*832dc76bSMariusz Zaborski 
825*832dc76bSMariusz Zaborski 	if (!net_allowed_mode(limits, CAPNET_DEPRECATED_ADDR2NAME))
826*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
827*832dc76bSMariusz Zaborski 
828*832dc76bSMariusz Zaborski 	funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, NULL);
829*832dc76bSMariusz Zaborski 
830*832dc76bSMariusz Zaborski 	family = (int)nvlist_get_number(nvlin, "family");
831*832dc76bSMariusz Zaborski 	if (!net_allowed_family(funclimit, family))
832*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
833*832dc76bSMariusz Zaborski 
834*832dc76bSMariusz Zaborski 	addr = nvlist_get_binary(nvlin, "addr", &addrsize);
835*832dc76bSMariusz Zaborski 	if (!net_allowed_bsaddr(funclimit, addr, addrsize))
836*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
837*832dc76bSMariusz Zaborski 
838*832dc76bSMariusz Zaborski 	hp = gethostbyaddr(addr, (socklen_t)addrsize, family);
839*832dc76bSMariusz Zaborski 	if (hp == NULL)
840*832dc76bSMariusz Zaborski 		return (h_errno);
841*832dc76bSMariusz Zaborski 	hostent_pack(hp, nvlout, false);
842*832dc76bSMariusz Zaborski 	return (0);
843*832dc76bSMariusz Zaborski }
844*832dc76bSMariusz Zaborski 
845*832dc76bSMariusz Zaborski static int
846*832dc76bSMariusz Zaborski net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
847*832dc76bSMariusz Zaborski {
848*832dc76bSMariusz Zaborski 	struct sockaddr_storage sast;
849*832dc76bSMariusz Zaborski 	const void *sabin;
850*832dc76bSMariusz Zaborski 	char *host, *serv;
851*832dc76bSMariusz Zaborski 	size_t sabinsize, hostlen, servlen;
852*832dc76bSMariusz Zaborski 	socklen_t salen;
853*832dc76bSMariusz Zaborski 	int error, flags;
854*832dc76bSMariusz Zaborski 	const nvlist_t *funclimit;
855*832dc76bSMariusz Zaborski 
856*832dc76bSMariusz Zaborski 	if (!net_allowed_mode(limits, CAPNET_ADDR2NAME))
857*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
858*832dc76bSMariusz Zaborski 	funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME, NULL);
859*832dc76bSMariusz Zaborski 
860*832dc76bSMariusz Zaborski 	error = 0;
861*832dc76bSMariusz Zaborski 	host = serv = NULL;
862*832dc76bSMariusz Zaborski 	memset(&sast, 0, sizeof(sast));
863*832dc76bSMariusz Zaborski 
864*832dc76bSMariusz Zaborski 	hostlen = (size_t)nvlist_get_number(nvlin, "hostlen");
865*832dc76bSMariusz Zaborski 	servlen = (size_t)nvlist_get_number(nvlin, "servlen");
866*832dc76bSMariusz Zaborski 
867*832dc76bSMariusz Zaborski 	if (hostlen > 0) {
868*832dc76bSMariusz Zaborski 		host = calloc(1, hostlen + 1);
869*832dc76bSMariusz Zaborski 		if (host == NULL) {
870*832dc76bSMariusz Zaborski 			error = EAI_MEMORY;
871*832dc76bSMariusz Zaborski 			goto out;
872*832dc76bSMariusz Zaborski 		}
873*832dc76bSMariusz Zaborski 	}
874*832dc76bSMariusz Zaborski 	if (servlen > 0) {
875*832dc76bSMariusz Zaborski 		serv = calloc(1, servlen + 1);
876*832dc76bSMariusz Zaborski 		if (serv == NULL) {
877*832dc76bSMariusz Zaborski 			error = EAI_MEMORY;
878*832dc76bSMariusz Zaborski 			goto out;
879*832dc76bSMariusz Zaborski 		}
880*832dc76bSMariusz Zaborski 	}
881*832dc76bSMariusz Zaborski 
882*832dc76bSMariusz Zaborski 	sabin = nvlist_get_binary(nvlin, "sa", &sabinsize);
883*832dc76bSMariusz Zaborski 	if (sabinsize > sizeof(sast)) {
884*832dc76bSMariusz Zaborski 		error = EAI_FAIL;
885*832dc76bSMariusz Zaborski 		goto out;
886*832dc76bSMariusz Zaborski 	}
887*832dc76bSMariusz Zaborski 	if (!net_allowed_bsaddr(funclimit, sabin, sabinsize))
888*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
889*832dc76bSMariusz Zaborski 
890*832dc76bSMariusz Zaborski 	memcpy(&sast, sabin, sabinsize);
891*832dc76bSMariusz Zaborski 	salen = (socklen_t)sabinsize;
892*832dc76bSMariusz Zaborski 
893*832dc76bSMariusz Zaborski 	if ((sast.ss_family != AF_INET ||
894*832dc76bSMariusz Zaborski 	     salen != sizeof(struct sockaddr_in)) &&
895*832dc76bSMariusz Zaborski 	    (sast.ss_family != AF_INET6 ||
896*832dc76bSMariusz Zaborski 	     salen != sizeof(struct sockaddr_in6))) {
897*832dc76bSMariusz Zaborski 		error = EAI_FAIL;
898*832dc76bSMariusz Zaborski 		goto out;
899*832dc76bSMariusz Zaborski 	}
900*832dc76bSMariusz Zaborski 
901*832dc76bSMariusz Zaborski 	if (!net_allowed_family(funclimit, (int)sast.ss_family)) {
902*832dc76bSMariusz Zaborski 		error = ENOTCAPABLE;
903*832dc76bSMariusz Zaborski 		goto out;
904*832dc76bSMariusz Zaborski 	}
905*832dc76bSMariusz Zaborski 
906*832dc76bSMariusz Zaborski 	flags = (int)nvlist_get_number(nvlin, "flags");
907*832dc76bSMariusz Zaborski 
908*832dc76bSMariusz Zaborski 	error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen,
909*832dc76bSMariusz Zaborski 	    serv, servlen, flags);
910*832dc76bSMariusz Zaborski 	if (error != 0)
911*832dc76bSMariusz Zaborski 		goto out;
912*832dc76bSMariusz Zaborski 
913*832dc76bSMariusz Zaborski 	if (host != NULL)
914*832dc76bSMariusz Zaborski 		nvlist_move_string(nvlout, "host", host);
915*832dc76bSMariusz Zaborski 	if (serv != NULL)
916*832dc76bSMariusz Zaborski 		nvlist_move_string(nvlout, "serv", serv);
917*832dc76bSMariusz Zaborski out:
918*832dc76bSMariusz Zaborski 	if (error != 0) {
919*832dc76bSMariusz Zaborski 		free(host);
920*832dc76bSMariusz Zaborski 		free(serv);
921*832dc76bSMariusz Zaborski 	}
922*832dc76bSMariusz Zaborski 	return (error);
923*832dc76bSMariusz Zaborski }
924*832dc76bSMariusz Zaborski 
925*832dc76bSMariusz Zaborski static nvlist_t *
926*832dc76bSMariusz Zaborski addrinfo_pack(const struct addrinfo *ai)
927*832dc76bSMariusz Zaborski {
928*832dc76bSMariusz Zaborski 	nvlist_t *nvl;
929*832dc76bSMariusz Zaborski 
930*832dc76bSMariusz Zaborski 	nvl = nvlist_create(0);
931*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "ai_flags", (uint64_t)ai->ai_flags);
932*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "ai_family", (uint64_t)ai->ai_family);
933*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "ai_socktype", (uint64_t)ai->ai_socktype);
934*832dc76bSMariusz Zaborski 	nvlist_add_number(nvl, "ai_protocol", (uint64_t)ai->ai_protocol);
935*832dc76bSMariusz Zaborski 	nvlist_add_binary(nvl, "ai_addr", ai->ai_addr, (size_t)ai->ai_addrlen);
936*832dc76bSMariusz Zaborski 	if (ai->ai_canonname != NULL)
937*832dc76bSMariusz Zaborski 		nvlist_add_string(nvl, "ai_canonname", ai->ai_canonname);
938*832dc76bSMariusz Zaborski 
939*832dc76bSMariusz Zaborski 	return (nvl);
940*832dc76bSMariusz Zaborski }
941*832dc76bSMariusz Zaborski 
942*832dc76bSMariusz Zaborski static int
943*832dc76bSMariusz Zaborski net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
944*832dc76bSMariusz Zaborski {
945*832dc76bSMariusz Zaborski 	struct addrinfo hints, *hintsp, *res, *cur;
946*832dc76bSMariusz Zaborski 	const char *hostname, *servname;
947*832dc76bSMariusz Zaborski 	char nvlname[64];
948*832dc76bSMariusz Zaborski 	nvlist_t *elem;
949*832dc76bSMariusz Zaborski 	unsigned int ii;
950*832dc76bSMariusz Zaborski 	int error, family, n;
951*832dc76bSMariusz Zaborski 	const nvlist_t *funclimit;
952*832dc76bSMariusz Zaborski 	bool dnscache;
953*832dc76bSMariusz Zaborski 
954*832dc76bSMariusz Zaborski 	if (!net_allowed_mode(limits, CAPNET_NAME2ADDR))
955*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
956*832dc76bSMariusz Zaborski 	dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS);
957*832dc76bSMariusz Zaborski 	funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_NAME2ADDR, NULL);
958*832dc76bSMariusz Zaborski 
959*832dc76bSMariusz Zaborski 	hostname = dnvlist_get_string(nvlin, "hostname", NULL);
960*832dc76bSMariusz Zaborski 	servname = dnvlist_get_string(nvlin, "servname", NULL);
961*832dc76bSMariusz Zaborski 	if (nvlist_exists_number(nvlin, "hints.ai_flags")) {
962*832dc76bSMariusz Zaborski 		hints.ai_flags = (int)nvlist_get_number(nvlin,
963*832dc76bSMariusz Zaborski 		    "hints.ai_flags");
964*832dc76bSMariusz Zaborski 		hints.ai_family = (int)nvlist_get_number(nvlin,
965*832dc76bSMariusz Zaborski 		    "hints.ai_family");
966*832dc76bSMariusz Zaborski 		hints.ai_socktype = (int)nvlist_get_number(nvlin,
967*832dc76bSMariusz Zaborski 		    "hints.ai_socktype");
968*832dc76bSMariusz Zaborski 		hints.ai_protocol = (int)nvlist_get_number(nvlin,
969*832dc76bSMariusz Zaborski 		    "hints.ai_protocol");
970*832dc76bSMariusz Zaborski 		hints.ai_addrlen = 0;
971*832dc76bSMariusz Zaborski 		hints.ai_addr = NULL;
972*832dc76bSMariusz Zaborski 		hints.ai_canonname = NULL;
973*832dc76bSMariusz Zaborski 		hints.ai_next = NULL;
974*832dc76bSMariusz Zaborski 		hintsp = &hints;
975*832dc76bSMariusz Zaborski 		family = hints.ai_family;
976*832dc76bSMariusz Zaborski 	} else {
977*832dc76bSMariusz Zaborski 		hintsp = NULL;
978*832dc76bSMariusz Zaborski 		family = AF_UNSPEC;
979*832dc76bSMariusz Zaborski 	}
980*832dc76bSMariusz Zaborski 
981*832dc76bSMariusz Zaborski 	if (!net_allowed_family(funclimit, family))
982*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
983*832dc76bSMariusz Zaborski 	if (!net_allowed_hosts(funclimit, hostname, servname))
984*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
985*832dc76bSMariusz Zaborski 	error = getaddrinfo(hostname, servname, hintsp, &res);
986*832dc76bSMariusz Zaborski 	if (error != 0) {
987*832dc76bSMariusz Zaborski 		goto out;
988*832dc76bSMariusz Zaborski 	}
989*832dc76bSMariusz Zaborski 
990*832dc76bSMariusz Zaborski 	for (cur = res, ii = 0; cur != NULL; cur = cur->ai_next, ii++) {
991*832dc76bSMariusz Zaborski 		elem = addrinfo_pack(cur);
992*832dc76bSMariusz Zaborski 		n = snprintf(nvlname, sizeof(nvlname), "res%u", ii);
993*832dc76bSMariusz Zaborski 		assert(n > 0 && n < (int)sizeof(nvlname));
994*832dc76bSMariusz Zaborski 		nvlist_move_nvlist(nvlout, nvlname, elem);
995*832dc76bSMariusz Zaborski 		if (dnscache) {
996*832dc76bSMariusz Zaborski 			net_add_sockaddr_to_cache(cur->ai_addr,
997*832dc76bSMariusz Zaborski 			    cur->ai_addrlen, false);
998*832dc76bSMariusz Zaborski 		}
999*832dc76bSMariusz Zaborski 	}
1000*832dc76bSMariusz Zaborski 
1001*832dc76bSMariusz Zaborski 	freeaddrinfo(res);
1002*832dc76bSMariusz Zaborski 	error = 0;
1003*832dc76bSMariusz Zaborski out:
1004*832dc76bSMariusz Zaborski 	return (error);
1005*832dc76bSMariusz Zaborski }
1006*832dc76bSMariusz Zaborski 
1007*832dc76bSMariusz Zaborski static int
1008*832dc76bSMariusz Zaborski net_bind(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout)
1009*832dc76bSMariusz Zaborski {
1010*832dc76bSMariusz Zaborski 	int socket, serrno;
1011*832dc76bSMariusz Zaborski 	const void *saddr;
1012*832dc76bSMariusz Zaborski 	size_t len;
1013*832dc76bSMariusz Zaborski 	const nvlist_t *funclimit;
1014*832dc76bSMariusz Zaborski 
1015*832dc76bSMariusz Zaborski 	if (!net_allowed_mode(limits, CAPNET_BIND))
1016*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1017*832dc76bSMariusz Zaborski 	funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_BIND, NULL);
1018*832dc76bSMariusz Zaborski 
1019*832dc76bSMariusz Zaborski 	saddr = nvlist_get_binary(nvlin, "saddr", &len);
1020*832dc76bSMariusz Zaborski 
1021*832dc76bSMariusz Zaborski 	if (!net_allowed_bsaddr(funclimit, saddr, len))
1022*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1023*832dc76bSMariusz Zaborski 
1024*832dc76bSMariusz Zaborski 	socket = nvlist_take_descriptor(nvlin, "s");
1025*832dc76bSMariusz Zaborski 	if (bind(socket, saddr, len) < 0) {
1026*832dc76bSMariusz Zaborski 		serrno = errno;
1027*832dc76bSMariusz Zaborski 		close(socket);
1028*832dc76bSMariusz Zaborski 		return (serrno);
1029*832dc76bSMariusz Zaborski 	}
1030*832dc76bSMariusz Zaborski 
1031*832dc76bSMariusz Zaborski 	nvlist_move_descriptor(nvlout, "s", socket);
1032*832dc76bSMariusz Zaborski 
1033*832dc76bSMariusz Zaborski 	return (0);
1034*832dc76bSMariusz Zaborski }
1035*832dc76bSMariusz Zaborski 
1036*832dc76bSMariusz Zaborski static int
1037*832dc76bSMariusz Zaborski net_connect(const nvlist_t *limits, nvlist_t *nvlin, nvlist_t *nvlout)
1038*832dc76bSMariusz Zaborski {
1039*832dc76bSMariusz Zaborski 	int socket, serrno;
1040*832dc76bSMariusz Zaborski 	const void *saddr;
1041*832dc76bSMariusz Zaborski 	const nvlist_t *funclimit;
1042*832dc76bSMariusz Zaborski 	size_t len;
1043*832dc76bSMariusz Zaborski 	bool conn, conndns;
1044*832dc76bSMariusz Zaborski 
1045*832dc76bSMariusz Zaborski 	conn = net_allowed_mode(limits, CAPNET_CONNECT);
1046*832dc76bSMariusz Zaborski 	conndns = net_allowed_mode(limits, CAPNET_CONNECTDNS);
1047*832dc76bSMariusz Zaborski 
1048*832dc76bSMariusz Zaborski 	if (!conn && !conndns)
1049*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1050*832dc76bSMariusz Zaborski 
1051*832dc76bSMariusz Zaborski 	funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_CONNECT, NULL);
1052*832dc76bSMariusz Zaborski 
1053*832dc76bSMariusz Zaborski 	saddr = nvlist_get_binary(nvlin, "saddr", &len);
1054*832dc76bSMariusz Zaborski 	if (conn && !net_allowed_bsaddr(funclimit, saddr, len)) {
1055*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1056*832dc76bSMariusz Zaborski 	} else if (conndns && (capdnscache == NULL ||
1057*832dc76bSMariusz Zaborski 	   !net_allowed_bsaddr_impl(capdnscache, saddr, len))) {
1058*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1059*832dc76bSMariusz Zaborski 	}
1060*832dc76bSMariusz Zaborski 	socket = dup(nvlist_get_descriptor(nvlin, "s"));
1061*832dc76bSMariusz Zaborski 	if (connect(socket, saddr, len) < 0) {
1062*832dc76bSMariusz Zaborski 		serrno = errno;
1063*832dc76bSMariusz Zaborski 		close(socket);
1064*832dc76bSMariusz Zaborski 		return (serrno);
1065*832dc76bSMariusz Zaborski 	}
1066*832dc76bSMariusz Zaborski 
1067*832dc76bSMariusz Zaborski 	nvlist_move_descriptor(nvlout, "s", socket);
1068*832dc76bSMariusz Zaborski 
1069*832dc76bSMariusz Zaborski 	return (0);
1070*832dc76bSMariusz Zaborski }
1071*832dc76bSMariusz Zaborski 
1072*832dc76bSMariusz Zaborski static bool
1073*832dc76bSMariusz Zaborski verify_only_sa_newlimts(const nvlist_t *oldfunclimits,
1074*832dc76bSMariusz Zaborski     const nvlist_t *newfunclimit)
1075*832dc76bSMariusz Zaborski {
1076*832dc76bSMariusz Zaborski 	void *cookie;
1077*832dc76bSMariusz Zaborski 
1078*832dc76bSMariusz Zaborski 	cookie = NULL;
1079*832dc76bSMariusz Zaborski 	while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) {
1080*832dc76bSMariusz Zaborski 		void *sacookie;
1081*832dc76bSMariusz Zaborski 
1082*832dc76bSMariusz Zaborski 		if (strcmp(cnvlist_name(cookie), "sockaddr") != 0)
1083*832dc76bSMariusz Zaborski 			return (false);
1084*832dc76bSMariusz Zaborski 
1085*832dc76bSMariusz Zaborski 		if (cnvlist_type(cookie) != NV_TYPE_NVLIST)
1086*832dc76bSMariusz Zaborski 			return (false);
1087*832dc76bSMariusz Zaborski 
1088*832dc76bSMariusz Zaborski 		sacookie = NULL;
1089*832dc76bSMariusz Zaborski 		while (nvlist_next(cnvlist_get_nvlist(cookie), NULL,
1090*832dc76bSMariusz Zaborski 		    &sacookie) != NULL) {
1091*832dc76bSMariusz Zaborski 			const void *sa;
1092*832dc76bSMariusz Zaborski 			size_t sasize;
1093*832dc76bSMariusz Zaborski 
1094*832dc76bSMariusz Zaborski 			if (cnvlist_type(sacookie) != NV_TYPE_BINARY)
1095*832dc76bSMariusz Zaborski 				return (false);
1096*832dc76bSMariusz Zaborski 
1097*832dc76bSMariusz Zaborski 			sa = cnvlist_get_binary(sacookie, &sasize);
1098*832dc76bSMariusz Zaborski 			if (!net_allowed_bsaddr(oldfunclimits, sa, sasize))
1099*832dc76bSMariusz Zaborski 				return (false);
1100*832dc76bSMariusz Zaborski 		}
1101*832dc76bSMariusz Zaborski 	}
1102*832dc76bSMariusz Zaborski 
1103*832dc76bSMariusz Zaborski 	return (true);
1104*832dc76bSMariusz Zaborski }
1105*832dc76bSMariusz Zaborski 
1106*832dc76bSMariusz Zaborski static bool
1107*832dc76bSMariusz Zaborski verify_bind_newlimts(const nvlist_t *oldlimits,
1108*832dc76bSMariusz Zaborski     const nvlist_t *newfunclimit)
1109*832dc76bSMariusz Zaborski {
1110*832dc76bSMariusz Zaborski 	const nvlist_t *oldfunclimits;
1111*832dc76bSMariusz Zaborski 
1112*832dc76bSMariusz Zaborski 	oldfunclimits = NULL;
1113*832dc76bSMariusz Zaborski 	if (oldlimits != NULL) {
1114*832dc76bSMariusz Zaborski 		oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_BIND,
1115*832dc76bSMariusz Zaborski 		    NULL);
1116*832dc76bSMariusz Zaborski 	}
1117*832dc76bSMariusz Zaborski 
1118*832dc76bSMariusz Zaborski 	return (verify_only_sa_newlimts(oldfunclimits, newfunclimit));
1119*832dc76bSMariusz Zaborski }
1120*832dc76bSMariusz Zaborski 
1121*832dc76bSMariusz Zaborski 
1122*832dc76bSMariusz Zaborski static bool
1123*832dc76bSMariusz Zaborski verify_connect_newlimits(const nvlist_t *oldlimits,
1124*832dc76bSMariusz Zaborski     const nvlist_t *newfunclimit)
1125*832dc76bSMariusz Zaborski {
1126*832dc76bSMariusz Zaborski 	const nvlist_t *oldfunclimits;
1127*832dc76bSMariusz Zaborski 
1128*832dc76bSMariusz Zaborski 	oldfunclimits = NULL;
1129*832dc76bSMariusz Zaborski 	if (oldlimits != NULL) {
1130*832dc76bSMariusz Zaborski 		oldfunclimits = dnvlist_get_nvlist(oldlimits, LIMIT_NV_CONNECT,
1131*832dc76bSMariusz Zaborski 		    NULL);
1132*832dc76bSMariusz Zaborski 	}
1133*832dc76bSMariusz Zaborski 
1134*832dc76bSMariusz Zaborski 	return (verify_only_sa_newlimts(oldfunclimits, newfunclimit));
1135*832dc76bSMariusz Zaborski }
1136*832dc76bSMariusz Zaborski 
1137*832dc76bSMariusz Zaborski static bool
1138*832dc76bSMariusz Zaborski verify_addr2name_newlimits(const nvlist_t *oldlimits,
1139*832dc76bSMariusz Zaborski     const nvlist_t *newfunclimit)
1140*832dc76bSMariusz Zaborski {
1141*832dc76bSMariusz Zaborski 	void *cookie;
1142*832dc76bSMariusz Zaborski 	const nvlist_t *oldfunclimits;
1143*832dc76bSMariusz Zaborski 
1144*832dc76bSMariusz Zaborski 	oldfunclimits = NULL;
1145*832dc76bSMariusz Zaborski 	if (oldlimits != NULL) {
1146*832dc76bSMariusz Zaborski 		oldfunclimits = dnvlist_get_nvlist(oldlimits,
1147*832dc76bSMariusz Zaborski 		    LIMIT_NV_ADDR2NAME, NULL);
1148*832dc76bSMariusz Zaborski 	}
1149*832dc76bSMariusz Zaborski 
1150*832dc76bSMariusz Zaborski 	cookie = NULL;
1151*832dc76bSMariusz Zaborski 	while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) {
1152*832dc76bSMariusz Zaborski 		if (strcmp(cnvlist_name(cookie), "sockaddr") == 0) {
1153*832dc76bSMariusz Zaborski 			void *sacookie;
1154*832dc76bSMariusz Zaborski 
1155*832dc76bSMariusz Zaborski 			if (cnvlist_type(cookie) != NV_TYPE_NVLIST)
1156*832dc76bSMariusz Zaborski 				return (false);
1157*832dc76bSMariusz Zaborski 
1158*832dc76bSMariusz Zaborski 			sacookie = NULL;
1159*832dc76bSMariusz Zaborski 			while (nvlist_next(cnvlist_get_nvlist(cookie), NULL,
1160*832dc76bSMariusz Zaborski 			    &sacookie) != NULL) {
1161*832dc76bSMariusz Zaborski 				const void *sa;
1162*832dc76bSMariusz Zaborski 				size_t sasize;
1163*832dc76bSMariusz Zaborski 
1164*832dc76bSMariusz Zaborski 				if (cnvlist_type(sacookie) != NV_TYPE_BINARY)
1165*832dc76bSMariusz Zaborski 					return (false);
1166*832dc76bSMariusz Zaborski 
1167*832dc76bSMariusz Zaborski 				sa = cnvlist_get_binary(sacookie, &sasize);
1168*832dc76bSMariusz Zaborski 				if (!net_allowed_bsaddr(oldfunclimits, sa,
1169*832dc76bSMariusz Zaborski 				    sasize)) {
1170*832dc76bSMariusz Zaborski 					return (false);
1171*832dc76bSMariusz Zaborski 				}
1172*832dc76bSMariusz Zaborski 			}
1173*832dc76bSMariusz Zaborski 		} else if (strcmp(cnvlist_name(cookie), "family") == 0) {
1174*832dc76bSMariusz Zaborski 			size_t i, sfamilies;
1175*832dc76bSMariusz Zaborski 			const uint64_t *families;
1176*832dc76bSMariusz Zaborski 
1177*832dc76bSMariusz Zaborski 			if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY)
1178*832dc76bSMariusz Zaborski 				return (false);
1179*832dc76bSMariusz Zaborski 
1180*832dc76bSMariusz Zaborski 			families = cnvlist_get_number_array(cookie, &sfamilies);
1181*832dc76bSMariusz Zaborski 			for (i = 0; i < sfamilies; i++) {
1182*832dc76bSMariusz Zaborski 				if (!net_allowed_family(oldfunclimits,
1183*832dc76bSMariusz Zaborski 				    families[i])) {
1184*832dc76bSMariusz Zaborski 					return (false);
1185*832dc76bSMariusz Zaborski 				}
1186*832dc76bSMariusz Zaborski 			}
1187*832dc76bSMariusz Zaborski 		} else {
1188*832dc76bSMariusz Zaborski 			return (false);
1189*832dc76bSMariusz Zaborski 		}
1190*832dc76bSMariusz Zaborski 	}
1191*832dc76bSMariusz Zaborski 
1192*832dc76bSMariusz Zaborski 	return (true);
1193*832dc76bSMariusz Zaborski }
1194*832dc76bSMariusz Zaborski 
1195*832dc76bSMariusz Zaborski static bool
1196*832dc76bSMariusz Zaborski verify_name2addr_newlimits(const nvlist_t *oldlimits,
1197*832dc76bSMariusz Zaborski     const nvlist_t *newfunclimit)
1198*832dc76bSMariusz Zaborski {
1199*832dc76bSMariusz Zaborski 	void *cookie;
1200*832dc76bSMariusz Zaborski 	const nvlist_t *oldfunclimits;
1201*832dc76bSMariusz Zaborski 
1202*832dc76bSMariusz Zaborski 	oldfunclimits = NULL;
1203*832dc76bSMariusz Zaborski 	if (oldlimits != NULL) {
1204*832dc76bSMariusz Zaborski 		oldfunclimits = dnvlist_get_nvlist(oldlimits,
1205*832dc76bSMariusz Zaborski 		    LIMIT_NV_ADDR2NAME, NULL);
1206*832dc76bSMariusz Zaborski 	}
1207*832dc76bSMariusz Zaborski 
1208*832dc76bSMariusz Zaborski 	cookie = NULL;
1209*832dc76bSMariusz Zaborski 	while (nvlist_next(newfunclimit, NULL, &cookie) != NULL) {
1210*832dc76bSMariusz Zaborski 		if (strcmp(cnvlist_name(cookie), "hosts") == 0) {
1211*832dc76bSMariusz Zaborski 			void *hostcookie;
1212*832dc76bSMariusz Zaborski 
1213*832dc76bSMariusz Zaborski 			if (cnvlist_type(cookie) != NV_TYPE_NVLIST)
1214*832dc76bSMariusz Zaborski 				return (false);
1215*832dc76bSMariusz Zaborski 
1216*832dc76bSMariusz Zaborski 			hostcookie = NULL;
1217*832dc76bSMariusz Zaborski 			while (nvlist_next(cnvlist_get_nvlist(cookie), NULL,
1218*832dc76bSMariusz Zaborski 			    &hostcookie) != NULL) {
1219*832dc76bSMariusz Zaborski 				if (cnvlist_type(hostcookie) != NV_TYPE_STRING)
1220*832dc76bSMariusz Zaborski 					return (false);
1221*832dc76bSMariusz Zaborski 
1222*832dc76bSMariusz Zaborski 				if (!net_allowed_hosts(oldfunclimits,
1223*832dc76bSMariusz Zaborski 				    cnvlist_name(hostcookie),
1224*832dc76bSMariusz Zaborski 				    cnvlist_get_string(hostcookie))) {
1225*832dc76bSMariusz Zaborski 					return (false);
1226*832dc76bSMariusz Zaborski 				}
1227*832dc76bSMariusz Zaborski 			}
1228*832dc76bSMariusz Zaborski 		} else if (strcmp(cnvlist_name(cookie), "family") == 0) {
1229*832dc76bSMariusz Zaborski 			size_t i, sfamilies;
1230*832dc76bSMariusz Zaborski 			const uint64_t *families;
1231*832dc76bSMariusz Zaborski 
1232*832dc76bSMariusz Zaborski 			if (cnvlist_type(cookie) != NV_TYPE_NUMBER_ARRAY)
1233*832dc76bSMariusz Zaborski 				return (false);
1234*832dc76bSMariusz Zaborski 
1235*832dc76bSMariusz Zaborski 			families = cnvlist_get_number_array(cookie, &sfamilies);
1236*832dc76bSMariusz Zaborski 			for (i = 0; i < sfamilies; i++) {
1237*832dc76bSMariusz Zaborski 				if (!net_allowed_family(oldfunclimits,
1238*832dc76bSMariusz Zaborski 				    families[i])) {
1239*832dc76bSMariusz Zaborski 					return (false);
1240*832dc76bSMariusz Zaborski 				}
1241*832dc76bSMariusz Zaborski 			}
1242*832dc76bSMariusz Zaborski 		} else {
1243*832dc76bSMariusz Zaborski 			return (false);
1244*832dc76bSMariusz Zaborski 		}
1245*832dc76bSMariusz Zaborski 	}
1246*832dc76bSMariusz Zaborski 
1247*832dc76bSMariusz Zaborski 	return (true);
1248*832dc76bSMariusz Zaborski }
1249*832dc76bSMariusz Zaborski 
1250*832dc76bSMariusz Zaborski static int
1251*832dc76bSMariusz Zaborski net_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
1252*832dc76bSMariusz Zaborski {
1253*832dc76bSMariusz Zaborski 	const char *name;
1254*832dc76bSMariusz Zaborski 	void *cookie;
1255*832dc76bSMariusz Zaborski 	bool hasmode, hasconnect, hasbind, hasaddr2name, hasname2addr;
1256*832dc76bSMariusz Zaborski 
1257*832dc76bSMariusz Zaborski 	/*
1258*832dc76bSMariusz Zaborski 	 * Modes:
1259*832dc76bSMariusz Zaborski 	 *	ADDR2NAME:
1260*832dc76bSMariusz Zaborski 	 *		getnameinfo
1261*832dc76bSMariusz Zaborski 	 *	DEPRECATED_ADDR2NAME:
1262*832dc76bSMariusz Zaborski 	 *		gethostbyaddr
1263*832dc76bSMariusz Zaborski 	 *
1264*832dc76bSMariusz Zaborski 	 *	NAME2ADDR:
1265*832dc76bSMariusz Zaborski 	 *		getaddrinfo
1266*832dc76bSMariusz Zaborski 	 *	DEPRECATED_NAME2ADDR:
1267*832dc76bSMariusz Zaborski 	 *		gethostbyname
1268*832dc76bSMariusz Zaborski 	 *
1269*832dc76bSMariusz Zaborski 	 * Limit scheme:
1270*832dc76bSMariusz Zaborski 	 *	mode	: NV_TYPE_NUMBER
1271*832dc76bSMariusz Zaborski 	 *	connect : NV_TYPE_NVLIST
1272*832dc76bSMariusz Zaborski 	 *		sockaddr : NV_TYPE_NVLIST
1273*832dc76bSMariusz Zaborski 	 *			""	: NV_TYPE_BINARY
1274*832dc76bSMariusz Zaborski 	 *			...	: NV_TYPE_BINARY
1275*832dc76bSMariusz Zaborski 	 *	bind	: NV_TYPE_NVLIST
1276*832dc76bSMariusz Zaborski 	 *		sockaddr : NV_TYPE_NVLIST
1277*832dc76bSMariusz Zaborski 	 *			""	: NV_TYPE_BINARY
1278*832dc76bSMariusz Zaborski 	 *			...	: NV_TYPE_BINARY
1279*832dc76bSMariusz Zaborski 	 *	addr2name : NV_TYPE_NVLIST
1280*832dc76bSMariusz Zaborski 	 *		family  : NV_TYPE_NUMBER_ARRAY
1281*832dc76bSMariusz Zaborski 	 *		sockaddr : NV_TYPE_NVLIST
1282*832dc76bSMariusz Zaborski 	 *			""	: NV_TYPE_BINARY
1283*832dc76bSMariusz Zaborski 	 *			...	: NV_TYPE_BINARY
1284*832dc76bSMariusz Zaborski 	 *	name2addr : NV_TYPE_NVLIST
1285*832dc76bSMariusz Zaborski 	 *		family : NV_TYPE_NUMBER
1286*832dc76bSMariusz Zaborski 	 *		hosts	: NV_TYPE_NVLIST
1287*832dc76bSMariusz Zaborski 	 *			host	: servname : NV_TYPE_STRING
1288*832dc76bSMariusz Zaborski 	 */
1289*832dc76bSMariusz Zaborski 
1290*832dc76bSMariusz Zaborski 	hasmode = false;
1291*832dc76bSMariusz Zaborski 	hasconnect = false;
1292*832dc76bSMariusz Zaborski 	hasbind = false;
1293*832dc76bSMariusz Zaborski 	hasaddr2name = false;
1294*832dc76bSMariusz Zaborski 	hasname2addr = false;
1295*832dc76bSMariusz Zaborski 
1296*832dc76bSMariusz Zaborski 	cookie = NULL;
1297*832dc76bSMariusz Zaborski 	while ((name = nvlist_next(newlimits, NULL, &cookie)) != NULL) {
1298*832dc76bSMariusz Zaborski 		if (strcmp(name, "mode") == 0) {
1299*832dc76bSMariusz Zaborski 			if (cnvlist_type(cookie) != NV_TYPE_NUMBER) {
1300*832dc76bSMariusz Zaborski 				return (NO_RECOVERY);
1301*832dc76bSMariusz Zaborski 			}
1302*832dc76bSMariusz Zaborski 			if (!net_allowed_mode(oldlimits,
1303*832dc76bSMariusz Zaborski 			    cnvlist_get_number(cookie))) {
1304*832dc76bSMariusz Zaborski 				return (ENOTCAPABLE);
1305*832dc76bSMariusz Zaborski 			}
1306*832dc76bSMariusz Zaborski 			hasmode = true;
1307*832dc76bSMariusz Zaborski 			continue;
1308*832dc76bSMariusz Zaborski 		}
1309*832dc76bSMariusz Zaborski 
1310*832dc76bSMariusz Zaborski 		if (cnvlist_type(cookie) != NV_TYPE_NVLIST) {
1311*832dc76bSMariusz Zaborski 			return (NO_RECOVERY);
1312*832dc76bSMariusz Zaborski 		}
1313*832dc76bSMariusz Zaborski 
1314*832dc76bSMariusz Zaborski 		if (strcmp(name, LIMIT_NV_BIND) == 0) {
1315*832dc76bSMariusz Zaborski 			hasbind = true;
1316*832dc76bSMariusz Zaborski 			if (!verify_bind_newlimts(oldlimits,
1317*832dc76bSMariusz Zaborski 			    cnvlist_get_nvlist(cookie))) {
1318*832dc76bSMariusz Zaborski 				return (ENOTCAPABLE);
1319*832dc76bSMariusz Zaborski 			}
1320*832dc76bSMariusz Zaborski 		} else if (strcmp(name, LIMIT_NV_CONNECT) == 0) {
1321*832dc76bSMariusz Zaborski 			hasconnect = true;
1322*832dc76bSMariusz Zaborski 			if (!verify_connect_newlimits(oldlimits,
1323*832dc76bSMariusz Zaborski 			    cnvlist_get_nvlist(cookie))) {
1324*832dc76bSMariusz Zaborski 				return (ENOTCAPABLE);
1325*832dc76bSMariusz Zaborski 			}
1326*832dc76bSMariusz Zaborski 		} else if (strcmp(name, LIMIT_NV_ADDR2NAME) == 0) {
1327*832dc76bSMariusz Zaborski 			hasaddr2name = true;
1328*832dc76bSMariusz Zaborski 			if (!verify_addr2name_newlimits(oldlimits,
1329*832dc76bSMariusz Zaborski 			    cnvlist_get_nvlist(cookie))) {
1330*832dc76bSMariusz Zaborski 				return (ENOTCAPABLE);
1331*832dc76bSMariusz Zaborski 			}
1332*832dc76bSMariusz Zaborski 		} else if (strcmp(name, LIMIT_NV_NAME2ADDR) == 0) {
1333*832dc76bSMariusz Zaborski 			hasname2addr = true;
1334*832dc76bSMariusz Zaborski 			if (!verify_name2addr_newlimits(oldlimits,
1335*832dc76bSMariusz Zaborski 			    cnvlist_get_nvlist(cookie))) {
1336*832dc76bSMariusz Zaborski 				return (ENOTCAPABLE);
1337*832dc76bSMariusz Zaborski 			}
1338*832dc76bSMariusz Zaborski 		}
1339*832dc76bSMariusz Zaborski 	}
1340*832dc76bSMariusz Zaborski 
1341*832dc76bSMariusz Zaborski 	/* Mode is required. */
1342*832dc76bSMariusz Zaborski 	if (!hasmode)
1343*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1344*832dc76bSMariusz Zaborski 
1345*832dc76bSMariusz Zaborski 	/*
1346*832dc76bSMariusz Zaborski 	 * If the new limit doesn't mention mode or family we have to
1347*832dc76bSMariusz Zaborski 	 * check if the current limit does have those. Missing mode or
1348*832dc76bSMariusz Zaborski 	 * family in the limit means that all modes or families are
1349*832dc76bSMariusz Zaborski 	 * allowed.
1350*832dc76bSMariusz Zaborski 	 */
1351*832dc76bSMariusz Zaborski 	if (oldlimits == NULL)
1352*832dc76bSMariusz Zaborski 		return (0);
1353*832dc76bSMariusz Zaborski 	if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_BIND))
1354*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1355*832dc76bSMariusz Zaborski 	if (!hasconnect && nvlist_exists(oldlimits, LIMIT_NV_CONNECT))
1356*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1357*832dc76bSMariusz Zaborski 	if (!hasaddr2name && nvlist_exists(oldlimits, LIMIT_NV_ADDR2NAME))
1358*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1359*832dc76bSMariusz Zaborski 	if (!hasname2addr && nvlist_exists(oldlimits, LIMIT_NV_NAME2ADDR))
1360*832dc76bSMariusz Zaborski 		return (ENOTCAPABLE);
1361*832dc76bSMariusz Zaborski 	return (0);
1362*832dc76bSMariusz Zaborski }
1363*832dc76bSMariusz Zaborski 
1364*832dc76bSMariusz Zaborski static int
1365*832dc76bSMariusz Zaborski net_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
1366*832dc76bSMariusz Zaborski     nvlist_t *nvlout)
1367*832dc76bSMariusz Zaborski {
1368*832dc76bSMariusz Zaborski 
1369*832dc76bSMariusz Zaborski 	if (strcmp(cmd, "bind") == 0)
1370*832dc76bSMariusz Zaborski 		return (net_bind(limits, nvlin, nvlout));
1371*832dc76bSMariusz Zaborski 	else if (strcmp(cmd, "connect") == 0)
1372*832dc76bSMariusz Zaborski 		return (net_connect(limits, nvlin, nvlout));
1373*832dc76bSMariusz Zaborski 	else if (strcmp(cmd, "gethostbyname") == 0)
1374*832dc76bSMariusz Zaborski 		return (net_gethostbyname(limits, nvlin, nvlout));
1375*832dc76bSMariusz Zaborski 	else if (strcmp(cmd, "gethostbyaddr") == 0)
1376*832dc76bSMariusz Zaborski 		return (net_gethostbyaddr(limits, nvlin, nvlout));
1377*832dc76bSMariusz Zaborski 	else if (strcmp(cmd, "getnameinfo") == 0)
1378*832dc76bSMariusz Zaborski 		return (net_getnameinfo(limits, nvlin, nvlout));
1379*832dc76bSMariusz Zaborski 	else if (strcmp(cmd, "getaddrinfo") == 0)
1380*832dc76bSMariusz Zaborski 		return (net_getaddrinfo(limits, nvlin, nvlout));
1381*832dc76bSMariusz Zaborski 
1382*832dc76bSMariusz Zaborski 	return (EINVAL);
1383*832dc76bSMariusz Zaborski }
1384*832dc76bSMariusz Zaborski 
1385*832dc76bSMariusz Zaborski CREATE_SERVICE("system.net", net_limit, net_command, 0);
1386