svn commit: r202468 - in head: sys/kern sys/netinet sys/netinet6 sys/sys usr.sbin/jail

Bjoern A. Zeeb bz at FreeBSD.org
Sun Jan 17 12:57:11 UTC 2010


Author: bz
Date: Sun Jan 17 12:57:11 2010
New Revision: 202468
URL: http://svn.freebsd.org/changeset/base/202468

Log:
  Add ip4.saddrsel/ip4.nosaddrsel (and equivalent for ip6) to control
  whether to use source address selection (default) or the primary
  jail address for unbound outgoing connections.
  
  This is intended to be used by people upgrading from single-IP
  jails to multi-IP jails but not having to change firewall rules,
  application ACLs, ... but to force their connections (unless
  otherwise changed) to the primry jail IP they had been used for
  years, as well as for people prefering to implement similar policies.
  
  Note that for IPv6, if configured incorrectly, this might lead to
  scope violations, which single-IPv6 jails could as well, as by the
  design of jails. [1]
  
  Reviewed by:	jamie, hrs (ipv6 part)
  Pointed out by:	hrs [1]
  MFC After:	2 weeks
  Asked for by:	Jase Thew (bazerka beardz.net)

Modified:
  head/sys/kern/kern_jail.c
  head/sys/netinet/in_pcb.c
  head/sys/netinet6/in6_src.c
  head/sys/sys/jail.h
  head/usr.sbin/jail/jail.8

Modified: head/sys/kern/kern_jail.c
==============================================================================
--- head/sys/kern/kern_jail.c	Sun Jan 17 11:21:18 2010	(r202467)
+++ head/sys/kern/kern_jail.c	Sun Jan 17 12:57:11 2010	(r202468)
@@ -77,6 +77,21 @@ __FBSDID("$FreeBSD$");
 
 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
 
