From 9c617e3758be2054d11f2412c3a489e3281f74bd Mon Sep 17 00:00:00 2001 From: Martin Pieuchot Date: Thu, 5 Feb 2015 01:10:58 +0000 Subject: 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@ --- sys/net/pf.c | 7 +------ sys/netinet6/ip6_input.c | 38 +++++++++++++++++++++++++++++++++++--- sys/netinet6/ip6_output.c | 30 +++++++++++++++++++++++++++++- 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 @@ -319,6 +319,22 @@ ip6_input(struct mbuf *m) } #endif + /* + * 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) { + 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 @@ -345,6 +361,22 @@ ip6_input(struct mbuf *m) srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); #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; @@ -660,6 +661,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); /* -- cgit v1.2.3