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)
This commit is contained in:
parent
f815125fbc
commit
592bcae802
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=202468
@ -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 prison *pr, struct in6_addr *newip6);
|
||||
*/
|
||||
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 uio *optuio, int flags)
|
||||
#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;
|
||||
@ -2658,6 +2688,41 @@ prison_get_ip4(struct ucred *cred, struct in_addr *ia)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -2963,6 +3028,41 @@ prison_get_ip6(struct ucred *cred, struct in6_addr *ia6)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -4116,12 +4216,18 @@ SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN,
|
||||
"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");
|
||||
|
@ -552,6 +552,13 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
|
||||
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));
|
||||
|
||||
|
@ -270,6 +270,13 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
|
@ -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, struct in_addr *ia);
|
||||
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);
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user