From befb0ff113682be7457ade6d3300be70bc2516f4 Mon Sep 17 00:00:00 2001 From: silby Date: Sat, 22 Feb 2003 06:41:47 +0000 Subject: Add the ability to limit the number of IP fragments allowed per packet, and enable it by default, with a limit of 16. At the same time, tweak maxfragpackets downward so that in the worst possible case, IP reassembly can use only 1/2 of all mbuf clusters. MFC after: 3 days Reviewed by: hsu Liked by: bmah --- sys/netinet/ip_input.c | 32 ++++++++++++++++++++++++++++---- sys/netinet/ip_var.h | 1 + 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 3e1f8a5..04aa1c3 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -125,6 +125,11 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragpackets, CTLFLAG_RW, &maxnipq, 0, "Maximum number of IPv4 fragment reassembly queue entries"); +static int maxfragsperpacket; +SYSCTL_INT(_net_inet_ip, OID_AUTO, maxfragsperpacket, CTLFLAG_RW, + &maxfragsperpacket, 0, + "Maximum number of IPv4 fragments allowed per packet"); + static int ip_sendsourcequench = 0; SYSCTL_INT(_net_inet_ip, OID_AUTO, sendsourcequench, CTLFLAG_RW, &ip_sendsourcequench, 0, @@ -256,7 +261,8 @@ ip_init() for (i = 0; i < IPREASS_NHASH; i++) TAILQ_INIT(&ipq[i]); - maxnipq = nmbclusters / 4; + maxnipq = nmbclusters / 32; + maxfragsperpacket = 16; #ifndef RANDOM_IP_ID ip_id = time_second & 0xffff; @@ -994,6 +1000,7 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp, #endif TAILQ_INSERT_HEAD(head, fp, ipq_list); nipq++; + fp->ipq_nfrags = 1; fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ip->ip_p; fp->ipq_id = ip->ip_id; @@ -1007,6 +1014,7 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp, #endif goto inserted; } else { + fp->ipq_nfrags++; #ifdef MAC mac_update_ipq(m, fp); #endif @@ -1064,6 +1072,7 @@ ip_reass(struct mbuf *m, struct ipqhead *head, struct ipq *fp, } nq = q->m_nextpkt; m->m_nextpkt = nq; + fp->ipq_nfrags--; m_freem(q); } @@ -1083,17 +1092,30 @@ inserted: #endif /* - * Check for complete reassembly. + * Check for complete reassembly and perform frag per packet + * limiting. + * + * Frag limiting is performed here so that the nth frag has + * a chance to complete the packet before we drop the packet. + * As a result, n+1 frags are actually allowed per packet, but + * only n will ever be stored. (n = maxfragsperpacket.) + * */ next = 0; for (p = NULL, q = fp->ipq_frags; q; p = q, q = q->m_nextpkt) { - if (GETIP(q)->ip_off != next) + if (GETIP(q)->ip_off != next) { + if (fp->ipq_nfrags > maxfragsperpacket) + ip_freef(head, fp); return (0); + } next += GETIP(q)->ip_len; } /* Make sure the last packet didn't have the IP_MF flag */ - if (p->m_flags & M_FRAG) + if (p->m_flags & M_FRAG) { + if (fp->ipq_nfrags > maxfragsperpacket) + ip_freef(head, fp); return (0); + } /* * Reassembly is complete. Make sure the packet is a sane size. @@ -1160,6 +1182,8 @@ dropfrag: *divert_rule = 0; #endif ipstat.ips_fragdropped++; + if (fp != 0) + fp->ipq_nfrags--; m_freem(m); return (0); diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index c03c446..c8df2e6 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -68,6 +68,7 @@ struct ipq { u_short ipq_id; /* sequence id for reassembly */ struct mbuf *ipq_frags; /* to ip headers of fragments */ struct in_addr ipq_src,ipq_dst; + u_char ipq_nfrags; /* # frags in this packet */ u_int32_t ipq_div_info; /* ipfw divert port & flags */ u_int16_t ipq_div_cookie; /* ipfw divert cookie */ struct label ipq_label; /* MAC label */ -- cgit v1.1