diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2002-05-28 03:04:39 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2002-05-28 03:04:39 +0000 |
commit | 53ec36032674958de4f895e731fb895e73b0ba88 (patch) | |
tree | f8c0e79e20f60c53d91f8445a2b26ec099fb843e /sys/netinet6/frag6.c | |
parent | ff76c548fd5e060eba335ca880eee1e8c2d017d1 (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/netinet6/frag6.c')
-rw-r--r-- | sys/netinet6/frag6.c | 53 |
1 files changed, 36 insertions, 17 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--; } |