diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index f9fab41e4591..328f32669854 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -136,6 +136,7 @@ frag6_init(void) mtx_init(&V_ip6q[i].lock, "ip6qlock", NULL, MTX_DEF); } V_ip6q_hashseed = arc4random(); + V_ip6_maxfragsperpacket = 64; if (!IS_DEFAULT_VNET(curvnet)) return; @@ -533,6 +534,7 @@ frag6_input(struct mbuf **mp, int *offp, int proto) /* * Stick new segment in its place; * check for complete reassembly. + * If not complete, check fragment limit. * Move to front of packet queue, as we are * the most recently active fragmented packet. */ @@ -549,12 +551,20 @@ frag6_input(struct mbuf **mp, int *offp, int proto) for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; af6 = af6->ip6af_down) { if (af6->ip6af_off != next) { + if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { + IP6STAT_INC(ip6s_fragdropped); + frag6_freef(q6, hash); + } IP6Q_UNLOCK(hash); return IPPROTO_DONE; } next += af6->ip6af_frglen; } if (af6->ip6af_up->ip6af_mff) { + if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { + IP6STAT_INC(ip6s_fragdropped); + frag6_freef(q6, hash); + } IP6Q_UNLOCK(hash); return IPPROTO_DONE; } diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index f634dc0f8e43..c771fca175f8 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -642,7 +642,8 @@ struct ip6_mtuinfo { #define IPV6CTL_INTRQMAXLEN 51 /* max length of IPv6 netisr queue */ #define IPV6CTL_INTRDQMAXLEN 52 /* max length of direct IPv6 netisr * queue */ -#define IPV6CTL_MAXID 53 +#define IPV6CTL_MAXFRAGSPERPACKET 53 /* Max fragments per packet */ +#define IPV6CTL_MAXID 54 #endif /* __BSD_VISIBLE */ /* diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 1d1e5233f1eb..967df169ccac 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -386,6 +386,7 @@ VNET_DEFINE(int, ip6_norbit_raif) = 0; VNET_DEFINE(int, ip6_rfc6204w3) = 0; VNET_DEFINE(int, ip6_maxfragpackets); /* initialized in frag6.c:frag6_init() */ int ip6_maxfrags; /* initialized in frag6.c:frag6_init() */ +VNET_DEFINE(int, ip6_maxfragsperpacket); /* initialized in frag6.c:frag6_init() */ VNET_DEFINE(int, ip6_log_interval) = 5; VNET_DEFINE(int, ip6_hdrnestlimit) = 15;/* How many header options will we * process? */ @@ -563,6 +564,9 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGS, maxfrags, "Maximum allowed number of outstanding IPv6 packet fragments. " "A value of 0 means no fragmented packets will be accepted, while a " "a value of -1 means no limit"); +SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGSPERPACKET, maxfragsperpacket, + CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_maxfragsperpacket), 0, + "Maximum allowed number of fragments per packet"); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MCAST_PMTU, mcast_pmtu, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_mcast_pmtu), 0, "Enable path MTU discovery for multicast packets"); diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index b82ecb5efe5f..7b2b656cb90f 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -303,6 +303,7 @@ VNET_DECLARE(int, ip6_maxfragpackets); /* Maximum packets in reassembly * queue */ extern int ip6_maxfrags; /* Maximum fragments in reassembly * queue */ +VNET_DECLARE(int, ip6_maxfragsperpacket); /* Maximum fragments per packet */ VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */ VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */ VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA @@ -317,6 +318,7 @@ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */ #define V_ip6_mrouter VNET(ip6_mrouter) #define V_ip6_sendredirects VNET(ip6_sendredirects) #define V_ip6_maxfragpackets VNET(ip6_maxfragpackets) +#define V_ip6_maxfragsperpacket VNET(ip6_maxfragsperpacket) #define V_ip6_accept_rtadv VNET(ip6_accept_rtadv) #define V_ip6_no_radr VNET(ip6_no_radr) #define V_ip6_norbit_raif VNET(ip6_norbit_raif)