summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2015-02-05 01:10:58 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2015-02-05 01:10:58 +0000
commit9c617e3758be2054d11f2412c3a489e3281f74bd (patch)
treee59bd77e422182832c1beb48e499ead97d9ba186
parent4d73dee4aabd2b00728ba212fd59df611497560a (diff)
Make sure pf(4) does not see embedded scopes.
Packets destinated to link-local addresses are looped back with embedded scopes because we cannot restore them using the receiving interface (lo0). Embedded scopes are needed by the routing table to match RTF_LOCAL routes, but pf(4) never saw them and existing rules are likely to break without teaching the rule engine about them, found by dlg@ the hard way. So save and restore embedded scopes around pf_test() for packets going through loopback. ok dlg@, mikeb@
-rw-r--r--sys/net/pf.c7
-rw-r--r--sys/netinet6/ip6_input.c38
-rw-r--r--sys/netinet6/ip6_output.c30
3 files changed, 65 insertions, 10 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 447354ca924..9d87d1664b4 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.899 2015/01/24 00:29:06 deraadt Exp $ */
+/* $OpenBSD: pf.c,v 1.900 2015/02/05 01:10:57 mpi Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -819,11 +819,6 @@ pf_state_key_addr_setup(struct pf_pdesc *pd, void *arg, int sidx,
default:
if (multi == PF_ICMP_MULTI_LINK) {
key->addr[sidx].addr32[0] = __IPV6_ADDR_INT32_MLL;
-
- if (IN6_IS_SCOPE_EMBED(&key->addr[didx].v6))
- key->addr[sidx].addr16[1] =
- key->addr[didx].addr16[1];
-
key->addr[sidx].addr32[1] = 0;
key->addr[sidx].addr32[2] = 0;
key->addr[sidx].addr32[3] = __IPV6_ADDR_INT32_ONE;
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 4efcb5e08cf..a386594843c 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_input.c,v 1.135 2015/01/19 13:53:55 mpi Exp $ */
+/* $OpenBSD: ip6_input.c,v 1.136 2015/02/05 01:10:57 mpi Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@@ -190,8 +190,8 @@ ip6_input(struct mbuf *m)
struct ifnet *ifp;
struct ip6_hdr *ip6;
int off, nest;
- u_int32_t plen;
- u_int32_t rtalert = ~0;
+ u_int16_t src_scope, dst_scope;
+ u_int32_t plen, rtalert = ~0;
int nxt, ours = 0;
struct ifnet *deliverifp = NULL;
#if NPF > 0
@@ -324,6 +324,22 @@ ip6_input(struct mbuf *m)
* can be destinated to any local address, not necessarily to
* an address configured on `ifp'.
*/
+ if (ifp->if_flags & IFF_LOOPBACK) {
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
+ src_scope = ip6->ip6_src.s6_addr16[1];
+ ip6->ip6_src.s6_addr16[1] = 0;
+ }
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) {
+ dst_scope = ip6->ip6_dst.s6_addr16[1];
+ ip6->ip6_dst.s6_addr16[1] = 0;
+ }
+ }
+
+ /*
+ * If the packet has been received on a loopback interface it
+ * can be destinated to any local address, not necessarily to
+ * an address configured on `ifp'.
+ */
if ((ifp->if_flags & IFF_LOOPBACK) == 0) {
if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
ip6->ip6_src.s6_addr16[1] = htons(ifp->if_index);
@@ -346,6 +362,22 @@ ip6_input(struct mbuf *m)
#endif
/*
+ * Without embedded scope ID we cannot find link-local
+ * addresses in the routing table.
+ */
+ if (ifp->if_flags & IFF_LOOPBACK) {
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] = src_scope;
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] = dst_scope;
+ } else {
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] = htons(ifp->if_index);
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] = htons(ifp->if_index);
+ }
+
+ /*
* Be more secure than RFC5095 and scan for type 0 routing headers.
* If pf has already scanned the header chain, do not do it twice.
*/
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 92879462518..d8c49002851 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.165 2014/12/17 09:57:13 mpi Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.166 2015/02/05 01:10:57 mpi Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -168,6 +168,7 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro,
int error = 0;
u_long mtu;
int alwaysfrag, dontfrag;
+ u_int16_t src_scope, dst_scope;
u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
struct ip6_exthdrs exthdrs;
struct in6_addr finaldst;
@@ -661,6 +662,21 @@ reroute:
}
/*
+ * If this packet is going trough a loopback interface we wont
+ * be able to restore its scope ID using the interface index.
+ */
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
+ if (ifp->if_flags & IFF_LOOPBACK)
+ src_scope = ip6->ip6_src.s6_addr16[1];
+ ip6->ip6_src.s6_addr16[1] = 0;
+ }
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst)) {
+ if (ifp->if_flags & IFF_LOOPBACK)
+ dst_scope = ip6->ip6_dst.s6_addr16[1];
+ ip6->ip6_dst.s6_addr16[1] = 0;
+ }
+
+ /*
* Fill the outgoing interface to tell the upper layer
* to increment per-interface statistics.
*/
@@ -759,6 +775,18 @@ reroute:
ip6->ip6_dst.s6_addr16[1] = 0;
}
+ /*
+ * If the packet is not going on the wire it can be destinated
+ * to any local address. In this case do not clear its scopes
+ * to let ip6_input() find a matching local route.
+ */
+ if (ifp->if_flags & IFF_LOOPBACK) {
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] = src_scope;
+ if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] = dst_scope;
+ }
+
in6_proto_cksum_out(m, ifp);
/*