From 70b0445b13342ecbe532acad0268188f1a51f5a6 Mon Sep 17 00:00:00 2001 From: itojun Date: Wed, 22 Mar 2000 03:50:35 +0000 Subject: [PATCH] aintroduce ip6_{next,last}hdr which lets us parse IPv6 header chain correctly. use it from icmp6 code. --- sys/netinet6/icmp6.c | 111 ++++++++++-------------------- sys/netinet6/ip6_input.c | 141 ++++++++++++++++++++++++++++++++++++++- sys/netinet6/ip6_var.h | 6 +- 3 files changed, 181 insertions(+), 77 deletions(-) diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index c056e23f04e..6a5be740bb1 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,5 +1,5 @@ -/* $OpenBSD: icmp6.c,v 1.9 2000/02/28 14:30:40 itojun Exp $ */ -/* $KAME: icmp6.c,v 1.71 2000/02/28 09:25:42 jinmei Exp $ */ +/* $OpenBSD: icmp6.c,v 1.10 2000/03/22 03:50:35 itojun Exp $ */ +/* $KAME: icmp6.c,v 1.75 2000/03/11 09:32:17 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -150,7 +150,7 @@ icmp6_error(m, type, code, param) struct icmp6_hdr *icmp6; u_int preplen; int off; - u_char nxt; + int nxt; icmp6stat.icp6s_error++; @@ -183,86 +183,41 @@ icmp6_error(m, type, code, param) goto freeit; /* - * If the erroneous packet is also an ICMP error, discard it. + * If we are about to send ICMPv6 against ICMPv6 error/redirect, + * don't do it. */ - off = sizeof(struct ip6_hdr); - nxt = oip6->ip6_nxt; - while (1) { /* XXX: should avoid inf. loop explicitly? */ - struct ip6_ext *ip6e; + nxt = -1; + off = ip6_lasthdr(m, sizeof(struct ip6_hdr), oip6->ip6_nxt, &nxt); + if (off >= 0 && nxt == IPPROTO_ICMPV6) { struct icmp6_hdr *icp; - switch(nxt) { - case IPPROTO_IPV6: - case IPPROTO_IPV4: - case IPPROTO_UDP: - case IPPROTO_TCP: - case IPPROTO_ESP: - case IPPROTO_IPCOMP: - case IPPROTO_FRAGMENT: - /* - * ICMPv6 error must not be fragmented. - * XXX: but can we trust the sender? - */ - default: - /* What if unknown header followed by ICMP error? */ - goto generate; - case IPPROTO_ICMPV6: #ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), ); - icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); + IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct icmp6_hdr), ); + icp = (struct icmp6_hdr *)(mtod(m, caddr_t) + off); #else - IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off, - sizeof(*icp)); - if (icp == NULL) { - icmp6stat.icp6s_tooshort++; - return; - } -#endif - if (icp->icmp6_type < ICMP6_ECHO_REQUEST - || icp->icmp6_type == ND_REDIRECT) { - /* - * ICMPv6 error - * Special case: for redirect (which is - * informational) we must not send icmp6 error. - */ - icmp6stat.icp6s_canterror++; - goto freeit; - } else { - /* ICMPv6 informational */ - goto generate; - } - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - case IPPROTO_ROUTING: - case IPPROTO_AH: -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, 0, off + sizeof(struct ip6_ext), ); - ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); -#else - IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, - sizeof(*ip6e)); - if (ip6e == NULL) { - /*XXX stat */ - return; - } + IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off, + sizeof(*icp)); + if (icp == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } #endif - if (nxt == IPPROTO_AH) - off += (ip6e->ip6e_len + 2) << 2; - else - off += (ip6e->ip6e_len + 1) << 3; - nxt = ip6e->ip6e_nxt; - break; + if (icp->icmp6_type < ICMP6_ECHO_REQUEST || + icp->icmp6_type == ND_REDIRECT) { + /* + * ICMPv6 error + * Special case: for redirect (which is + * informational) we must not send icmp6 error. + */ + icmp6stat.icp6s_canterror++; + goto freeit; + } else { + /* ICMPv6 informational - send the error */ } + } else { + /* non-ICMPv6 - send the error */ } - freeit: - /* - * If we can't tell wheter or not we can generate ICMP6, free it. - */ - m_freem(m); - return; - - generate: oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */ /* Finally, do rate limitation check. */ @@ -303,6 +258,14 @@ icmp6_error(m, type, code, param) icmp6stat.icp6s_outhist[type]++; icmp6_reflect(m, sizeof(struct ip6_hdr)); /*header order: IPv6 - ICMPv6*/ + + return; + + freeit: + /* + * If we can't tell wheter or not we can generate ICMP6, free it. + */ + m_freem(m); } /* diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 6180f47b1f4..e39d5513e0b 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,5 @@ -/* $OpenBSD: ip6_input.c,v 1.8 2000/02/07 06:09:10 itojun Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.9 2000/03/22 03:50:35 itojun Exp $ */ +/* $KAME: ip6_input.c,v 1.72 2000/03/21 09:23:19 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -320,6 +321,35 @@ ip6_input(m) in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } +#if 1 + /* + * The following check is not documented in the spec. Malicious party + * may be able to use IPv4 mapped addr to confuse tcp/udp stack and + * bypass security checks (act as if it was from 127.0.0.1 by using + * IPv6 src ::ffff:127.0.0.1). Be cautious. + */ + if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || + IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } +#endif +#if 0 + /* + * Reject packets with IPv4 compatible addresses (auto tunnel). + * + * The code forbids auto tunnel relay case in RFC1933 (the check is + * stronger than RFC1933). We may want to re-enable it if mech-xx + * is revised to forbid relaying case. + */ + if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || + IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { + ip6stat.ip6s_badscope++; + in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); + goto bad; + } +#endif if (IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) || IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) { if (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) { @@ -1109,6 +1139,115 @@ ip6_get_prevhdr(m, off) } } +/* + * get next header offset. m will be retained. + */ +int +ip6_nexthdr(m, off, proto, nxtp) + struct mbuf *m; + int off; + int proto; + int *nxtp; +{ + struct ip6_hdr ip6; + struct ip6_ext ip6e; + struct ip6_frag fh; + + /* just in case */ + if (m == NULL) + panic("ip6_nexthdr: m == NULL"); + if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) + return -1; + + switch (proto) { + case IPPROTO_IPV6: + if (m->m_pkthdr.len < off + sizeof(ip6)) + return -1; + m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); + if (nxtp) + *nxtp = ip6.ip6_nxt; + off += sizeof(ip6); + return off; + + case IPPROTO_FRAGMENT: + /* + * terminate parsing if it is not the first fragment, + * it does not make sense to parse through it. + */ + if (m->m_pkthdr.len < off + sizeof(fh)) + return -1; + m_copydata(m, off, sizeof(fh), (caddr_t)&fh); + if ((ntohs(fh.ip6f_offlg) & IP6F_OFF_MASK) != 0) + return -1; + if (nxtp) + *nxtp = fh.ip6f_nxt; + off += sizeof(struct ip6_frag); + return off; + + case IPPROTO_AH: + if (m->m_pkthdr.len < off + sizeof(ip6e)) + return -1; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxtp) + *nxtp = ip6e.ip6e_nxt; + off += (ip6e.ip6e_len + 2) << 2; + return off; + + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_DSTOPTS: + if (m->m_pkthdr.len < off + sizeof(ip6e)) + return -1; + m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); + if (nxtp) + *nxtp = ip6e.ip6e_nxt; + off += (ip6e.ip6e_len + 1) << 3; + return off; + + case IPPROTO_NONE: + case IPPROTO_ESP: + case IPPROTO_IPCOMP: + /* give up */ + return -1; + + default: + return -1; + } + + return -1; +} + +/* + * get offset for the last header in the chain. m will be kept untainted. + */ +int +ip6_lasthdr(m, off, proto, nxtp) + struct mbuf *m; + int off; + int proto; + int *nxtp; +{ + int newoff; + int nxt; + + if (!nxtp) { + nxt = -1; + nxtp = &nxt; + } + while (1) { + newoff = ip6_nexthdr(m, off, proto, nxtp); + if (newoff < 0) + return off; + else if (newoff < off) + return -1; /* invalid */ + else if (newoff == off) + return newoff; + + off = newoff; + proto = *nxtp; + } +} + /* * System control for IP6 */ diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 1a77cd643b4..4e31b1fe439 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,5 +1,5 @@ -/* $OpenBSD: ip6_var.h,v 1.6 2000/02/28 16:40:39 itojun Exp $ */ -/* $KAME: ip6_var.h,v 1.27 2000/02/22 14:04:22 itojun Exp $ */ +/* $OpenBSD: ip6_var.h,v 1.7 2000/03/22 03:50:35 itojun Exp $ */ +/* $KAME: ip6_var.h,v 1.28 2000/03/09 00:46:12 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -253,6 +253,8 @@ void ip6_input __P((struct mbuf *)); void ip6_freemoptions __P((struct ip6_moptions *)); int ip6_unknown_opt __P((u_int8_t *, struct mbuf *, int)); char * ip6_get_prevhdr __P((struct mbuf *, int)); +int ip6_nexthdr __P((struct mbuf *, int, int, int *)); +int ip6_lasthdr __P((struct mbuf *, int, int, int *)); int ip6_mforward __P((struct ip6_hdr *, struct ifnet *, struct mbuf *)); int ip6_process_hopopts __P((struct mbuf *, u_int8_t *, int, u_int32_t *, u_int32_t *)); -- 2.20.1