+/* Keep struct prison prison0 and some code in kern_jail_set() readable. */
+#ifdef INET
+#ifdef INET6
+#define	_PR_IP_SADDRSEL	PR_IP4_SADDRSEL|PR_IP6_SADDRSEL
+#else
+#define	_PR_IP_SADDRSEL	PR_IP4_SADDRSEL
+#endif
+#else /* !INET */
+#ifdef INET6
+#define	_PR_IP_SADDRSEL	PR_IP6_SADDRSEL
+#else
+#define	_PR_IP_SADDRSEL	0
+#endif
+#endif
+
 /* prison0 describes what is "real" about the system. */
 struct prison prison0 = {
 	.pr_id		= 0,
@@ -89,9 +104,9 @@ struct prison prison0 = {
 	.pr_hostuuid	= DEFAULT_HOSTUUID,
 	.pr_children	= LIST_HEAD_INITIALIZER(prison0.pr_children),
 #ifdef VIMAGE
-	.pr_flags	= PR_HOST|PR_VNET,
+	.pr_flags	= PR_HOST|PR_VNET|_PR_IP_SADDRSEL,
 #else
-	.pr_flags	= PR_HOST,
+	.pr_flags	= PR_HOST|_PR_IP_SADDRSEL,
 #endif
 	.pr_allow	= PR_ALLOW_ALL,
 };
@@ -129,10 +144,22 @@ static int prison_restrict_ip6(struct pr
  */
 static char *pr_flag_names[] = {
 	[0] = "persist",
+#ifdef INET
+	[7] = "ip4.saddrsel",
+#endif
+#ifdef INET6
+	[8] = "ip6.saddrsel",
+#endif
 };
 
 static char *pr_flag_nonames[] = {
 	[0] = "nopersist",
+#ifdef INET
+	[7] = "ip4.nosaddrsel",
+#endif
+#ifdef INET6
+	[8] = "ip6.nosaddrsel",
+#endif
 };
 
 struct jailsys_flags {
@@ -1199,6 +1226,9 @@ kern_jail_set(struct thread *td, struct 
 #endif
 		}
 #endif
+		/* Source address selection is always on by default. */
+		pr->pr_flags |= _PR_IP_SADDRSEL;
+
 		pr->pr_securelevel = ppr->pr_securelevel;
 		pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow;
 		pr->pr_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS;
@@ -2659,6 +2689,41 @@ prison_get_ip4(struct ucred *cred, struc
 }
 
 /*
+ * Return 1 if we should do proper source address selection or are not jailed.
+ * We will return 0 if we should bypass source address selection in favour
+ * of the primary jail IPv4 address. Only in this case *ia will be updated and
+ * returned in NBO.
+ * Return EAFNOSUPPORT, in case this jail does not allow IPv4.
+ */
+int
+prison_saddrsel_ip4(struct ucred *cred, struct in_addr *ia)
+{
+	struct prison *pr;
+	struct in_addr lia;
+	int error;
+
+	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+	KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
+
+	if (!jailed(cred))
+		return (1);
+
+	pr = cred->cr_prison;
+	if (pr->pr_flags & PR_IP4_SADDRSEL)
+		return (1);
+
+	lia.s_addr = INADDR_ANY;
+	error = prison_get_ip4(cred, &lia);
+	if (error)
+		return (error);
+	if (lia.s_addr == INADDR_ANY)
+		return (1);
+
+	ia->s_addr = lia.s_addr;
+	return (0);
+}
+
+/*
  * Return true if pr1 and pr2 have the same IPv4 address restrictions.
  */
 int
@@ -2964,6 +3029,41 @@ prison_get_ip6(struct ucred *cred, struc
 }
 
 /*
+ * Return 1 if we should do proper source address selection or are not jailed.
+ * We will return 0 if we should bypass source address selection in favour
+ * of the primary jail IPv6 address. Only in this case *ia will be updated and
+ * returned in NBO.
+ * Return EAFNOSUPPORT, in case this jail does not allow IPv6.
+ */
+int
+prison_saddrsel_ip6(struct ucred *cred, struct in6_addr *ia6)
+{
+	struct prison *pr;
+	struct in6_addr lia6;
+	int error;
+
+	KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+	KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
+
+	if (!jailed(cred))
+		return (1);
+
+	pr = cred->cr_prison;
+	if (pr->pr_flags & PR_IP6_SADDRSEL)
+		return (1);
+
+	lia6 = in6addr_any;
+	error = prison_get_ip6(cred, &lia6);
+	if (error)
+		return (error);
+	if (IN6_IS_ADDR_UNSPECIFIED(&lia6))
+		return (1);
+
+	bcopy(&lia6, ia6, sizeof(struct in6_addr));
+	return (0);
+}
+
+/*
  * Return true if pr1 and pr2 have the same IPv6 address restrictions.
  */
 int
@@ -4116,12 +4216,18 @@ SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_
     "Jail IPv4 address virtualization");
 SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr),
     "S,in_addr,a", "Jail IPv4 addresses");
+SYSCTL_JAIL_PARAM(_ip4, saddrsel, CTLTYPE_INT | CTLFLAG_RW,
+    "B", "Do (not) use IPv4 source address selection rather than the "
+    "primary jail IPv4 address.");
 #endif
 #ifdef INET6
 SYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RDTUN,
     "Jail IPv6 address virtualization");
 SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr),
     "S,in6_addr,a", "Jail IPv6 addresses");
+SYSCTL_JAIL_PARAM(_ip6, saddrsel, CTLTYPE_INT | CTLFLAG_RW,
+    "B", "Do (not) use IPv6 source address selection rather than the "
+    "primary jail IPv6 address.");
 #endif
 
 SYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags");

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c	Sun Jan 17 11:21:18 2010	(r202467)
+++ head/sys/netinet/in_pcb.c	Sun Jan 17 12:57:11 2010	(r202468)
@@ -552,6 +552,13 @@ in_pcbladdr(struct inpcb *inp, struct in
 
 	KASSERT(laddr != NULL, ("%s: laddr NULL", __func__));
 
+	/*
+	 * Bypass source address selection and use the primary jail IP
+	 * if requested.
+	 */
+	if (cred != NULL && !prison_saddrsel_ip4(cred, laddr))
+		return (0);
+
 	error = 0;
 	bzero(&sro, sizeof(sro));
 

Modified: head/sys/netinet6/in6_src.c
==============================================================================
--- head/sys/netinet6/in6_src.c	Sun Jan 17 11:21:18 2010	(r202467)
+++ head/sys/netinet6/in6_src.c	Sun Jan 17 12:57:11 2010	(r202468)
@@ -271,6 +271,13 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	}
 
 	/*
+	 * Bypass source address selection and use the primary jail IP
+	 * if requested.
+	 */
+	if (cred != NULL && !prison_saddrsel_ip6(cred, srcp))
+		return (0);
+
+	/*
 	 * If the address is not specified, choose the best one based on
 	 * the outgoing interface and the destination address.
 	 */

