inet6: Limit the # of fragments in addition to the # of fragmented packets
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Mon, 17 Aug 2015 12:38:59 +0000 (20:38 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Tue, 18 Aug 2015 01:24:36 +0000 (09:24 +0800)
Obtained-from: KAME via FreeBSD

sys/netinet6/frag6.c
sys/netinet6/in6.h
sys/netinet6/in6_proto.c
sys/netinet6/ip6_var.h

index 0c158b3..8a070c2 100644 (file)
@@ -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--;
 }
index 67c51e3..b4874db 100644 (file)
@@ -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 */
 
index 608e869..9846922 100644 (file)
@@ -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,
index f30f0ca..0abb6b6 100644 (file)
@@ -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 */