diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f0f4a20e76c..4bf4473fd86 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -125,6 +125,12 @@ SYSCTL_INT(_net_inet_ip, IPCTL_KEEPFAITH, keepfaith, CTLFLAG_RW, &ip_keepfaith, 0, "Enable packet capture for FAITH IPv4->IPv6 translater daemon"); +static int ip_nfragpackets = 0; +static int ip_maxfragpackets = 200; +SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, + &ip_maxfragpackets, 0, + "Maximum number of IPv4 fragment reassembly queue entries"); + /* * XXX - Setting ip_checkinterface mostly implements the receive side of * the Strong ES model described in RFC 1122, but since the routing table @@ -865,6 +871,15 @@ ip_reass(m, head, fp) * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { + /* + * 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 ((ip_maxfragpackets >= 0) && (ip_nfragpackets >= ip_maxfragpackets)) + goto dropfrag; + ip_nfragpackets++; if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); @@ -1013,6 +1028,7 @@ inserted: TAILQ_REMOVE(head, fp, ipq_list); nipq--; (void) m_free(dtom(fp)); + ip_nfragpackets--; m->m_len += (IP_VHL_HL(ip->ip_vhl) << 2); m->m_data -= (IP_VHL_HL(ip->ip_vhl) << 2); /* some debugging cruft by sklower, below, will go away soon */ @@ -1054,6 +1070,7 @@ ip_freef(fhp, fp) } TAILQ_REMOVE(fhp, fp, ipq_list); (void) m_free(dtom(fp)); + ip_nfragpackets--; nipq--; } @@ -1081,6 +1098,20 @@ ip_slowtimo() } } } + /* + * If we are over the maximum number of fragments + * (due to the limit being lowered), drain off + * enough to get down to the new limit. + */ + for (i = 0; i < IPREASS_NHASH; i++) { + if (ip_maxfragpackets >= 0) { + while (ip_nfragpackets > ip_maxfragpackets && + !TAILQ_EMPTY(&ipq[i])) { + ipstat.ips_fragdropped++; + ip_freef(&ipq[i], TAILQ_FIRST(&ipq[i])); + } + } + } ipflow_slowtimo(); splx(s); }