summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
authorclaudio <claudio@openbsd.org>2009-06-05 00:05:21 +0000
committerclaudio <claudio@openbsd.org>2009-06-05 00:05:21 +0000
commit22760f565a521eee1242a6b1041c186acc77d298 (patch)
treecf09757382c6a5172e7749b5e2348595c70d6bc3 /sys/netinet/ip_output.c
parentMake imsg completely async model agnostic by not requiring an (diff)
downloadwireguard-openbsd-22760f565a521eee1242a6b1041c186acc77d298.tar.xz
wireguard-openbsd-22760f565a521eee1242a6b1041c186acc77d298.zip
Initial support for routing domains. This allows to bind interfaces to
alternate routing table and separate them from other interfaces in distinct routing tables. The same network can now be used in any doamin at the same time without causing conflicts. This diff is mostly mechanical and adds the necessary rdomain checks accross net and netinet. L2 and IPv4 are mostly covered still missing pf and IPv6. input and tested by jsg@, phessler@ and reyk@. "put it in" deraadt@
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c77
1 files changed, 52 insertions, 25 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index ab65a4b0eb4..8247955acab 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.193 2009/01/30 20:46:33 claudio Exp $ */
+/* $OpenBSD: ip_output.c,v 1.194 2009/06/05 00:05:22 claudio Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -201,11 +201,13 @@ ip_output(struct mbuf *m0, ...)
* If routing to interface only, short-circuit routing lookup.
*/
if (flags & IP_ROUTETOIF) {
- if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
- (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
- ipstat.ips_noroute++;
- error = ENETUNREACH;
- goto bad;
+ if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst),
+ m->m_pkthdr.rdomain))) == 0 &&
+ (ia = ifatoia(ifa_ifwithnet(sintosa(dst),
+ m->m_pkthdr.rdomain))) == 0) {
+ ipstat.ips_noroute++;
+ error = ENETUNREACH;
+ goto bad;
}
ifp = ia->ia_ifp;
@@ -219,7 +221,8 @@ ip_output(struct mbuf *m0, ...)
IFP_TO_IA(ifp, ia);
} else {
if (ro->ro_rt == 0)
- rtalloc_mpath(ro, NULL, 0);
+ rtalloc_mpath(ro, NULL,
+ m->m_pkthdr.rdomain);
if (ro->ro_rt == 0) {
ipstat.ips_noroute++;
@@ -371,11 +374,13 @@ ip_output(struct mbuf *m0, ...)
* If routing to interface only, short-circuit routing lookup.
*/
if (flags & IP_ROUTETOIF) {
- if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == 0 &&
- (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == 0) {
- ipstat.ips_noroute++;
- error = ENETUNREACH;
- goto bad;
+ if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst),
+ m->m_pkthdr.rdomain))) == 0 &&
+ (ia = ifatoia(ifa_ifwithnet(sintosa(dst),
+ m->m_pkthdr.rdomain))) == 0) {
+ ipstat.ips_noroute++;
+ error = ENETUNREACH;
+ goto bad;
}
ifp = ia->ia_ifp;
@@ -389,7 +394,8 @@ ip_output(struct mbuf *m0, ...)
IFP_TO_IA(ifp, ia);
} else {
if (ro->ro_rt == 0)
- rtalloc_mpath(ro, &ip->ip_src.s_addr, 0);
+ rtalloc_mpath(ro, &ip->ip_src.s_addr,
+ m->m_pkthdr.rdomain);
if (ro->ro_rt == 0) {
ipstat.ips_noroute++;
@@ -623,7 +629,8 @@ sendit:
struct sockaddr_in dst = {
sizeof(struct sockaddr_in), AF_INET};
dst.sin_addr = ip->ip_dst;
- rt = icmp_mtudisc_clone((struct sockaddr *)&dst);
+ rt = icmp_mtudisc_clone((struct sockaddr *)&dst,
+ m->m_pkthdr.rdomain);
rt_mtucloned = 1;
}
DPRINTF(("ip_output: spi %08x mtu %d rt %p cloned %d\n",
@@ -632,8 +639,9 @@ sendit:
rt->rt_rmx.rmx_mtu = icmp_mtu;
if (ro && ro->ro_rt != NULL) {
RTFREE(ro->ro_rt);
- ro->ro_rt = (struct rtentry *) 0;
- rtalloc(ro);
+ ro->ro_rt = NULL;
+ rtalloc1(&ro->ro_dst, 1,
+ m->m_pkthdr.rdomain);
}
if (rt_mtucloned)
rtfree(rt);
@@ -1037,6 +1045,7 @@ ip_ctloutput(op, so, level, optname, mp)
u_int16_t opt16val;
#endif
int error = 0;
+ u_int rtid = 0;
if (level != IPPROTO_IP) {
error = EINVAL;
@@ -1121,7 +1130,8 @@ ip_ctloutput(op, so, level, optname, mp)
case IP_MULTICAST_LOOP:
case IP_ADD_MEMBERSHIP:
case IP_DROP_MEMBERSHIP:
- error = ip_setmoptions(optname, &inp->inp_moptions, m);
+ error = ip_setmoptions(optname, &inp->inp_moptions, m,
+ inp->inp_rdomain);
break;
case IP_PORTRANGE:
@@ -1385,6 +1395,18 @@ ip_ctloutput(op, so, level, optname, mp)
}
#endif
break;
+ case SO_RDOMAIN:
+ if (m == NULL || m->m_len < sizeof(u_int)) {
+ error = EINVAL;
+ break;
+ }
+ rtid = *mtod(m, u_int *);
+ if (!rtable_exists(rtid)) {
+ error = EINVAL;
+ break;
+ }
+ inp->inp_rdomain = rtid;
+ break;
default:
error = ENOPROTOOPT;
break;
@@ -1575,6 +1597,11 @@ ip_ctloutput(op, so, level, optname, mp)
}
#endif
break;
+ case SO_RDOMAIN:
+ *mp = m = m_get(M_WAIT, MT_SOOPTS);
+ m->m_len = sizeof(u_int);
+ *mtod(m, u_int *) = inp->inp_rdomain;
+ break;
default:
error = ENOPROTOOPT;
break;
@@ -1696,10 +1723,8 @@ bad:
* Set the IP multicast options in response to user setsockopt().
*/
int
-ip_setmoptions(optname, imop, m)
- int optname;
- struct ip_moptions **imop;
- struct mbuf *m;
+ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
+ u_int rdomain)
{
int error = 0;
u_char loop;
@@ -1756,7 +1781,7 @@ ip_setmoptions(optname, imop, m)
* IP address. Find the interface and confirm that
* it supports multicasting.
*/
- INADDR_TO_IFP(addr, ifp);
+ INADDR_TO_IFP(addr, ifp, rdomain);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
error = EADDRNOTAVAIL;
break;
@@ -1812,7 +1837,9 @@ ip_setmoptions(optname, imop, m)
dst->sin_len = sizeof(*dst);
dst->sin_family = AF_INET;
dst->sin_addr = mreq->imr_multiaddr;
- rtalloc(&ro);
+ if (!(ro.ro_rt && ro.ro_rt->rt_ifp &&
+ (ro.ro_rt->rt_flags & RTF_UP)))
+ ro.ro_rt = rtalloc1(&ro.ro_dst, 1, rdomain);
if (ro.ro_rt == NULL) {
error = EADDRNOTAVAIL;
break;
@@ -1820,7 +1847,7 @@ ip_setmoptions(optname, imop, m)
ifp = ro.ro_rt->rt_ifp;
rtfree(ro.ro_rt);
} else {
- INADDR_TO_IFP(mreq->imr_interface, ifp);
+ INADDR_TO_IFP(mreq->imr_interface, ifp, rdomain);
}
/*
* See if we found an interface, and confirm that it
@@ -1906,7 +1933,7 @@ ip_setmoptions(optname, imop, m)
if (mreq->imr_interface.s_addr == INADDR_ANY)
ifp = NULL;
else {
- INADDR_TO_IFP(mreq->imr_interface, ifp);
+ INADDR_TO_IFP(mreq->imr_interface, ifp, rdomain);
if (ifp == NULL) {
error = EADDRNOTAVAIL;
break;