Modified: head/sys/sys/jail.h
==============================================================================
--- head/sys/sys/jail.h	Sun Jan 17 11:21:18 2010	(r202467)
+++ head/sys/sys/jail.h	Sun Jan 17 12:57:11 2010	(r202468)
@@ -191,6 +191,10 @@ struct prison {
 #define	PR_VNET		0x00000010	/* Virtual network stack */
 #define	PR_IP4_DISABLE	0x00000020	/* Disable IPv4 */
 #define	PR_IP6_DISABLE	0x00000040	/* Disable IPv6 */
+#define	PR_IP4_SADDRSEL	0x00000080	/* Do IPv4 src addr sel. or use the */
+					/* primary jail address. */
+#define	PR_IP6_SADDRSEL	0x00000100	/* Do IPv6 src addr sel. or use the */
+					/* primary jail address. */
 
 /* Internal flag bits */
 #define	PR_REMOVE	0x01000000	/* In process of being removed */
@@ -362,12 +366,14 @@ int prison_get_ip4(struct ucred *cred, s
 int prison_local_ip4(struct ucred *cred, struct in_addr *ia);
 int prison_remote_ip4(struct ucred *cred, struct in_addr *ia);
 int prison_check_ip4(struct ucred *cred, struct in_addr *ia);
+int prison_saddrsel_ip4(struct ucred *, struct in_addr *);
 #ifdef INET6
 int prison_equal_ip6(struct prison *, struct prison *);
 int prison_get_ip6(struct ucred *, struct in6_addr *);
 int prison_local_ip6(struct ucred *, struct in6_addr *, int);
 int prison_remote_ip6(struct ucred *, struct in6_addr *);
 int prison_check_ip6(struct ucred *, struct in6_addr *);
+int prison_saddrsel_ip6(struct ucred *, struct in6_addr *);
 #endif
 int prison_check_af(struct ucred *cred, int af);
 int prison_if(struct ucred *cred, struct sockaddr *sa);

Modified: head/usr.sbin/jail/jail.8
==============================================================================
--- head/usr.sbin/jail/jail.8	Sun Jan 17 11:21:18 2010	(r202467)
+++ head/usr.sbin/jail/jail.8	Sun Jan 17 12:57:11 2010	(r202468)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 18, 2009
+.Dd January 17, 2010
 .Dt JAIL 8
 .Os
 .Sh NAME
@@ -252,6 +252,13 @@ match.
 It is only possible to start multiple jails with the same IP address,
 if none of the jails has more than this single overlapping IP address
 assigned to itself.
+.It Va ip4.saddrsel
+A boolean option to change the formerly mentioned behaviour and disable
+IPv4 source address selection for the prison in favour of the primary
+IPv4 address of the jail.
+Source address selection is enabled by default for all jails and a
+.Va ip4.nosaddrsel
+setting of a parent jail is not inherited for any child jails.
 .It Va ip4
 Control the availablity of IPv4 addresses.
 Possible values are
@@ -267,9 +274,10 @@ Setting the
 .Va ip4.addr
 parameter implies a value of
 .Dq new .
-.It Va ip6.addr , Va ip6
-A list of IPv6 addresses assigned to the prison, the counterpart to
-.Va ip4.addr
+.It Va ip6.addr , Va ip6.saddrsel , Va ip6
+A set of IPv6 options for the prison, the counterparts to
+.Va ip4.addr ,
+.Va ip4.saddrsel
 and
 .Va ip4
 above.


More information about the svn-src-all mailing list