summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2002-05-28 03:04:39 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2002-05-28 03:04:39 +0000
commit53ec36032674958de4f895e731fb895e73b0ba88 (patch)
treef8c0e79e20f60c53d91f8445a2b26ec099fb843e /sys
parentff76c548fd5e060eba335ca880eee1e8c2d017d1 (diff)
limit number of IPv6 fragments (not the fragment queue size) to
fight against lots-of-frags DoS attacks. sync w/kame
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet6/frag6.c53
-rw-r--r--sys/netinet6/in6.h23
-rw-r--r--sys/netinet6/in6_proto.c3
-rw-r--r--sys/netinet6/ip6_input.c4
-rw-r--r--sys/netinet6/ip6_var.h4
5 files changed, 65 insertions, 22 deletions
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
index 83ff8d1a0ca..6d180787d85 100644
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: frag6.c,v 1.15 2002/05/27 19:48:27 deraadt Exp $ */
-/* $KAME: frag6.c,v 1.31 2001/05/17 13:45:34 jinmei Exp $ */
+/* $OpenBSD: frag6.c,v 1.16 2002/05/28 03:04:38 itojun Exp $ */
+/* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -70,6 +70,7 @@ static void frag6_freef(struct ip6q *);
static int ip6q_locked;
u_int frag6_nfragpackets;
+u_int frag6_nfrags;
struct ip6q ip6q; /* ip6 reassemble queue */
static __inline int ip6q_lock_try(void);
@@ -240,9 +241,8 @@ frag6_input(mp, offp, proto)
*/
if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
(((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
- icmp6_error(m, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- offsetof(struct ip6_hdr, ip6_plen));
+ icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
+ offsetof(struct ip6_hdr, ip6_plen));
in6_ifstat_inc(dstifp, ifs6_reass_fail);
return IPPROTO_DONE;
}
@@ -255,6 +255,16 @@ frag6_input(mp, offp, proto)
IP6Q_LOCK();
+ /*
+ * Enforce upper bound on number of fragments.
+ * If maxfrag is 0, never accept fragments.
+ * If maxfrag is -1, accept all fragments without limitation.
+ */
+ if (ip6_maxfrags < 0)
+ ;
+ else if (frag6_nfrags >= (u_int)ip6_maxfrags)
+ goto dropfrag;
+
for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
if (ip6f->ip6f_ident == q6->ip6q_ident &&
IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
@@ -270,8 +280,9 @@ frag6_input(mp, offp, proto)
/*
* Enforce upper bound on number of fragmented packets
* for which we attempt reassembly;
- * If maxfrag is 0, never accept fragments.
- * If maxfrag is -1, accept all fragments without limitation.
+ * If maxfragpackets is 0, never accept fragments.
+ * If maxfragpackets is -1, accept all fragments without
+ * limitation.
*/
if (ip6_maxfragpackets < 0)
;
@@ -279,7 +290,7 @@ frag6_input(mp, offp, proto)
goto dropfrag;
frag6_nfragpackets++;
q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
- M_DONTWAIT);
+ M_DONTWAIT);
if (q6 == NULL)
goto dropfrag;
bzero(q6, sizeof(*q6));
@@ -297,6 +308,8 @@ frag6_input(mp, offp, proto)
q6->ip6q_src = ip6->ip6_src;
q6->ip6q_dst = ip6->ip6_dst;
q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
+
+ q6->ip6q_nfrag = 0;
}
/*
@@ -305,8 +318,8 @@ frag6_input(mp, offp, proto)
*/
fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
if (fragoff == 0) {
- q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr)
- - sizeof(struct ip6_frag);
+ q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
+ sizeof(struct ip6_frag);
q6->ip6q_nxt = ip6f->ip6f_nxt;
}
@@ -320,13 +333,12 @@ frag6_input(mp, offp, proto)
/* The 1st fragment has already arrived. */
if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
- offset - sizeof(struct ip6_frag) +
- offsetof(struct ip6_frag, ip6f_offlg));
+ offset - sizeof(struct ip6_frag) +
+ offsetof(struct ip6_frag, ip6f_offlg));
IP6Q_UNLOCK();
return(IPPROTO_DONE);
}
- }
- else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
+ } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
offset - sizeof(struct ip6_frag) +
offsetof(struct ip6_frag, ip6f_offlg));
@@ -363,9 +375,9 @@ frag6_input(mp, offp, proto)
ip6err->ip6_dst = q6->ip6q_dst;
icmp6_error(merr, ICMP6_PARAM_PROB,
- ICMP6_PARAMPROB_HEADER,
- erroff - sizeof(struct ip6_frag) +
- offsetof(struct ip6_frag, ip6f_offlg));
+ ICMP6_PARAMPROB_HEADER,
+ erroff - sizeof(struct ip6_frag) +
+ offsetof(struct ip6_frag, ip6f_offlg));
}
}
}
@@ -458,6 +470,8 @@ frag6_input(mp, offp, proto)
* If the incoming framgent overlaps some existing fragments in
* the reassembly queue, drop it, since it is dangerous to override
* existing fragments from a security point of view.
+ * We don't know which fragment is the bad guy - here we trust
+ * fragment that came in earlier, with no real reason.
*/
if (af6->ip6af_up != (struct ip6asfrag *)q6) {
i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
@@ -495,6 +509,8 @@ insert:
* the most recently active fragmented packet.
*/
frag6_enq(ip6af, af6->ip6af_up);
+ frag6_nfrags++;
+ q6->ip6q_nfrag++;
#if 0 /* xxx */
if (q6 != ip6q.ip6q_next) {
frag6_remque(q6);
@@ -557,6 +573,7 @@ insert:
/* this comes with no copy if the boundary is on cluster */
if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
frag6_remque(q6);
+ frag6_nfrags -= q6->ip6q_nfrag;
free(q6, M_FTABLE);
frag6_nfragpackets--;
goto dropfrag;
@@ -574,6 +591,7 @@ insert:
}
frag6_remque(q6);
+ frag6_nfrags -= q6->ip6q_nfrag;
free(q6, M_FTABLE);
frag6_nfragpackets--;
@@ -645,6 +663,7 @@ frag6_freef(q6)
free(af6, M_FTABLE);
}
frag6_remque(q6);
+ frag6_nfrags -= q6->ip6q_nfrag;
free(q6, M_FTABLE);
frag6_nfragpackets--;
}
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index 40e88198bd0..f19719db76d 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6.h,v 1.26 2002/03/14 01:27:11 millert Exp $ */
+/* $OpenBSD: in6.h,v 1.27 2002/05/28 03:04:38 itojun Exp $ */
/* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */
/*
@@ -531,9 +531,11 @@ struct in6_pktinfo {
#define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */
#define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */
/*#define IPV6CTL_MAPPED_ADDR 23 not for openbsd */
+/* 24 to 40: resrved */
+#define IPV6CTL_MAXFRAGS 41 /* max fragments */
/* New entries should be added here from current IPV6CTL_MAXID value. */
/* to define items, should talk with KAME guys first, for *BSD compatibility */
-#define IPV6CTL_MAXID 24
+#define IPV6CTL_MAXID 42
#define IPV6CTL_NAMES { \
{ 0, 0 }, \
@@ -560,6 +562,23 @@ struct in6_pktinfo {
{ "use_deprecated", CTLTYPE_INT }, \
{ "rr_prune", CTLTYPE_INT }, \
{ 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { 0, 0 }, \
+ { "maxfrags", CTLTYPE_INT }, \
}
#endif /* !_XOPEN_SOURCE */
diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c
index 5d46a0e2aff..8f1fda7ff09 100644
--- a/sys/netinet6/in6_proto.c
+++ b/sys/netinet6/in6_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_proto.c,v 1.32 2002/01/08 02:29:03 itojun Exp $ */
+/* $OpenBSD: in6_proto.c,v 1.33 2002/05/28 03:04:38 itojun Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@@ -251,6 +251,7 @@ int ip6_defhlim = IPV6_DEFHLIM;
int ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS;
int ip6_accept_rtadv = 0; /* "IPV6FORWARDING ? 0 : 1" is dangerous */
int ip6_maxfragpackets = 200;
+int ip6_maxfrags = 200;
int ip6_log_interval = 5;
int ip6_hdrnestlimit = 50; /* appropriate? */
int ip6_dad_count = 1; /* DupAddrDetectionTransmits */
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index b00665a0e44..2062a97d23a 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_input.c,v 1.41 2002/03/14 01:27:12 millert Exp $ */
+/* $OpenBSD: ip6_input.c,v 1.42 2002/05/28 03:04:38 itojun Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@@ -1473,6 +1473,8 @@ ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
&ip6_use_deprecated);
case IPV6CTL_RR_PRUNE:
return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune);
+ case IPV6CTL_MAXFRAGS:
+ return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_maxfrags);
default:
return EOPNOTSUPP;
}
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index a762113b178..4c07d7c694f 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_var.h,v 1.14 2002/03/14 01:27:12 millert Exp $ */
+/* $OpenBSD: ip6_var.h,v 1.15 2002/05/28 03:04:38 itojun Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@@ -89,6 +89,7 @@ struct ip6q {
#ifdef notyet
u_char *ip6q_nxtp;
#endif
+ int ip6q_nfrag; /* # of fragments */
};
struct ip6asfrag {
@@ -216,6 +217,7 @@ extern int ip6_rr_prune; /* router renumbering prefix
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 */
+extern int ip6_maxfrags; /* Maximum fragments in reassembly queue */
extern int ip6_sourcecheck; /* Verify source interface */
extern int ip6_sourcecheck_interval; /* Interval between log messages */
extern int ip6_accept_rtadv; /* Acts as a host not a router */