summaryrefslogtreecommitdiffstats
path: root/sys/net/rtsock.c
diff options
context:
space:
mode:
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