mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-11 14:10:34 +00:00
Prevent denial of service using bogus fragmented IPv4 packets.
A attacker sending a lot of bogus fragmented packets to the target (with different IPv4 identification field - ip_id), may be able to put the target machine into mbuf starvation state. By setting a upper limit on the number of reassembly queues we prevent this situation. This upper limit is controlled by the new sysctl net.inet.ip.maxfragpackets which defaults to NMBCLUSTERS/4 If you want old behaviour (no upper limit) set this sysctl to a negative value. If you don't want to accept any fragments (not recommended) set the sysctl to 0 (zero) Obtained from: NetBSD (partially) MFC after: 1 week
This commit is contained in:
parent
e916d96e64
commit
2b1a209a17
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=77545
@ -124,6 +124,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 = NMBCLUSTERS/4;
|
||||
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
|
||||
@ -862,6 +868,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 *);
|
||||
@ -1010,6 +1025,7 @@ ip_reass(m, head, fp)
|
||||
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 */
|
||||
@ -1051,6 +1067,7 @@ ip_freef(fhp, fp)
|
||||
}
|
||||
TAILQ_REMOVE(fhp, fp, ipq_list);
|
||||
(void) m_free(dtom(fp));
|
||||
ip_nfragpackets--;
|
||||
nipq--;
|
||||
}
|
||||
|
||||
@ -1078,6 +1095,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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user