summaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/icmp6.c116
-rw-r--r--sys/netinet6/in6_proto.c10
-rw-r--r--sys/netinet6/ip6_input.c29
-rw-r--r--sys/netinet6/ip6_var.h15
-rw-r--r--sys/netinet6/nd6.c46
-rw-r--r--sys/netinet6/nd6.h8
6 files changed, 178 insertions, 46 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 3594241b158..ac64e71b10d 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: icmp6.c,v 1.18 2000/06/13 17:32:47 itojun Exp $ */
-/* $KAME: icmp6.c,v 1.113 2000/06/12 09:24:41 itojun Exp $ */
+/* $OpenBSD: icmp6.c,v 1.19 2000/07/06 10:11:24 itojun Exp $ */
+/* $KAME: icmp6.c,v 1.119 2000/07/03 14:16:46 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -109,10 +109,14 @@ struct icmp6stat icmp6stat;
extern struct in6pcb rawin6pcb;
extern struct timeval icmp6errratelim;
+static struct timeval icmp6errratelim_last;
+extern int icmp6errppslim;
+static int icmp6errpps_count = 0;
extern int icmp6_nodeinfo;
static struct rttimer_queue *icmp6_mtudisc_timeout_q = NULL;
extern int pmtu_expire;
+static void icmp6_errcount __P((struct icmp6errstat *, int, int));
static void icmp6_mtudisc_update __P((struct in6_addr *, struct icmp6_hdr *,
struct mbuf *));
static int icmp6_ratelimit __P((const struct in6_addr *, const int, const int));
@@ -139,6 +143,64 @@ icmp6_init()
icmp6_mtudisc_timeout_q = rt_timer_queue_create(pmtu_expire);
}
+static void
+icmp6_errcount(stat, type, code)
+ struct icmp6errstat *stat;
+ int type, code;
+{
+ switch(type) {
+ case ICMP6_DST_UNREACH:
+ switch (code) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ stat->icp6errs_dst_unreach_noroute++;
+ return;
+ case ICMP6_DST_UNREACH_ADMIN:
+ stat->icp6errs_dst_unreach_admin++;
+ return;
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ stat->icp6errs_dst_unreach_beyondscope++;
+ return;
+ case ICMP6_DST_UNREACH_ADDR:
+ stat->icp6errs_dst_unreach_addr++;
+ return;
+ case ICMP6_DST_UNREACH_NOPORT:
+ stat->icp6errs_dst_unreach_noport++;
+ return;
+ }
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ stat->icp6errs_packet_too_big++;
+ return;
+ case ICMP6_TIME_EXCEEDED:
+ switch(code) {
+ case ICMP6_TIME_EXCEED_TRANSIT:
+ stat->icp6errs_time_exceed_transit++;
+ return;
+ case ICMP6_TIME_EXCEED_REASSEMBLY:
+ stat->icp6errs_time_exceed_reassembly++;
+ return;
+ }
+ break;
+ case ICMP6_PARAM_PROB:
+ switch(code) {
+ case ICMP6_PARAMPROB_HEADER:
+ stat->icp6errs_paramprob_header++;
+ return;
+ case ICMP6_PARAMPROB_NEXTHEADER:
+ stat->icp6errs_paramprob_nextheader++;
+ return;
+ case ICMP6_PARAMPROB_OPTION:
+ stat->icp6errs_paramprob_option++;
+ return;
+ }
+ break;
+ case ND_REDIRECT:
+ stat->icp6errs_redirect++;
+ return;
+ }
+ stat->icp6errs_unknown++;
+}
+
/*
* Generate an error packet of type error in response to bad IP6 packet.
*/
@@ -155,6 +217,9 @@ icmp6_error(m, type, code, param)
icmp6stat.icp6s_error++;
+ /* count per-type-code statistics */
+ icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
+
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), );
#else
@@ -1633,6 +1698,10 @@ icmp6_reflect(m, off)
* If there are extra headers between IPv6 and ICMPv6, strip
* off that header first.
*/
+#ifdef DIAGNOSTIC
+ if (sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) > MHLEN)
+ panic("assumption failed in icmp6_reflect");
+#endif
if (off > sizeof(struct ip6_hdr)) {
size_t l;
struct ip6_hdr nip6;
@@ -1786,6 +1855,9 @@ icmp6_fasttimo()
{
mld6_fasttimeo();
+
+ /* reset ICMPv6 pps limit */
+ icmp6errpps_count = 0;
}
static const char *
@@ -2022,6 +2094,8 @@ icmp6_redirect_output(m0, rt)
struct ifnet *outif = NULL;
struct sockaddr_in6 src_sa;
+ icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
+
/* if we are not router, we don't send icmp6 redirect */
if (!ip6_forwarding || ip6_accept_rtadv)
goto fail;
@@ -2168,6 +2242,8 @@ nolladdropt:;
m->m_pkthdr.len = m->m_len = p - (u_char *)ip6;
/* just to be safe */
+ if (p - (u_char *)ip6 > maxlen)
+ goto noredhdropt;
{
/* redirected header option */
@@ -2238,6 +2314,7 @@ nolladdropt:;
m->m_next = m0;
m->m_pkthdr.len = m->m_len + m0->m_len;
}
+noredhdropt:;
if (IN6_IS_ADDR_LINKLOCAL(&sip6->ip6_src))
sip6->ip6_src.s6_addr16[1] = 0;
@@ -2286,6 +2363,14 @@ fail:
* Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
* limitation.
*
+ * There are two limitations defined:
+ * - pps limit: ICMPv6 error packet cannot exceed defined packet-per-second.
+ * we measure it every 0.2 second, since fasttimo works every 0.2 second.
+ * - rate limit: ICMPv6 error packet cannot appear more than once per
+ * defined interval.
+ * In any case, if we perform rate limitation, we'll see jitter in the ICMPv6
+ * error packets.
+ *
* XXX per-destination/type check necessary?
*/
static int
@@ -2294,13 +2379,23 @@ icmp6_ratelimit(dst, type, code)
const int type; /* not used at this moment */
const int code; /* not used at this moment */
{
- static struct timeval icmp6errratelim_last;
+ int ret;
- /*
- * ratecheck() returns true if it is okay to send. We return
- * true if it is not okay to send.
- */
- return (ratecheck(&icmp6errratelim_last, &icmp6errratelim) == 0);
+ ret = 0; /*okay to send*/
+
+ /* PPS limit */
+ icmp6errpps_count++;
+ if (icmp6errppslim && icmp6errpps_count > icmp6errppslim / 5) {
+ /* The packet is subject to pps limit */
+ ret++;
+ }
+
+ if (!ratecheck(&icmp6errratelim_last, &icmp6errratelim)) {
+ /* The packet is subject to rate limit */
+ ret++;
+ }
+
+ return ret;
}
static struct rtentry *
@@ -2421,6 +2516,11 @@ icmp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
&nd6_useloopback);
case ICMPV6CTL_NODEINFO:
return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6_nodeinfo);
+ case ICMPV6CTL_ERRPPSLIMIT:
+ return sysctl_int(oldp, oldlenp, newp, newlen, &icmp6errppslim);
+ case ICMPV6CTL_ND6_MAXNUDHINT:
+ return sysctl_int(oldp, oldlenp, newp, newlen,
+ &nd6_maxnudhint);
default:
return ENOPROTOOPT;
}
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index 65424304f3d..244af2cec19 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -1,9 +1,10 @@
-/* $OpenBSD: in6_proto.c,v 1.22 2000/06/18 17:32:48 itojun Exp $ */
+/* $OpenBSD: in6_proto.c,v 1.23 2000/07/06 10:11:25 itojun Exp $ */
+/* $KAME: in6_proto.c,v 1.64 2000/06/20 16:20:27 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -15,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -299,7 +300,8 @@ u_long rip6_recvspace = RIPV6RCVQ;
/* ICMPV6 parameters */
int icmp6_rediraccept = 1; /* accept and process redirects */
int icmp6_redirtimeout = 10 * 60; /* 10 minutes */
-struct timeval icmp6errratelim = { 0, 1000 }; /* 1000usec = 1msec */
+struct timeval icmp6errratelim = { 0, 0 }; /* no ratelimit */
+int icmp6errppslim = 100; /* 100pps */
int icmp6_nodeinfo = 1; /* enable/disable NI response */
#ifdef TCP6
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 8381025c768..98f45003ac9 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_input.c,v 1.17 2000/07/02 10:10:55 itojun Exp $ */
+/* $OpenBSD: ip6_input.c,v 1.18 2000/07/06 10:11:25 itojun Exp $ */
/* $KAME: ip6_input.c,v 1.95 2000/07/02 07:49:37 jinmei Exp $ */
/*
@@ -428,13 +428,14 @@ ip6_input(m)
* Unicast check
*/
if (ip6_forward_rt.ro_rt != NULL &&
- (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 &&
+ (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) != 0 &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
&ip6_forward_rt.ro_dst.sin6_addr))
- ; /* cache hit */
+ ip6stat.ip6s_forward_cachehit++;
else {
if (ip6_forward_rt.ro_rt) {
/* route is down or destination is different */
+ ip6stat.ip6s_forward_cachemiss++;
RTFREE(ip6_forward_rt.ro_rt);
ip6_forward_rt.ro_rt = 0;
}
@@ -565,7 +566,7 @@ ip6_input(m)
ip6 = mtod(m, struct ip6_hdr *);
/*
- * if the payload length field is 0 and the next header field
+ * if the payload length field is 0 and the next header field
* indicates Hop-by-Hop Options header, then a Jumbo Payload
* option MUST be included.
*/
@@ -573,7 +574,7 @@ ip6_input(m)
/*
* Note that if a valid jumbo payload option is
* contained, ip6_hoptops_input() must set a valid
- * (non-zero) payload length to the variable plen.
+ * (non-zero) payload length to the variable plen.
*/
ip6stat.ip6s_badoptions++;
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
@@ -650,6 +651,24 @@ ip6_input(m)
return;
}
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ /*
+ * 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.
+ *
+ * For SIIT end node behavior, you may want to disable the check.
+ * However, you will become vulnerable to attacks using IPv4 mapped
+ * source.
+ */
+ 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;
+ }
+
/*
* Tell launch routine the next header
*/
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 138c419f980..be445bbc42a 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -1,10 +1,10 @@
-/* $OpenBSD: ip6_var.h,v 1.9 2000/06/19 03:43:17 itojun Exp $ */
-/* $KAME: ip6_var.h,v 1.28 2000/03/09 00:46:12 itojun Exp $ */
+/* $OpenBSD: ip6_var.h,v 1.10 2000/07/06 10:11:25 itojun Exp $ */
+/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -16,7 +16,7 @@
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -208,6 +208,9 @@ struct ip6stat {
u_quad_t ip6s_sources_otherscope[16];
/* number of times that an deprecated address is chosen */
u_quad_t ip6s_sources_deprecated[16];
+
+ u_quad_t ip6s_forward_cachehit;
+ u_quad_t ip6s_forward_cachemiss;
};
#ifdef _KERNEL
@@ -225,10 +228,6 @@ extern int ip6_forward_srcrt; /* forward src-routed? */
extern int ip6_use_deprecated; /* allow deprecated addr as source */
extern int ip6_rr_prune; /* router renumbering prefix
* walk list every 5 sec. */
-#ifdef MAPPED_ADDR_ENABLED
-extern int ip6_mapped_addr_on;
-#endif /* MAPPED_ADDR_ENABLED */
-
extern struct socket *ip6_mrouter; /* multicast routing daemon */
extern int ip6_sendredirects; /* send IP redirects when forwarding? */
extern int ip6_maxfragpackets; /* Maximum packets in reassembly queue */
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index f8f2e44caea..6a9d7dc0c2e 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: nd6.c,v 1.17 2000/06/16 21:47:17 provos Exp $ */
-/* $KAME: nd6.c,v 1.63 2000/05/17 12:35:59 jinmei Exp $ */
+/* $OpenBSD: nd6.c,v 1.18 2000/07/06 10:11:26 itojun Exp $ */
+/* $KAME: nd6.c,v 1.68 2000/07/02 14:48:02 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,6 +91,8 @@ int nd6_useloopback = 1; /* use loopback interface for local traffic */
/* preventing too many loops in ND option parsing */
int nd6_maxndopt = 10; /* max # of ND options allowed */
+int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */
+
/* for debugging? */
static int nd6_inuse, nd6_allocated;
@@ -220,8 +222,7 @@ nd6_setmtu(ifp)
*/
if (in6_maxmtu < ndi->linkmtu)
in6_maxmtu = ndi->linkmtu;
- }
- else
+ } else
in6_setmaxmtu();
}
}
@@ -462,8 +463,7 @@ nd6_timer(ignored_arg)
nd6_ns_output(ifp, &dst->sin6_addr,
&dst->sin6_addr,
ln, 0);
- }
- else
+ } else
ln->ln_state = ND6_LLINFO_STALE; /* XXX */
break;
case ND6_LLINFO_PROBE:
@@ -704,8 +704,7 @@ nd6_lookup(addr6, create, ifp)
(struct llinfo_nd6 *)rt->rt_llinfo;
ln->ln_state = ND6_LLINFO_NOSTATE;
}
- }
- else
+ } else
return(NULL);
}
rt->rt_refcnt--;
@@ -870,9 +869,10 @@ nd6_free(rt)
* XXX cost-effective metods?
*/
void
-nd6_nud_hint(rt, dst6)
+nd6_nud_hint(rt, dst6, force)
struct rtentry *rt;
struct in6_addr *dst6;
+ int force;
{
struct llinfo_nd6 *ln;
long time_second = time.tv_sec;
@@ -888,11 +888,10 @@ nd6_nud_hint(rt, dst6)
return;
}
- if ((rt->rt_flags & RTF_GATEWAY)
- || (rt->rt_flags & RTF_LLINFO) == 0
- || !rt->rt_llinfo
- || !rt->rt_gateway
- || rt->rt_gateway->sa_family != AF_LINK) {
+ if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
+ (rt->rt_flags & RTF_LLINFO) == 0 ||
+ !rt->rt_llinfo || !rt->rt_gateway ||
+ rt->rt_gateway->sa_family != AF_LINK) {
/* This is not a host route. */
return;
}
@@ -901,6 +900,16 @@ nd6_nud_hint(rt, dst6)
if (ln->ln_state < ND6_LLINFO_REACHABLE)
return;
+ /*
+ * if we get upper-layer reachability confirmation many times,
+ * it is possible we have false information.
+ */
+ if (!force) {
+ ln->ln_byhint++;
+ if (ln->ln_byhint > nd6_maxnudhint)
+ return;
+ }
+
ln->ln_state = ND6_LLINFO_REACHABLE;
if (ln->ln_expire)
ln->ln_expire = time_second +
@@ -1122,6 +1131,7 @@ nd6_rtrequest(req, rt, sa)
* which is specified by ndp command.
*/
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
} else {
/*
* When req == RTM_RESOLVE, rt is created and
@@ -1146,6 +1156,7 @@ nd6_rtrequest(req, rt, sa)
caddr_t macp = nd6_ifptomac(ifp);
ln->ln_expire = 0;
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
if (macp) {
Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen);
SDL(gate)->sdl_alen = ifp->if_addrlen;
@@ -1169,6 +1180,7 @@ nd6_rtrequest(req, rt, sa)
} else if (rt->rt_flags & RTF_ANNOUNCE) {
ln->ln_expire = 0;
ln->ln_state = ND6_LLINFO_REACHABLE;
+ ln->ln_byhint = 0;
/* join solicited node multicast for proxy ND */
if (ifp->if_flags & IFF_MULTICAST) {
@@ -1308,8 +1320,7 @@ nd6_ioctl(cmd, data, ifp)
if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) {
/* XXX: need to this hack for KAME stack */
drl->defrouter[i].rtaddr.s6_addr16[1] = 0;
- }
- else
+ } else
log(LOG_ERR,
"default router list contains a "
"non-linklocal address(%s)\n",
@@ -1354,8 +1365,7 @@ nd6_ioctl(cmd, data, ifp)
if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) {
/* XXX: hack for KAME */
RTRADDR.s6_addr16[1] = 0;
- }
- else
+ } else
log(LOG_ERR,
"a router(%s) advertises "
"a prefix with "
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 49e5d0d9714..340f4c3f50e 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: nd6.h,v 1.7 2000/05/19 13:55:17 itojun Exp $ */
-/* $KAME: nd6.h,v 1.21 2000/05/17 12:35:59 jinmei Exp $ */
+/* $OpenBSD: nd6.h,v 1.8 2000/07/06 10:11:26 itojun Exp $ */
+/* $KAME: nd6.h,v 1.23 2000/06/04 12:54:57 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -49,6 +49,7 @@ struct llinfo_nd6 {
u_long ln_expire; /* lifetime for NDP state transition */
short ln_state; /* reachability state */
short ln_router; /* 2^0: ND6 router bit */
+ int ln_byhint; /* # of times we made it reachable by UL hint */
};
#define ND6_LLINFO_NOSTATE -2
@@ -230,6 +231,7 @@ extern int nd6_delay;
extern int nd6_umaxtries;
extern int nd6_mmaxtries;
extern int nd6_useloopback;
+extern int nd6_maxnudhint;
extern struct llinfo_nd6 llinfo_nd6;
extern struct nd_ifinfo *nd_ifinfo;
extern struct nd_drhead nd_defrouter;
@@ -277,7 +279,7 @@ void nd6_setmtu __P((struct ifnet *));
void nd6_timer __P((void *));
void nd6_purge __P((struct ifnet *));
void nd6_free __P((struct rtentry *));
-void nd6_nud_hint __P((struct rtentry *, struct in6_addr *));
+void nd6_nud_hint __P((struct rtentry *, struct in6_addr *, int));
int nd6_resolve __P((struct ifnet *, struct rtentry *,
struct mbuf *, struct sockaddr *, u_char *));
#if defined(__bsdi__) && _BSDI_VERSION >= 199802