xref: /freebsd/sys/security/mac_ipacl/mac_ipacl.c (revision db33c6f3ae9d1231087710068ee4ea5398aacca7)
1215bab79SShivank Garg /*-
2215bab79SShivank Garg  * Copyright (c) 2003-2004 Networks Associates Technology, Inc.
3215bab79SShivank Garg  * Copyright (c) 2006 SPARTA, Inc.
4215bab79SShivank Garg  * Copyright (c) 2019, 2023 Shivank Garg <shivank@FreeBSD.org>
5215bab79SShivank Garg  *
6215bab79SShivank Garg  * This software was developed for the FreeBSD Project by Network
7215bab79SShivank Garg  * Associates Laboratories, the Security Research Division of Network
8215bab79SShivank Garg  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
9215bab79SShivank Garg  * as part of the DARPA CHATS research program.
10215bab79SShivank Garg  *
11215bab79SShivank Garg  * This software was enhanced by SPARTA ISSO under SPAWAR contract
12215bab79SShivank Garg  * N66001-04-C-6019 ("SEFOS").
13215bab79SShivank Garg  *
14215bab79SShivank Garg  * This code was developed as a Google Summer of Code 2019 project
15215bab79SShivank Garg  * under the guidance of Bjoern A. Zeeb.
16215bab79SShivank Garg  *
17215bab79SShivank Garg  * Redistribution and use in source and binary forms, with or without
18215bab79SShivank Garg  * modification, are permitted provided that the following conditions
19215bab79SShivank Garg  * are met:
20215bab79SShivank Garg  * 1. Redistributions of source code must retain the above copyright
21215bab79SShivank Garg  *    notice, this list of conditions and the following disclaimer.
22215bab79SShivank Garg  * 2. Redistributions in binary form must reproduce the above copyright
23215bab79SShivank Garg  *    notice, this list of conditions and the following disclaimer in the
24215bab79SShivank Garg  *    documentation and/or other materials provided with the distribution.
25215bab79SShivank Garg  *
26215bab79SShivank Garg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27215bab79SShivank Garg  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28215bab79SShivank Garg  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29215bab79SShivank Garg  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30215bab79SShivank Garg  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31215bab79SShivank Garg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32215bab79SShivank Garg  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33215bab79SShivank Garg  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34215bab79SShivank Garg  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35215bab79SShivank Garg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36215bab79SShivank Garg  * SUCH DAMAGE.
37215bab79SShivank Garg  */
38215bab79SShivank Garg 
39215bab79SShivank Garg /*
40215bab79SShivank Garg  * The IP address access control policy module - mac_ipacl allows the root of
41215bab79SShivank Garg  * the host to limit the VNET jail's privileges of setting IPv4 and IPv6
42215bab79SShivank Garg  * addresses via sysctl(8) interface. So, the host can define rules for jails
43215bab79SShivank Garg  * and their interfaces about IP addresses.
44215bab79SShivank Garg  * sysctl(8) is to be used to modify the rules string in following format-
45215bab79SShivank Garg  * "jail_id,allow,interface,address_family,IP_addr/prefix_length[@jail_id,...]"
46215bab79SShivank Garg  */
47215bab79SShivank Garg 
48215bab79SShivank Garg #include "opt_inet.h"
49215bab79SShivank Garg #include "opt_inet6.h"
50215bab79SShivank Garg 
51215bab79SShivank Garg #include <sys/param.h>
52215bab79SShivank Garg #include <sys/module.h>
53215bab79SShivank Garg #include <sys/errno.h>
54215bab79SShivank Garg #include <sys/kernel.h>
55215bab79SShivank Garg #include <sys/mutex.h>
56215bab79SShivank Garg #include <sys/priv.h>
57215bab79SShivank Garg #include <sys/queue.h>
58215bab79SShivank Garg #include <sys/socket.h>
59215bab79SShivank Garg #include <sys/sysctl.h>
60215bab79SShivank Garg #include <sys/systm.h>
61215bab79SShivank Garg #include <sys/types.h>
62215bab79SShivank Garg #include <sys/ucred.h>
63215bab79SShivank Garg #include <sys/jail.h>
64215bab79SShivank Garg 
65215bab79SShivank Garg #include <net/if.h>
66215bab79SShivank Garg #include <net/if_var.h>
67215bab79SShivank Garg 
68215bab79SShivank Garg #include <netinet/in.h>
69215bab79SShivank Garg #include <netinet6/scope6_var.h>
70215bab79SShivank Garg 
71215bab79SShivank Garg #include <security/mac/mac_policy.h>
72215bab79SShivank Garg 
73215bab79SShivank Garg static SYSCTL_NODE(_security_mac, OID_AUTO, ipacl, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
74215bab79SShivank Garg     "TrustedBSD mac_ipacl policy controls");
75215bab79SShivank Garg 
76215bab79SShivank Garg #ifdef INET
77215bab79SShivank Garg static int ipacl_ipv4 = 1;
78215bab79SShivank Garg SYSCTL_INT(_security_mac_ipacl, OID_AUTO, ipv4, CTLFLAG_RWTUN,
79215bab79SShivank Garg     &ipacl_ipv4, 0, "Enforce mac_ipacl for IPv4 addresses");
80215bab79SShivank Garg #endif
81215bab79SShivank Garg 
82215bab79SShivank Garg #ifdef INET6
83215bab79SShivank Garg static int ipacl_ipv6 = 1;
84215bab79SShivank Garg SYSCTL_INT(_security_mac_ipacl, OID_AUTO, ipv6, CTLFLAG_RWTUN,
85215bab79SShivank Garg     &ipacl_ipv6, 0, "Enforce mac_ipacl for IPv6 addresses");
86215bab79SShivank Garg #endif
87215bab79SShivank Garg 
88215bab79SShivank Garg static MALLOC_DEFINE(M_IPACL, "ipacl_rule", "Rules for mac_ipacl");
89215bab79SShivank Garg 
90215bab79SShivank Garg #define	MAC_RULE_STRING_LEN	1024
91215bab79SShivank Garg 
92215bab79SShivank Garg struct ipacl_addr {
93215bab79SShivank Garg 	union {
94215bab79SShivank Garg #ifdef INET
95215bab79SShivank Garg 		struct in_addr	ipv4;
96215bab79SShivank Garg #endif
97215bab79SShivank Garg #ifdef INET6
98215bab79SShivank Garg 		struct in6_addr	ipv6;
99215bab79SShivank Garg #endif
100215bab79SShivank Garg 		u_int8_t	addr8[16];
101215bab79SShivank Garg 		u_int16_t	addr16[8];
102215bab79SShivank Garg 		u_int32_t	addr32[4];
103215bab79SShivank Garg 	} ipa; /* 128 bit address*/
104215bab79SShivank Garg #ifdef INET
105215bab79SShivank Garg #define v4	ipa.ipv4
106215bab79SShivank Garg #endif
107215bab79SShivank Garg #ifdef INET6
108215bab79SShivank Garg #define v6	ipa.ipv6
109215bab79SShivank Garg #endif
110215bab79SShivank Garg #define addr8	ipa.addr8
111215bab79SShivank Garg #define addr16	ipa.addr16
112215bab79SShivank Garg #define addr32	ipa.addr32
113215bab79SShivank Garg };
114215bab79SShivank Garg 
115215bab79SShivank Garg struct ip_rule {
116215bab79SShivank Garg 	int			jid;
117215bab79SShivank Garg 	bool			allow;
118215bab79SShivank Garg 	bool			subnet_apply; /* Apply rule on whole subnet. */
119215bab79SShivank Garg 	char			if_name[IFNAMSIZ];
120215bab79SShivank Garg 	int			af; /* Address family. */
121215bab79SShivank Garg 	struct	ipacl_addr	addr;
122215bab79SShivank Garg 	struct	ipacl_addr	mask;
123215bab79SShivank Garg 	TAILQ_ENTRY(ip_rule)	r_entries;
124215bab79SShivank Garg };
125215bab79SShivank Garg 
126215bab79SShivank Garg static struct mtx			rule_mtx;
127215bab79SShivank Garg static TAILQ_HEAD(rulehead, ip_rule)	rule_head;
128215bab79SShivank Garg static char				rule_string[MAC_RULE_STRING_LEN];
129215bab79SShivank Garg 
130215bab79SShivank Garg static void
destroy_rules(struct rulehead * head)131215bab79SShivank Garg destroy_rules(struct rulehead *head)
132215bab79SShivank Garg {
133215bab79SShivank Garg 	struct ip_rule *rule;
134215bab79SShivank Garg 
135215bab79SShivank Garg 	while ((rule = TAILQ_FIRST(head)) != NULL) {
136215bab79SShivank Garg 		TAILQ_REMOVE(head, rule, r_entries);
137215bab79SShivank Garg 		free(rule, M_IPACL);
138215bab79SShivank Garg 	}
139215bab79SShivank Garg }
140215bab79SShivank Garg 
141215bab79SShivank Garg static void
ipacl_init(struct mac_policy_conf * conf)142215bab79SShivank Garg ipacl_init(struct mac_policy_conf *conf)
143215bab79SShivank Garg {
144215bab79SShivank Garg 	mtx_init(&rule_mtx, "rule_mtx", NULL, MTX_DEF);
145215bab79SShivank Garg 	TAILQ_INIT(&rule_head);
146215bab79SShivank Garg }
147215bab79SShivank Garg 
148215bab79SShivank Garg static void
ipacl_destroy(struct mac_policy_conf * conf)149215bab79SShivank Garg ipacl_destroy(struct mac_policy_conf *conf)
150215bab79SShivank Garg {
151215bab79SShivank Garg 	mtx_destroy(&rule_mtx);
152215bab79SShivank Garg 	destroy_rules(&rule_head);
153215bab79SShivank Garg }
154215bab79SShivank Garg 
155215bab79SShivank Garg /*
156215bab79SShivank Garg  * Note: parsing routines are destructive on the passed string.
157215bab79SShivank Garg  */
158215bab79SShivank Garg static int
parse_rule_element(char * element,struct ip_rule * rule)159215bab79SShivank Garg parse_rule_element(char *element, struct ip_rule *rule)
160215bab79SShivank Garg {
161215bab79SShivank Garg 	char *tok, *p;
162215bab79SShivank Garg 	int prefix;
163215bab79SShivank Garg #ifdef INET6
164215bab79SShivank Garg 	int i;
165215bab79SShivank Garg #endif
166215bab79SShivank Garg 
167215bab79SShivank Garg 	/* Should we support a jail wildcard? */
168215bab79SShivank Garg 	tok = strsep(&element, ",");
169215bab79SShivank Garg 	if (tok == NULL)
170215bab79SShivank Garg 		return (EINVAL);
171215bab79SShivank Garg 	rule->jid = strtol(tok, &p, 10);
172215bab79SShivank Garg 	if (*p != '\0')
173215bab79SShivank Garg 		return (EINVAL);
174215bab79SShivank Garg 	tok = strsep(&element, ",");
175215bab79SShivank Garg 	if (tok == NULL)
176215bab79SShivank Garg 		return (EINVAL);
177215bab79SShivank Garg 	rule->allow = strtol(tok, &p, 10);
178215bab79SShivank Garg 	if (*p != '\0')
179215bab79SShivank Garg 		return (EINVAL);
180215bab79SShivank Garg 	tok = strsep(&element, ",");
181215bab79SShivank Garg 	if (strlen(tok) + 1 > IFNAMSIZ)
182215bab79SShivank Garg 		return (EINVAL);
183215bab79SShivank Garg 	/* Empty interface name is wildcard to all interfaces. */
184215bab79SShivank Garg 	strlcpy(rule->if_name, tok, strlen(tok) + 1);
185215bab79SShivank Garg 	tok = strsep(&element, ",");
186215bab79SShivank Garg 	if (tok == NULL)
187215bab79SShivank Garg 		return (EINVAL);
188215bab79SShivank Garg 	rule->af = (strcmp(tok, "AF_INET") == 0) ? AF_INET :
189215bab79SShivank Garg 	    (strcmp(tok, "AF_INET6") == 0) ? AF_INET6 : -1;
190215bab79SShivank Garg 	if (rule->af == -1)
191215bab79SShivank Garg 		return (EINVAL);
192215bab79SShivank Garg 	tok = strsep(&element, "/");
193215bab79SShivank Garg 	if (tok == NULL)
194215bab79SShivank Garg 		return (EINVAL);
195215bab79SShivank Garg 	if (inet_pton(rule->af, tok, rule->addr.addr32) != 1)
196215bab79SShivank Garg 		return (EINVAL);
197215bab79SShivank Garg 	tok = element;
198215bab79SShivank Garg 	if (tok == NULL)
199215bab79SShivank Garg 		return (EINVAL);
200215bab79SShivank Garg 	prefix = strtol(tok, &p, 10);
201215bab79SShivank Garg 	if (*p != '\0')
202215bab79SShivank Garg 		return (EINVAL);
203215bab79SShivank Garg 	/* Value -1 for prefix make policy applicable to individual IP only. */
204215bab79SShivank Garg 	if (prefix == -1)
205215bab79SShivank Garg 		rule->subnet_apply = false;
206215bab79SShivank Garg 	else {
207215bab79SShivank Garg 		rule->subnet_apply = true;
208215bab79SShivank Garg 		switch (rule->af) {
209215bab79SShivank Garg #ifdef INET
210215bab79SShivank Garg 		case AF_INET:
211215bab79SShivank Garg 			if (prefix < 0 || prefix > 32)
212215bab79SShivank Garg 				return (EINVAL);
213215bab79SShivank Garg 
214215bab79SShivank Garg 			if (prefix == 0)
215215bab79SShivank Garg 				rule->mask.addr32[0] = htonl(0);
216215bab79SShivank Garg 			else
217215bab79SShivank Garg 				rule->mask.addr32[0] =
218215bab79SShivank Garg 				    htonl(~((1 << (32 - prefix)) - 1));
219215bab79SShivank Garg 			rule->addr.addr32[0] &= rule->mask.addr32[0];
220215bab79SShivank Garg 			break;
221215bab79SShivank Garg #endif
222215bab79SShivank Garg #ifdef INET6
223215bab79SShivank Garg 		case AF_INET6:
224215bab79SShivank Garg 			if (prefix < 0 || prefix > 128)
225215bab79SShivank Garg 				return (EINVAL);
226215bab79SShivank Garg 
227215bab79SShivank Garg 			for (i = 0; prefix > 0; prefix -= 8, i++)
228215bab79SShivank Garg 				rule->mask.addr8[i] = prefix >= 8 ? 0xFF :
229215bab79SShivank Garg 				    (u_int8_t)((0xFFU << (8 - prefix)) & 0xFFU);
230215bab79SShivank Garg 			for (i = 0; i < 16; i++)
231215bab79SShivank Garg 				rule->addr.addr8[i] &= rule->mask.addr8[i];
232215bab79SShivank Garg 			break;
233215bab79SShivank Garg #endif
234215bab79SShivank Garg 		}
235215bab79SShivank Garg 	}
236215bab79SShivank Garg 	return (0);
237215bab79SShivank Garg }
238215bab79SShivank Garg 
239215bab79SShivank Garg /*
240215bab79SShivank Garg  * Format of Rule- jid,allow,interface_name,addr_family,ip_addr/subnet_mask
241215bab79SShivank Garg  * Example: sysctl security.mac.ipacl.rules=1,1,epair0b,AF_INET,192.0.2.2/24
242215bab79SShivank Garg  */
243215bab79SShivank Garg static int
parse_rules(char * string,struct rulehead * head)244215bab79SShivank Garg parse_rules(char *string, struct rulehead *head)
245215bab79SShivank Garg {
246215bab79SShivank Garg 	struct ip_rule *new;
247215bab79SShivank Garg 	char *element;
248215bab79SShivank Garg 	int error;
249215bab79SShivank Garg 
250215bab79SShivank Garg 	error = 0;
251215bab79SShivank Garg 	while ((element = strsep(&string, "@")) != NULL) {
252215bab79SShivank Garg 		if (strlen(element) == 0)
253215bab79SShivank Garg 			continue;
254215bab79SShivank Garg 
255215bab79SShivank Garg 		new = malloc(sizeof(*new), M_IPACL, M_ZERO | M_WAITOK);
256215bab79SShivank Garg 		error = parse_rule_element(element, new);
257215bab79SShivank Garg 		if (error != 0) {
258215bab79SShivank Garg 			free(new, M_IPACL);
259215bab79SShivank Garg 			goto out;
260215bab79SShivank Garg 		}
261215bab79SShivank Garg 		TAILQ_INSERT_TAIL(head, new, r_entries);
262215bab79SShivank Garg 	}
263215bab79SShivank Garg out:
264215bab79SShivank Garg 	if (error != 0)
265215bab79SShivank Garg 		destroy_rules(head);
266215bab79SShivank Garg 	return (error);
267215bab79SShivank Garg }
268215bab79SShivank Garg 
269215bab79SShivank Garg static int
sysctl_rules(SYSCTL_HANDLER_ARGS)270215bab79SShivank Garg sysctl_rules(SYSCTL_HANDLER_ARGS)
271215bab79SShivank Garg {
272215bab79SShivank Garg 	char *string, *copy_string, *new_string;
273215bab79SShivank Garg 	struct rulehead head, save_head;
274215bab79SShivank Garg 	int error;
275215bab79SShivank Garg 
276215bab79SShivank Garg 	new_string = NULL;
277215bab79SShivank Garg 	if (req->newptr != NULL) {
278215bab79SShivank Garg 		new_string = malloc(MAC_RULE_STRING_LEN, M_IPACL,
279215bab79SShivank Garg 		    M_WAITOK | M_ZERO);
280215bab79SShivank Garg 		mtx_lock(&rule_mtx);
281215bab79SShivank Garg 		strcpy(new_string, rule_string);
282215bab79SShivank Garg 		mtx_unlock(&rule_mtx);
283215bab79SShivank Garg 		string = new_string;
284215bab79SShivank Garg 	} else
285215bab79SShivank Garg 		string = rule_string;
286215bab79SShivank Garg 
287215bab79SShivank Garg 	error = sysctl_handle_string(oidp, string, MAC_RULE_STRING_LEN, req);
288215bab79SShivank Garg 	if (error)
289215bab79SShivank Garg 		goto out;
290215bab79SShivank Garg 
291215bab79SShivank Garg 	if (req->newptr != NULL) {
292215bab79SShivank Garg 		copy_string = strdup(string, M_IPACL);
293215bab79SShivank Garg 		TAILQ_INIT(&head);
294215bab79SShivank Garg 		error = parse_rules(copy_string, &head);
295215bab79SShivank Garg 		free(copy_string, M_IPACL);
296215bab79SShivank Garg 		if (error)
297215bab79SShivank Garg 			goto out;
298215bab79SShivank Garg 
299215bab79SShivank Garg 		TAILQ_INIT(&save_head);
300215bab79SShivank Garg 		mtx_lock(&rule_mtx);
301215bab79SShivank Garg 		TAILQ_CONCAT(&save_head, &rule_head, r_entries);
302215bab79SShivank Garg 		TAILQ_CONCAT(&rule_head, &head, r_entries);
303215bab79SShivank Garg 		strcpy(rule_string, string);
304215bab79SShivank Garg 		mtx_unlock(&rule_mtx);
305215bab79SShivank Garg 		destroy_rules(&save_head);
306215bab79SShivank Garg 	}
307215bab79SShivank Garg out:
308215bab79SShivank Garg 	if (new_string != NULL)
309215bab79SShivank Garg 		free(new_string, M_IPACL);
310215bab79SShivank Garg 	return (error);
311215bab79SShivank Garg }
312215bab79SShivank Garg SYSCTL_PROC(_security_mac_ipacl, OID_AUTO, rules,
313215bab79SShivank Garg     CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
314215bab79SShivank Garg     0, sysctl_rules, "A", "IP ACL Rules");
315215bab79SShivank Garg 
316215bab79SShivank Garg static int
rules_check(struct ucred * cred,struct ipacl_addr * ip_addr,if_t ifp)317215bab79SShivank Garg rules_check(struct ucred *cred,
318*b820820eSJustin Hibbits     struct ipacl_addr *ip_addr, if_t ifp)
319215bab79SShivank Garg {
320215bab79SShivank Garg 	struct ip_rule *rule;
321215bab79SShivank Garg 	int error;
322215bab79SShivank Garg #ifdef INET6
323215bab79SShivank Garg 	int i;
324215bab79SShivank Garg 	bool same_subnet;
325215bab79SShivank Garg #endif
326215bab79SShivank Garg 
327215bab79SShivank Garg 	error = EPERM;
328215bab79SShivank Garg 
329215bab79SShivank Garg 	mtx_lock(&rule_mtx);
330215bab79SShivank Garg 
331215bab79SShivank Garg 	/*
332215bab79SShivank Garg 	 * In the case where multiple rules are applicable to an IP address or
333215bab79SShivank Garg 	 * a set of IP addresses, the rule that is defined later in the list
334215bab79SShivank Garg 	 * determines the outcome, disregarding any previous rule for that IP
335215bab79SShivank Garg 	 * address.
336215bab79SShivank Garg 	 * Walk the policy rules list in reverse order until rule applicable
337215bab79SShivank Garg 	 * to the requested IP address is found.
338215bab79SShivank Garg 	 */
339215bab79SShivank Garg 	TAILQ_FOREACH_REVERSE(rule, &rule_head, rulehead, r_entries) {
340215bab79SShivank Garg 		/* Skip if current rule applies to different jail. */
341215bab79SShivank Garg 		if (cred->cr_prison->pr_id != rule->jid)
342215bab79SShivank Garg 			continue;
343215bab79SShivank Garg 
344215bab79SShivank Garg 		if (strcmp(rule->if_name, "\0") &&
345*b820820eSJustin Hibbits 		    strcmp(rule->if_name, if_name(ifp)))
346215bab79SShivank Garg 			continue;
347215bab79SShivank Garg 
348215bab79SShivank Garg 		switch (rule->af) {
349215bab79SShivank Garg #ifdef INET
350215bab79SShivank Garg 		case AF_INET:
351215bab79SShivank Garg 			if (rule->subnet_apply) {
352215bab79SShivank Garg 				if (rule->addr.v4.s_addr !=
353215bab79SShivank Garg 				    (ip_addr->v4.s_addr & rule->mask.v4.s_addr))
354215bab79SShivank Garg 					continue;
355215bab79SShivank Garg 			} else
356215bab79SShivank Garg 				if (ip_addr->v4.s_addr != rule->addr.v4.s_addr)
357215bab79SShivank Garg 					continue;
358215bab79SShivank Garg 			break;
359215bab79SShivank Garg #endif
360215bab79SShivank Garg #ifdef INET6
361215bab79SShivank Garg 		case AF_INET6:
362215bab79SShivank Garg 			if (rule->subnet_apply) {
363215bab79SShivank Garg 				same_subnet = true;
364215bab79SShivank Garg 				for (i = 0; i < 16; i++)
365215bab79SShivank Garg 					if (rule->addr.v6.s6_addr[i] !=
366215bab79SShivank Garg 					    (ip_addr->v6.s6_addr[i] &
367215bab79SShivank Garg 					    rule->mask.v6.s6_addr[i])) {
368215bab79SShivank Garg 						same_subnet = false;
369215bab79SShivank Garg 						break;
370215bab79SShivank Garg 					}
371215bab79SShivank Garg 				if (!same_subnet)
372215bab79SShivank Garg 					continue;
373215bab79SShivank Garg 			} else
374215bab79SShivank Garg 				if (bcmp(&rule->addr, ip_addr,
375215bab79SShivank Garg 				    sizeof(*ip_addr)))
376215bab79SShivank Garg 					continue;
377215bab79SShivank Garg 			break;
378215bab79SShivank Garg #endif
379215bab79SShivank Garg 		}
380215bab79SShivank Garg 
381215bab79SShivank Garg 		if (rule->allow)
382215bab79SShivank Garg 			error = 0;
383215bab79SShivank Garg 		break;
384215bab79SShivank Garg 	}
385215bab79SShivank Garg 
386215bab79SShivank Garg 	mtx_unlock(&rule_mtx);
387215bab79SShivank Garg 
388215bab79SShivank Garg 	return (error);
389215bab79SShivank Garg }
390215bab79SShivank Garg 
391215bab79SShivank Garg /*
392215bab79SShivank Garg  * Feature request: Can we make this sysctl policy apply to jails by default,
393215bab79SShivank Garg  * but also allow it to be changed to apply to the base system?
394215bab79SShivank Garg  */
395215bab79SShivank Garg #ifdef INET
396215bab79SShivank Garg static int
ipacl_ip4_check_jail(struct ucred * cred,const struct in_addr * ia,if_t ifp)397215bab79SShivank Garg ipacl_ip4_check_jail(struct ucred *cred,
398*b820820eSJustin Hibbits     const struct in_addr *ia, if_t ifp)
399215bab79SShivank Garg {
400215bab79SShivank Garg 	struct ipacl_addr ip4_addr;
401215bab79SShivank Garg 
402215bab79SShivank Garg 	ip4_addr.v4 = *ia;
403215bab79SShivank Garg 
404215bab79SShivank Garg 	if (!jailed(cred))
405215bab79SShivank Garg 		return (0);
406215bab79SShivank Garg 
407215bab79SShivank Garg 	/* Checks with the policy only when it is enforced for ipv4. */
408215bab79SShivank Garg 	if (ipacl_ipv4)
409215bab79SShivank Garg 		return rules_check(cred, &ip4_addr, ifp);
410215bab79SShivank Garg 
411215bab79SShivank Garg 	return (0);
412215bab79SShivank Garg }
413215bab79SShivank Garg #endif
414215bab79SShivank Garg 
415215bab79SShivank Garg #ifdef INET6
416215bab79SShivank Garg static int
ipacl_ip6_check_jail(struct ucred * cred,const struct in6_addr * ia6,if_t ifp)417215bab79SShivank Garg ipacl_ip6_check_jail(struct ucred *cred,
418*b820820eSJustin Hibbits     const struct in6_addr *ia6, if_t ifp)
419215bab79SShivank Garg {
420215bab79SShivank Garg 	struct ipacl_addr ip6_addr;
421215bab79SShivank Garg 
422215bab79SShivank Garg 	ip6_addr.v6 = *ia6; /* Make copy to not alter the original. */
423215bab79SShivank Garg 	in6_clearscope(&ip6_addr.v6); /* Clear the scope id. */
424215bab79SShivank Garg 
425215bab79SShivank Garg 	if (!jailed(cred))
426215bab79SShivank Garg 		return (0);
427215bab79SShivank Garg 
428215bab79SShivank Garg 	/* Checks with the policy when it is enforced for ipv6. */
429215bab79SShivank Garg 	if (ipacl_ipv6)
430215bab79SShivank Garg 		return rules_check(cred, &ip6_addr, ifp);
431215bab79SShivank Garg 
432215bab79SShivank Garg 	return (0);
433215bab79SShivank Garg }
434215bab79SShivank Garg #endif
435215bab79SShivank Garg 
436215bab79SShivank Garg static struct mac_policy_ops ipacl_ops =
437215bab79SShivank Garg {
438215bab79SShivank Garg 	.mpo_init = ipacl_init,
439215bab79SShivank Garg 	.mpo_destroy = ipacl_destroy,
440215bab79SShivank Garg #ifdef INET
441215bab79SShivank Garg 	.mpo_ip4_check_jail = ipacl_ip4_check_jail,
442215bab79SShivank Garg #endif
443215bab79SShivank Garg #ifdef INET6
444215bab79SShivank Garg 	.mpo_ip6_check_jail = ipacl_ip6_check_jail,
445215bab79SShivank Garg #endif
446215bab79SShivank Garg };
447215bab79SShivank Garg 
448215bab79SShivank Garg MAC_POLICY_SET(&ipacl_ops, mac_ipacl, "TrustedBSD MAC/ipacl",
449215bab79SShivank Garg     MPC_LOADTIME_FLAG_UNLOADOK, NULL);
450