From: Sepherosa Ziehau Date: Mon, 17 Aug 2015 12:38:59 +0000 (+0800) Subject: inet6: Limit the # of fragments in addition to the # of fragmented packets X-Git-Url: https://gitweb.dragonflybsd.org/~nant/dragonfly.git/commitdiff_plain/f2d599d1da1550eed77650ad0b57363cb9f63e48 inet6: Limit the # of fragments in addition to the # of fragmented packets Obtained-from: KAME via FreeBSD --- diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index 0c158b3da2..8a070c2452 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -70,6 +70,7 @@ static void frag6_freef (struct ip6q *); /* XXX we eventually need splreass6, or some real semaphore */ int frag6_doing_reass; u_int frag6_nfragpackets; +u_int frag6_nfrags; struct ip6q ip6q; /* ip6 reassemble queue */ /* FreeBSD tweak */ @@ -84,6 +85,7 @@ frag6_init(void) struct timeval tv; ip6_maxfragpackets = nmbclusters / 4; + ip6_maxfrags = nmbclusters / 4; /* * in many cases, random() here does NOT return random number @@ -208,6 +210,16 @@ frag6_input(struct mbuf **mp, int *offp, int proto) frag6_doing_reass = 1; + /* + * 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) && @@ -249,6 +261,7 @@ frag6_input(struct mbuf **mp, int *offp, int 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; } /* @@ -377,6 +390,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); @@ -439,6 +454,7 @@ insert: /* this comes with no copy if the boundary is on cluster */ if ((t = m_split(m, offset, M_NOWAIT)) == NULL) { frag6_remque(q6); + frag6_nfrags -= q6->ip6q_nfrag; kfree(q6, M_FTABLE); frag6_nfragpackets--; goto dropfrag; @@ -456,6 +472,7 @@ insert: } frag6_remque(q6); + frag6_nfrags -= q6->ip6q_nfrag; kfree(q6, M_FTABLE); frag6_nfragpackets--; @@ -527,6 +544,7 @@ frag6_freef(struct ip6q *q6) kfree(af6, M_FTABLE); } frag6_remque(q6); + frag6_nfrags -= q6->ip6q_nfrag; kfree(q6, M_FTABLE); frag6_nfragpackets--; } diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 67c51e3a70..b4874db089 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -588,6 +588,8 @@ struct ip6_mtuinfo { #define IPV6CTL_ADDRCTLPOLICY 38 /* get/set address selection policy */ #define IPV6CTL_MINHLIM 39 /* minimum Hop-Limit */ +#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 */ diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 608e869d24..9846922faf 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -422,6 +422,7 @@ int ip6_minhlim = IPV6_MINHLIM; int ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS; int ip6_accept_rtadv = 0; /* "IPV6FORWARDING ? 0 : 1" is dangerous */ int ip6_maxfragpackets; /* initialized in frag6.c:frag6_init() */ +int ip6_maxfrags; /* initialized in frag6.c:frag6_init() */ int ip6_log_interval = 5; int ip6_hdrnestlimit = 50; /* appropriate? */ int ip6_dad_count = 1; /* DupAddrDetectionTransmits */ @@ -569,6 +570,8 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL, auto_linklocal, CTLFLAG_RW, &ip6_auto_linklocal, 0, "Enable auto-assigning a link-local address"); SYSCTL_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD, &rip6stat, rip6stat, "Raw stats"); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGS, maxfrags, CTLFLAG_RW, + &ip6_maxfrags, 0, "Maximum fragments in reassembly queues"); /* net.inet6.icmp6 */ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT, rediraccept, CTLFLAG_RW, diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index f30f0ca666..0abb6b6f2a 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -100,6 +100,7 @@ struct ip6q { #ifdef notyet u_char *ip6q_nxtp; #endif + int ip6q_nfrag; /* # of fragments */ }; struct ip6asfrag { @@ -309,6 +310,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 */