diff options
-rw-r--r-- | sys/net/pf.c | 3 | ||||
-rw-r--r-- | sys/netinet6/ip6_input.c | 85 | ||||
-rw-r--r-- | sys/sys/mbuf.h | 3 |
3 files changed, 88 insertions, 3 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index bf060a789d0..63683e92cda 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.858 2013/11/15 10:18:26 haesbaert Exp $ */ +/* $OpenBSD: pf.c,v 1.859 2013/11/15 16:15:41 bluhm Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -6490,6 +6490,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, struct mbuf **m0, } } pd.eh = eh; + pd.m->m_pkthdr.pf.flags |= PF_TAG_PROCESSED; switch (pd.virtual_proto) { diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 4c3a41918c6..8260b74fb36 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.120 2013/11/11 09:15:35 mpi Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.121 2013/11/15 16:15:42 bluhm Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -122,6 +122,7 @@ struct ifqueue ip6intrq; struct ip6stat ip6stat; void ip6_init2(void *); +int ip6_check_rh0hdr(struct mbuf *, int *); int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); @@ -331,6 +332,20 @@ ip6_input(struct mbuf *m) srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); #endif + /* + * 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. + */ + if (!(m->m_pkthdr.pf.flags & PF_TAG_PROCESSED) && + ip6_check_rh0hdr(m, &off)) { + ip6stat.ip6s_badoptions++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); + icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, off); + /* m is already freed */ + return; + } + if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { ours = 1; @@ -700,6 +715,74 @@ ip6_input(struct mbuf *m) m_freem(m); } +/* scan packet for RH0 routing header. Mostly stolen from pf.c:pf_test() */ +int +ip6_check_rh0hdr(struct mbuf *m, int *offp) +{ + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + struct ip6_rthdr rthdr; + struct ip6_ext opt6; + u_int8_t proto = ip6->ip6_nxt; + int done = 0, lim, off, rh_cnt = 0; + + off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr); + lim = min(m->m_pkthdr.len, ntohs(ip6->ip6_plen) + sizeof(*ip6)); + do { + switch (proto) { + case IPPROTO_ROUTING: + *offp = off; + if (rh_cnt++) { + /* more then one rh header present */ + return (1); + } + + if (off + sizeof(rthdr) > lim) { + /* packet to short to make sense */ + return (1); + } + + m_copydata(m, off, sizeof(rthdr), (caddr_t)&rthdr); + + if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) { + *offp += offsetof(struct ip6_rthdr, ip6r_type); + return (1); + } + + off += (rthdr.ip6r_len + 1) * 8; + proto = rthdr.ip6r_nxt; + break; + case IPPROTO_AH: + case IPPROTO_HOPOPTS: + case IPPROTO_DSTOPTS: + /* get next header and header length */ + if (off + sizeof(opt6) > lim) { + /* + * Packet to short to make sense, we could + * reject the packet but as a router we + * should not do that so forward it. + */ + return (0); + } + + m_copydata(m, off, sizeof(opt6), (caddr_t)&opt6); + + if (proto == IPPROTO_AH) + off += (opt6.ip6e_len + 2) * 4; + else + off += (opt6.ip6e_len + 1) * 8; + proto = opt6.ip6e_nxt; + break; + case IPPROTO_FRAGMENT: + default: + /* end of header stack */ + done = 1; + break; + } + } while (!done); + + return (0); +} + /* * Hop-by-Hop options header processing. If a valid jumbo payload option is * included, the real payload length will be stored in plenp. diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index 2fed3c09910..cc4a973c966 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mbuf.h,v 1.168 2013/10/13 10:10:04 reyk Exp $ */ +/* $OpenBSD: mbuf.h,v 1.169 2013/11/15 16:15:42 bluhm Exp $ */ /* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */ /* @@ -100,6 +100,7 @@ struct pkthdr_pf { #define PF_TAG_DIVERTED_PACKET 0x10 #define PF_TAG_REROUTE 0x20 #define PF_TAG_REFRAGMENTED 0x40 /* refragmented ipv6 packet */ +#define PF_TAG_PROCESSED 0x80 /* packet was checked by pf */ /* record/packet header in first mbuf of chain; valid if M_PKTHDR set */ struct pkthdr { |