summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-03-22 03:50:36 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-03-22 03:50:36 +0000
commit3bb8147b834d766311f08a0c1549461ea53351eb (patch)
tree4b3469deea0ee9b65832fdb0aba02d2b1c58c1db
parent3286d6b6e228d4fc5d1dc8f1cedab7d76d8b6149 (diff)
aintroduce ip6_{next,last}hdr which lets us parse IPv6 header chain correctly.
use it from icmp6 code.
-rw-r--r--sys/netinet6/icmp6.c111
-rw-r--r--sys/netinet6/ip6_input.c141
-rw-r--r--sys/netinet6/ip6_var.h6
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) {
@@ -1110,6 +1140,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 *));