summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorCedric Berger <cedric@cvs.openbsd.org>2004-06-06 16:49:10 +0000
committerCedric Berger <cedric@cvs.openbsd.org>2004-06-06 16:49:10 +0000
commit9e25ab1fcd3c8a3b75b6ae3c7ca26a172a86d2e8 (patch)
tree021044703db486221cd747d714184ece1513b162 /sys/net
parentac4791c970556454694a0c9ab754ea95de5b9bc1 (diff)
extend routing table to be able to match and route packets based on
their *source* IP address in addition to their destination address. routing table "destination" now contains a "struct sockaddr_rtin" for IPv4 instead of a "struct sockaddr_in". the routing socket has been extended in a backward-compatible way. todo: PMTU enhancements, IPv6. ok deraadt@ mcbride@
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/pf.c28
-rw-r--r--sys/net/route.c24
-rw-r--r--sys/net/route.h26
-rw-r--r--sys/net/route_src.c203
-rw-r--r--sys/net/rtsock.c7
5 files changed, 269 insertions, 19 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 12cff3c1ef8..0eead2874af 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.449 2004/05/19 17:50:51 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.450 2004/06/06 16:49:08 cedric Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -199,8 +199,8 @@ u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t,
sa_family_t);
u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t,
sa_family_t);
-u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t,
- u_int16_t);
+u_int16_t pf_calc_mss(struct pf_addr *, struct pf_addr *,
+ sa_family_t, u_int16_t);
void pf_set_rt_ifp(struct pf_state *,
struct pf_addr *);
int pf_check_proto_cksum(struct mbuf *, int, int,
@@ -2415,10 +2415,11 @@ pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
}
u_int16_t
-pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
+pf_calc_mss(struct pf_addr *saddr, struct pf_addr *daddr, sa_family_t af,
+ u_int16_t offer)
{
#ifdef INET
- struct sockaddr_in *dst;
+ struct sockaddr_rtin *dst;
struct route ro;
#endif /* INET */
#ifdef INET6
@@ -2434,10 +2435,11 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
case AF_INET:
hlen = sizeof(struct ip);
bzero(&ro, sizeof(ro));
- dst = (struct sockaddr_in *)&ro.ro_dst;
- dst->sin_family = AF_INET;
- dst->sin_len = sizeof(*dst);
- dst->sin_addr = addr->v4;
+ dst = satortin(&ro.ro_dst);
+ dst->rtin_family = AF_INET;
+ dst->rtin_len = sizeof(*dst);
+ dst->rtin_dst = daddr->v4;
+ dst->rtin_src = saddr->v4;
rtalloc_noclone(&ro, NO_CLONING);
rt = ro.ro_rt;
break;
@@ -2449,7 +2451,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
dst6->sin6_family = AF_INET6;
dst6->sin6_len = sizeof(*dst6);
- dst6->sin6_addr = addr->v6;
+ dst6->sin6_addr = daddr->v6;
rtalloc_noclone((struct route *)&ro6, NO_CLONING);
rt = ro6.ro_rt;
break;
@@ -2838,8 +2840,8 @@ cleanup:
s->src.seqhi = htonl(arc4random());
/* Find mss option */
mss = pf_get_mss(m, off, th->th_off, af);
- mss = pf_calc_mss(saddr, af, mss);
- mss = pf_calc_mss(daddr, af, mss);
+ mss = pf_calc_mss(saddr, daddr, af, mss);
+ mss = pf_calc_mss(daddr, saddr, af, mss);
s->src.mss = mss;
pf_send_tcp(r, af, daddr, saddr, th->th_dport,
th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
@@ -4999,7 +5001,9 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
dst->sin_addr = ip->ip_dst;
if (r->rt == PF_FASTROUTE) {
+ satortin(&ro->ro_dst)->rtin_src = ip->ip_src;
rtalloc(ro);
+ satortin(&ro->ro_dst)->rtin_src.s_addr = 0;
if (ro->ro_rt == 0) {
ipstat.ips_noroute++;
goto bad;
diff --git a/sys/net/route.c b/sys/net/route.c
index 06fa17d9dcc..62c5b865121 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.40 2004/04/25 02:48:04 itojun Exp $ */
+/* $OpenBSD: route.c,v 1.41 2004/06/06 16:49:09 cedric Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -138,6 +138,9 @@ struct radix_node_head *rt_tables[AF_MAX+1];
int rttrash; /* routes not in table but not freed */
struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
+const struct sockaddr_rtin rt_defmask4 = { /* default IPv4 route mask */
+ offsetof(struct sockaddr_rtin, rtin_src), 0, 0, { -1 }};
+
static int okaytoclone(u_int, int);
static int rtdeletemsg(struct rtentry *);
static int rtflushclone1(struct radix_node *, void *);
@@ -668,8 +671,14 @@ rtrequest1(req, info, ret_nrt)
if ((rnh = rt_tables[dst->sa_family]) == 0)
senderr(EAFNOSUPPORT);
- if (flags & RTF_HOST)
- netmask = 0;
+ if (flags & RTF_HOST) {
+#ifdef SMALL_KERNEL
+ netmask = (dst->sa_family == AF_INET) ?
+ (struct sockaddr *)&rt_defmask4 : NULL;
+#else
+ sroute_verify_host(info);
+#endif
+ }
switch (req) {
case RTM_DELETE:
if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL)
@@ -726,8 +735,15 @@ rtrequest1(req, info, ret_nrt)
flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
flags |= RTF_CLONED;
gateway = rt->rt_gateway;
- if ((netmask = rt->rt_genmask) == NULL)
+#ifdef SMALL_KERNEL
+ if ((netmask = rt->rt_genmask) == NULL) {
flags |= RTF_HOST;
+ if (dst->sa_family == AF_INET)
+ netmask = (struct sockaddr *)&rt_defmask4;
+ }
+#else
+ sroute_clone_route(info, rt_mask(rt), rt->rt_genmask);
+#endif
goto makeroute;
case RTM_ADD:
diff --git a/sys/net/route.h b/sys/net/route.h
index 2b79cd10dbb..fefbda574d2 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.h,v 1.21 2004/05/04 22:50:18 claudio Exp $ */
+/* $OpenBSD: route.h,v 1.22 2004/06/06 16:49:09 cedric Exp $ */
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
/*
@@ -150,6 +150,7 @@ struct ortentry {
#define RTF_PROTO2 0x4000 /* protocol specific routing flag */
#define RTF_PROTO1 0x8000 /* protocol specific routing flag */
#define RTF_CLONED 0x10000 /* this is a cloned route */
+#define RTF_SOURCE 0x20000 /* this route has a source selector */
#ifndef _KERNEL
/* obsoleted */
@@ -223,6 +224,8 @@ struct rt_msghdr {
#define RTA_IFA 0x20 /* interface addr sockaddr present */
#define RTA_AUTHOR 0x40 /* sockaddr for author of redirect */
#define RTA_BRD 0x80 /* for NEWADDR, broadcast or p-p dest addr */
+#define RTA_SRC 0x100 /* source sockaddr present */
+#define RTA_SRCMASK 0x200 /* source netmask present */
/*
* Index offsets for sockaddr array for alternate internal encoding.
@@ -235,7 +238,9 @@ struct rt_msghdr {
#define RTAX_IFA 5 /* interface addr sockaddr present */
#define RTAX_AUTHOR 6 /* sockaddr for author of redirect */
#define RTAX_BRD 7 /* for NEWADDR, broadcast or p-p dest addr */
-#define RTAX_MAX 8 /* size of array to allocate */
+#define RTAX_SRC 8 /* source sockaddr present */
+#define RTAX_SRCMASK 9 /* source netmask present */
+#define RTAX_MAX 10 /* size of array to allocate */
struct rt_addrinfo {
int rti_addrs;
@@ -295,6 +300,7 @@ struct rttimer_queue {
extern struct route_cb route_cb;
extern struct rtstat rtstat;
extern struct radix_node_head *rt_tables[];
+extern const struct sockaddr_rtin rt_defmask4;
struct socket;
void route_init(void);
@@ -340,5 +346,21 @@ int rtrequest(int, struct sockaddr *,
struct sockaddr *, struct sockaddr *, int,
struct rtentry **);
int rtrequest1(int, struct rt_addrinfo *, struct rtentry **);
+
+#ifndef SMALL_KERNEL
+void sroute_verify_host(struct rt_addrinfo *);
+void sroute_clone_route(struct rt_addrinfo *, struct sockaddr *,
+ struct sockaddr *);
+void sroute_compact(struct rt_addrinfo *, int);
+void sroute_expand(struct rt_addrinfo *);
+struct sockaddr *
+ sroute_clone_mask4(struct sockaddr *, struct sockaddr *);
+#else
+#define sroute_compact(ai, int)
+#define sroute_expand(ai)
+#define sroute_clone_mask4(old, gen) ((gen) != NULL ? (gen) : \
+ (struct sockaddr *)&rt_defmask4)
+#endif
+
#endif /* _KERNEL */
#endif /* _NET_ROUTE_H_ */
diff --git a/sys/net/route_src.c b/sys/net/route_src.c
new file mode 100644
index 00000000000..8287543f249
--- /dev/null
+++ b/sys/net/route_src.c
@@ -0,0 +1,203 @@
+/* $OpenBSD: route_src.c,v 1.1 2004/06/06 16:49:09 cedric Exp $ */
+
+/*
+ * Copyright (c) 2004 Cedric Berger <cedric@berger.to>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+
+void mask_set(void *, struct sockaddr *, int, int);
+struct sockaddr *mask_trim(struct sockaddr *, int, int);
+
+/*
+ * verify that the netmask is NULL or has all 1s for the destination part.
+ * setup a corrected mask otherwise.
+ */
+void
+sroute_verify_host(struct rt_addrinfo *ai)
+{
+ static struct sockaddr_rtin netmask4;
+
+ if (ai->rti_info[RTAX_NETMASK] == NULL)
+ return; /* no mask is a host mask */
+ if (ai->rti_info[RTAX_DST]->sa_family == AF_INET)
+ goto _inet;
+ /* just clear the netmask */
+ ai->rti_info[RTAX_NETMASK] = NULL;
+ return;
+
+_inet:
+ if (satortin(ai->rti_info[RTAX_NETMASK])->rtin_dst.s_addr ==
+ (in_addr_t)-1)
+ return; /* all 1s is a host mask */
+ netmask4.rtin_dst.s_addr = (in_addr_t)-1;
+ netmask4.rtin_src = satortin(ai->rti_info[RTAX_NETMASK])->rtin_src;
+ ai->rti_info[RTAX_NETMASK] = mask_trim(sintosa(&netmask4),
+ offsetof(struct sockaddr_rtin, rtin_dst), 8);
+}
+
+/*
+ * set the netmask of a cloned route. take the source part of the
+ * old mask and use the genmask (or NULL) for the destination part.
+ */
+void
+sroute_clone_route(struct rt_addrinfo *ai, struct sockaddr *oldmask,
+ struct sockaddr *genmask)
+{
+ if (ai->rti_info[RTAX_DST]->sa_family == AF_INET)
+ goto _inet;
+ if ((ai->rti_info[RTAX_NETMASK] = genmask) == NULL)
+ ai->rti_flags |= RTF_HOST;
+ return;
+
+_inet:
+ ai->rti_info[RTAX_NETMASK] = sroute_clone_mask4(oldmask, genmask);
+ if (ai->rti_info[RTAX_NETMASK] == NULL || satortin(
+ ai->rti_info[RTAX_NETMASK])->rtin_dst.s_addr == (in_addr_t)-1)
+ ai->rti_flags |= RTF_HOST;
+}
+
+/*
+ * get the netmask of an IPv4 cloned route. take the source part of the
+ * old mask and use the genmask (or NULL) for the destination part.
+ */
+struct sockaddr *
+sroute_clone_mask4(struct sockaddr *oldmask, struct sockaddr *genmask)
+{
+ static struct sockaddr_rtin netmask4;
+
+ mask_set(&netmask4.rtin_dst, genmask,
+ offsetof(struct sockaddr_in, sin_addr), 4);
+ mask_set(&netmask4.rtin_src, oldmask,
+ offsetof(struct sockaddr_rtin, rtin_src), 4);
+ return mask_trim(sintosa(&netmask4),
+ offsetof(struct sockaddr_rtin, rtin_dst), 8);
+}
+
+/*
+ * userland provides RTAX_SRC and RTAX_SRCMASK entries, but the kernel wants
+ * that info packed inside RTAX_DST and RTAX_NETMASK themselves.
+ */
+void
+sroute_compact(struct rt_addrinfo *ai, int type)
+{
+ static struct sockaddr_rtin dst4 = { sizeof(dst4), AF_INET };
+ static struct sockaddr_rtin netmask4;
+
+ if (ai->rti_info[RTAX_DST]->sa_family == AF_INET)
+ goto _inet;
+ return;
+
+_inet:
+ dst4.rtin_dst = satosin(ai->rti_info[RTAX_DST])->sin_addr;
+ mask_set(&netmask4.rtin_dst, ai->rti_info[RTAX_NETMASK],
+ offsetof(struct sockaddr_in, sin_addr), 4);
+ if (ai->rti_info[RTAX_SRC] != NULL) {
+ dst4.rtin_src = satosin(ai->rti_info[RTAX_SRC])->sin_addr;
+ mask_set(&netmask4.rtin_src, ai->rti_info[RTAX_SRCMASK],
+ offsetof(struct sockaddr_in, sin_addr), 4);
+ } else
+ dst4.rtin_src.s_addr = netmask4.rtin_src.s_addr = 0;
+ ai->rti_info[RTAX_DST] = (struct sockaddr *)&dst4;
+ /*
+ * do not generate a netmask artificially for RTM_GET or it
+ * will break the loose-matching behaviour that is expected.
+ */
+ if (type != RTM_GET || ai->rti_info[RTAX_NETMASK] != NULL ||
+ ai->rti_info[RTAX_SRCMASK] != NULL)
+ ai->rti_info[RTAX_NETMASK] = mask_trim(sintosa(&netmask4),
+ offsetof(struct sockaddr_rtin, rtin_dst), 8);
+}
+
+/*
+ * opposite of sroute_compact, when sending a routing message to userland.
+ */
+void
+sroute_expand(struct rt_addrinfo *ai)
+{
+ static struct sockaddr_in dst4 = { sizeof(dst4), AF_INET };
+ static struct sockaddr_in src4 = { sizeof(src4), AF_INET };
+ static struct sockaddr_in netmask4, srcmask4;
+
+ if (ai->rti_info[RTAX_DST]->sa_family == AF_INET)
+ goto _inet;
+ return;
+
+_inet:
+ dst4.sin_addr = satortin(ai->rti_info[RTAX_DST])->rtin_dst;
+ src4.sin_addr = satortin(ai->rti_info[RTAX_DST])->rtin_src;
+ ai->rti_info[RTAX_DST] = sintosa(&dst4);
+ ai->rti_info[RTAX_SRC] = sintosa(&src4);
+ mask_set(&netmask4.sin_addr, ai->rti_info[RTAX_NETMASK],
+ offsetof(struct sockaddr_rtin, rtin_dst), 4);
+ mask_set(&srcmask4.sin_addr, ai->rti_info[RTAX_NETMASK],
+ offsetof(struct sockaddr_rtin, rtin_src), 4);
+ ai->rti_info[RTAX_NETMASK] = mask_trim(sintosa(&netmask4),
+ offsetof(struct sockaddr_in, sin_addr), 4);
+ ai->rti_info[RTAX_SRCMASK] = mask_trim(sintosa(&srcmask4),
+ offsetof(struct sockaddr_in, sin_addr), 4);
+ if (!src4.sin_addr.s_addr && !srcmask4.sin_addr.s_addr) {
+ ai->rti_info[RTAX_SRC] = NULL;
+ ai->rti_info[RTAX_SRCMASK] = NULL;
+ }
+}
+
+/*
+ * set a netmask from a potentially NULL or truncated mask.
+ */
+void
+mask_set(void *mask, struct sockaddr *sa, int off, int sz)
+{
+ int i, len = off + sz;
+
+ if (sa == NULL) {
+ memset(mask, -1, sz);
+ return;
+ }
+ bzero(mask, sz);
+ for (i = off; i < len; i++) {
+ if (i >= sa->sa_len)
+ break;
+ *((char *)mask)++ = ((char *)sa)[i];
+ }
+}
+
+/*
+ * set length and trim unused bytes from a netmask.
+ * return NULL if the mask is all 1s (host route)
+ */
+struct sockaddr *
+mask_trim(struct sockaddr *sa, int off, int sz)
+{
+ int i, len = off + sz;
+
+ if (sa == NULL)
+ return (NULL);
+ for (i = len; i > 1 && ((char *)sa)[i-1] == 0; i--)
+ ;
+ sa->sa_len = i;
+ if (i < len)
+ return (sa);
+ for (i = off; i < len; i++)
+ if (((char *)sa)[i] != (char)-1)
+ break;
+ return ((i < len) ? sa : NULL);
+}
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 7b64447eebe..3b55a425ed3 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtsock.c,v 1.38 2004/05/12 20:46:00 claudio Exp $ */
+/* $OpenBSD: rtsock.c,v 1.39 2004/06/06 16:49:09 cedric Exp $ */
/* $NetBSD: rtsock.c,v 1.18 1996/03/29 00:32:10 cgd Exp $ */
/*
@@ -221,6 +221,7 @@ route_output(struct mbuf *m, ...)
senderr(EINVAL);
if (gate != 0 && (gate->sa_family >= AF_MAX))
senderr(EINVAL);
+ sroute_compact(&info, rtm->rtm_type);
if (genmask) {
struct radix_node *t;
t = rn_addmask((caddr_t)genmask, 0, 1);
@@ -324,6 +325,7 @@ route_output(struct mbuf *m, ...)
ifaaddr = 0;
}
}
+ sroute_expand(&info);
len = rt_msg2(rtm->rtm_type, &info, (caddr_t)0,
(struct walkarg *)0);
if (len > rtm->rtm_msglen) {
@@ -637,6 +639,7 @@ rt_missmsg(type, rtinfo, flags, error)
if (route_cb.any_count == 0)
return;
+ sroute_expand(rtinfo);
m = rt_msg1(type, rtinfo);
if (m == 0)
return;
@@ -725,6 +728,7 @@ rt_newaddrmsg(cmd, ifa, error, rt)
netmask = rt_mask(rt);
dst = sa = rt_key(rt);
gate = rt->rt_gateway;
+ sroute_expand(&info);
if ((m = rt_msg1(cmd, &info)) == NULL)
continue;
rtm = mtod(m, struct rt_msghdr *);
@@ -791,6 +795,7 @@ sysctl_dumpentry(rn, v)
if (rt->rt_ifp->if_flags & IFF_POINTOPOINT)
brdaddr = rt->rt_ifa->ifa_dstaddr;
}
+ sroute_expand(&info);
size = rt_msg2(RTM_GET, &info, 0, w);
if (w->w_where && w->w_tmem && w->w_needed <= 0) {
struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem;