summaryrefslogtreecommitdiffstats
path: root/sys/net/rtsock.c
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2008-11-29 14:32:14 +0000
committerbz <bz@FreeBSD.org>2008-11-29 14:32:14 +0000
commitd2730d5b27273f2e5a9b9f2703b896b5194496ee (patch)
tree2b8f4835032d12a0e61cc40dad151e279cf7a49f /sys/net/rtsock.c
parent3b10ad8d71152b89fda1bef42dc519fc460aba1b (diff)
downloadFreeBSD-src-d2730d5b27273f2e5a9b9f2703b896b5194496ee.zip
FreeBSD-src-d2730d5b27273f2e5a9b9f2703b896b5194496ee.tar.gz
MFp4:
Bring in updated jail support from bz_jail branch. This enhances the current jail implementation to permit multiple addresses per jail. In addtion to IPv4, IPv6 is supported as well. Due to updated checks it is even possible to have jails without an IP address at all, which basically gives one a chroot with restricted process view, no networking,.. SCTP support was updated and supports IPv6 in jails as well. Cpuset support permits jails to be bound to specific processor sets after creation. Jails can have an unrestricted (no duplicate protection, etc.) name in addition to the hostname. The jail name cannot be changed from within a jail and is considered to be used for management purposes or as audit-token in the future. DDB 'show jails' command was added to aid debugging. Proper compat support permits 32bit jail binaries to be used on 64bit systems to manage jails. Also backward compatibility was preserved where possible: for jail v1 syscalls, as well as with user space management utilities. Both jail as well as prison version were updated for the new features. A gap was intentionally left as the intermediate versions had been used by various patches floating around the last years. Bump __FreeBSD_version for the afore mentioned and in kernel changes. Special thanks to: - Pawel Jakub Dawidek (pjd) for his multi-IPv4 patches and Olivier Houchard (cognet) for initial single-IPv6 patches. - Jeff Roberson (jeff) and Randall Stewart (rrs) for their help, ideas and review on cpuset and SCTP support. - Robert Watson (rwatson) for lots and lots of help, discussions, suggestions and review of most of the patch at various stages. - John Baldwin (jhb) for his help. - Simon L. Nielsen (simon) as early adopter testing changes on cluster machines as well as all the testers and people who provided feedback the last months on freebsd-jail and other channels. - My employer, CK Software GmbH, for the support so I could work on this. Reviewed by: (see above) MFC after: 3 months (this is just so that I get the mail) X-MFC Before: 7.2-RELEASE if possible
Diffstat (limited to 'sys/net/rtsock.c')
-rw-r--r--sys/net/rtsock.c160
1 files changed, 148 insertions, 12 deletions
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index ae6fa6a..15c6928 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -31,11 +31,13 @@
*/
#include "opt_sctp.h"
#include "opt_mpath.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/domain.h>
-#include <sys/kernel.h>
#include <sys/jail.h>
+#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/priv.h>
@@ -54,6 +56,9 @@
#include <net/route.h>
#include <netinet/in.h>
+#ifdef INET6
+#include <netinet6/scope6_var.h>
+#endif
#ifdef SCTP
extern void sctp_addr_change(struct ifaddr *ifa, int cmd);
@@ -309,6 +314,136 @@ static struct pr_usrreqs route_usrreqs = {
.pru_close = rts_close,
};
+#ifndef _SOCKADDR_UNION_DEFINED
+#define _SOCKADDR_UNION_DEFINED
+/*
+ * The union of all possible address formats we handle.
+ */
+union sockaddr_union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+#endif /* _SOCKADDR_UNION_DEFINED */
+
+static int
+rtm_get_jailed(struct rt_addrinfo *info, struct ifnet *ifp,
+ struct rtentry *rt, union sockaddr_union *saun, struct ucred *cred)
+{
+
+ switch (info->rti_info[RTAX_DST]->sa_family) {
+#ifdef INET
+ case AF_INET:
+ {
+ struct in_addr ia;
+
+ /*
+ * 1. Check if the returned address is part of the jail.
+ */
+ ia = ((struct sockaddr_in *)rt->rt_ifa->ifa_addr)->sin_addr;
+ if (prison_check_ip4(cred, &ia) != 0) {
+ info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
+
+ } else {
+ struct ifaddr *ifa;
+ int found;
+
+ found = 0;
+
+ /*
+ * 2. Try to find an address on the given outgoing
+ * interface that belongs to the jail.
+ */
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ struct sockaddr *sa;
+ sa = ifa->ifa_addr;
+ if (sa->sa_family != AF_INET)
+ continue;
+ ia = ((struct sockaddr_in *)sa)->sin_addr;
+ if (prison_check_ip4(cred, &ia) != 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ /*
+ * 3. As a last resort return the 'default'
+ * jail address.
+ */
+ if (prison_getip4(cred, &ia) != 0)
+ return (ESRCH);
+ }
+ bzero(&saun->sin, sizeof(struct sockaddr_in));
+ saun->sin.sin_len = sizeof(struct sockaddr_in);
+ saun->sin.sin_family = AF_INET;
+ saun->sin.sin_addr.s_addr = ia.s_addr;
+ info->rti_info[RTAX_IFA] =
+ (struct sockaddr *)&saun->sin;
+ }
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct in6_addr ia6;
+
+ /*
+ * 1. Check if the returned address is part of the jail.
+ */
+ bcopy(&((struct sockaddr_in6 *)rt->rt_ifa->ifa_addr)->sin6_addr,
+ &ia6, sizeof(struct in6_addr));
+ if (prison_check_ip6(cred, &ia6) != 0) {
+ info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
+ } else {
+ struct ifaddr *ifa;
+ int found;
+
+ found = 0;
+
+ /*
+ * 2. Try to find an address on the given outgoing
+ * interface that belongs to the jail.
+ */
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ struct sockaddr *sa;
+ sa = ifa->ifa_addr;
+ if (sa->sa_family != AF_INET6)
+ continue;
+ bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr,
+ &ia6, sizeof(struct in6_addr));
+ if (prison_check_ip6(cred, &ia6) != 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ /*
+ * 3. As a last resort return the 'default'
+ * jail address.
+ */
+ if (prison_getip6(cred, &ia6) != 0)
+ return (ESRCH);
+ }
+ bzero(&saun->sin6, sizeof(struct sockaddr_in6));
+ saun->sin6.sin6_len = sizeof(struct sockaddr_in6);
+ saun->sin6.sin6_family = AF_INET6;
+ bcopy(&ia6, &saun->sin6.sin6_addr,
+ sizeof(struct in6_addr));
+ if (sa6_recoverscope(&saun->sin6) != 0)
+ return (ESRCH);
+ info->rti_info[RTAX_IFA] =
+ (struct sockaddr *)&saun->sin6;
+ }
+ break;
+ }
+#endif
+ default:
+ return (ESRCH);
+ }
+ return (0);
+}
+
/*ARGSUSED*/
static int
route_output(struct mbuf *m, struct socket *so)
@@ -321,7 +456,7 @@ route_output(struct mbuf *m, struct socket *so)
struct rt_addrinfo info;
int len, error = 0;
struct ifnet *ifp = NULL;
- struct sockaddr_in jail;
+ union sockaddr_union saun;
#define senderr(e) { error = e; goto flush;}
if (m == NULL || ((m->m_len < sizeof(long)) &&
@@ -481,16 +616,17 @@ route_output(struct mbuf *m, struct socket *so)
info.rti_info[RTAX_IFP] =
ifp->if_addr->ifa_addr;
if (jailed(so->so_cred)) {
- bzero(&jail, sizeof(jail));
- jail.sin_family = PF_INET;
- jail.sin_len = sizeof(jail);
- jail.sin_addr.s_addr =
- htonl(prison_getip(so->so_cred));
- info.rti_info[RTAX_IFA] =
- (struct sockaddr *)&jail;
- } else
+ error = rtm_get_jailed(
+ &info, ifp, rt, &saun,
+ so->so_cred);
+ if (error != 0) {
+ RT_UNLOCK(rt);
+ senderr(ESRCH);
+ }
+ } else {
info.rti_info[RTAX_IFA] =
rt->rt_ifa->ifa_addr;
+ }
if (ifp->if_flags & IFF_POINTOPOINT)
info.rti_info[RTAX_BRD] =
rt->rt_ifa->ifa_dstaddr;
@@ -1171,7 +1307,7 @@ sysctl_iflist(int af, struct walkarg *w)
if (af && af != ifa->ifa_addr->sa_family)
continue;
if (jailed(curthread->td_ucred) &&
- prison_if(curthread->td_ucred, ifa->ifa_addr))
+ !prison_if(curthread->td_ucred, ifa->ifa_addr))
continue;
info.rti_info[RTAX_IFA] = ifa->ifa_addr;
info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
@@ -1220,7 +1356,7 @@ sysctl_ifmalist(int af, struct walkarg *w)
if (af && af != ifma->ifma_addr->sa_family)
continue;
if (jailed(curproc->p_ucred) &&
- prison_if(curproc->p_ucred, ifma->ifma_addr))
+ !prison_if(curproc->p_ucred, ifma->ifma_addr))
continue;
info.rti_info[RTAX_IFA] = ifma->ifma_addr;
info.rti_info[RTAX_GATEWAY] =
OpenPOWER on IntegriCloud