>Number:         173478
>Category:       kern
>Synopsis:       icmp forward bandwithlimit
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Thu Nov 08 17:00:02 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Ingo Flaschberger
>Release:        9.1 Stable
>Organization:
crossip communications gmbh
>Environment:
9.1-PRERELEASE
>Description:
Updated icmp forward bandwithlimit patch.
*) added configurable sysctl option net.inet.icmp.icmplim_forward
   similar to net.inet.icmp.icmplim_output
   DEFAULT: OFF
*) added icmp forward bandwithlimit also to fastforward

>How-To-Repeat:

>Fix:


Patch attached with submission follows:

diff -u -r sys_org/netinet/icmp_var.h /router/usr/src/sys/netinet/icmp_var.h
--- sys_org/netinet/icmp_var.h  2012-11-08 15:15:11.000000000 +0100
+++ /router/usr/src/sys/netinet/icmp_var.h      2012-11-08 15:31:32.000000000 
+0100
@@ -95,6 +95,7 @@
 #define        V_icmpstat      VNET(icmpstat)
 
 extern int badport_bandlim(int);
+extern int badport_bandlim_forward(int);
 #define BANDLIM_UNLIMITED -1
 #define BANDLIM_ICMP_UNREACH 0
 #define BANDLIM_ICMP_ECHO 1
@@ -103,7 +104,12 @@
 #define BANDLIM_RST_OPENPORT 4   /* No connection, listener */
 #define BANDLIM_ICMP6_UNREACH 5
 #define BANDLIM_SCTP_OOTB 6
-#define BANDLIM_MAX 6
+#define BANDLIM_ICMP_FWD_UNREACH 7 /* forwarding: limit unreachable */
+#define BANDLIM_ICMP_FWD_TIMXCEED 8 /* forwarding: limit time-exceeded */
+#define BANDLIM_ICMP_FWD_NEEDFRAG 9 /* forwarding: limit need-frag */
+#define BANDLIM_ICMP_FWD_FILTER 10 /* forwarding: limit admin-prohib */
+#define BANDLIM_MAX 10
+
 #endif
 
 #endif
diff -u -r sys_org/netinet/ip_fastfwd.c /router/usr/src/sys/netinet/ip_fastfwd.c
--- sys_org/netinet/ip_fastfwd.c        2012-11-08 15:15:11.000000000 +0100
+++ /router/usr/src/sys/netinet/ip_fastfwd.c    2012-11-08 15:32:49.000000000 
+0100
@@ -102,6 +103,7 @@
 #include <netinet/ip.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
 #include <netinet/ip_options.h>
 
 #include <machine/in_cksum.h>
@@ -142,7 +152,10 @@
                IPSTAT_INC(ips_cantforward);
                if (rt)
                        RTFREE(rt);
-               icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
+               if (badport_bandlim_forward(BANDLIM_ICMP_FWD_UNREACH) < 0)
+                       m_freem(m);
+               else
+                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
                return NULL;
        }
        return dst;
@@ -299,8 +312,11 @@
                if (ip_doopts == 1)
                        return m;
                else if (ip_doopts == 2) {
-                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB,
-                               0, 0);
+                       if (badport_bandlim_forward(BANDLIM_ICMP_FWD_FILTER) < 
0)
+                               m_freem(m);
+                       else
+                               icmp_error(m, ICMP_UNREACH, 
+                                   ICMP_UNREACH_FILTER_PROHIB, 0, 0);
                        return NULL;    /* mbuf already free'd */
                }
                /* else ignore IP options and continue */
@@ -399,7 +415,11 @@
        if (!V_ipstealth) {
 #endif
        if (ip->ip_ttl <= IPTTLDEC) {
-               icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, 0);
+               if (badport_bandlim_forward(BANDLIM_ICMP_FWD_TIMXCEED) < 0)
+                       m_freem(m);
+               else
+                       icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
+                           0, 0);
                return NULL;    /* mbuf already free'd */
        }
 
@@ -507,6 +538,8 @@
        if ((ro.ro_rt->rt_flags & RTF_REJECT) &&
            (ro.ro_rt->rt_rmx.rmx_expire == 0 ||
            time_uptime < ro.ro_rt->rt_rmx.rmx_expire)) {
+               if (badport_bandlim_forward(BANDLIM_ICMP_FWD_UNREACH) < 0)
+                       goto drop;
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
                goto consumed;
        }
@@ -527,6 +560,8 @@
         * Check if media link state of interface is not down
         */
        if (ifp->if_link_state == LINK_STATE_DOWN) {
+               if (badport_bandlim_forward(BANDLIM_ICMP_FWD_UNREACH) < 0)
+                       goto drop;
                icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
                goto consumed;
        }
@@ -557,6 +592,8 @@
                 */
                if (ip->ip_off & IP_DF) {
                        IPSTAT_INC(ips_cantfrag);
+                       if (badport_bandlim_forward(BANDLIM_ICMP_FWD_NEEDFRAG) 
< 0)
+                               goto drop;
                        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
                                0, mtu);
                        goto consumed;
diff -u -r sys_org/netinet/ip_icmp.c /router/usr/src/sys/netinet/ip_icmp.c
--- sys_org/netinet/ip_icmp.c   2012-11-08 15:15:11.000000000 +0100
+++ /router/usr/src/sys/netinet/ip_icmp.c       2012-11-08 15:35:27.000000000 
+0100
@@ -91,6 +91,12 @@
        &VNET_NAME(icmplim_output), 0,
        "Enable rate limiting of ICMP responses");
 
+static VNET_DEFINE(int, icmplim_forward) = 0;
+#define        V_icmplim_forward               VNET(icmplim_forward)
+SYSCTL_VNET_INT(_net_inet_icmp, OID_AUTO, icmplim_forward, CTLFLAG_RW,
+       &VNET_NAME(icmplim_forward), 0,
+       "Enable rate limiting of forwarded ICMP responses");
+
 #ifdef INET
 VNET_DEFINE(struct icmpstat, icmpstat);
 SYSCTL_VNET_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RW,
@@ -966,7 +972,11 @@
                { "closed port RST response" },
                { "open port RST response" },
                { "icmp6 unreach response" },
-               { "sctp ootb response" }
+               { "sctp ootb response" },
+               { "forwarding: limit unreachable" },
+               { "forwarding: limit time-exceeded" },
+               { "forwarding: limit need-frag" },
+               { "forwarding: limit admin-prohib" }
        };
 
        /*
@@ -990,3 +1000,67 @@
        return 0;                       /* okay to send packet */
 #undef N
 }
+
+/*
+ * badport_bandlim_fw() - check for ICMP bandwidth limit
+ *
+ *     Return 0 if it is ok to send an ICMP error response, -1 if we have
+ *     hit our bandwidth limit and it is not ok.
+ *
+ *     If icmplim is <= 0, the feature is disabled and 0 is returned.
+ *
+ *     For now we separate the TCP and UDP subsystems w/ different 'which'
+ *     values.  We may eventually remove this separation (and simplify the
+ *     code further).
+ *
+ *     Note that the printing of the error message is delayed so we can
+ *     properly print the icmp error rate that the system was trying to do
+ *     (i.e. 22000/100 pps, etc...).  This can cause long delays in printing
+ *     the 'final' error, but it doesn't make sense to solve the printing
+ *     delay with more complex code.
+ */
+
+int
+badport_bandlim_forward(int which)
+{
+
+#define        N(a)    (sizeof (a) / sizeof (a[0]))
+       static struct rate {
+               const char      *type;
+               struct timeval  lasttime;
+               int             curpps;
+       } rates[BANDLIM_MAX+1] = {
+               { "icmp unreach response" },
+               { "icmp ping response" },
+               { "icmp tstamp response" },
+               { "closed port RST response" },
+               { "open port RST response" },
+               { "icmp6 unreach response" },
+               { "sctp ootb response" },
+               { "forwarding: limit unreachable" },
+               { "forwarding: limit time-exceeded" },
+               { "forwarding: limit need-frag" },
+               { "forwarding: limit admin-prohib" }
+       };
+
+       /*
+        * Return ok status if feature disabled or argument out of range.
+        */
+       if (V_icmplim > 0 && (u_int) which < N(rates)) {
+               struct rate *r = &rates[which];
+               int opps = r->curpps;
+
+               if (!ppsratecheck(&r->lasttime, &r->curpps, V_icmplim))
+                       return -1;      /* discard packet */
+               /*
+                * If we've dropped below the threshold after having
+                * rate-limited traffic print the message.  This preserves
+                * the previous behaviour at the expense of added complexity.
+                */
+               if (V_icmplim_forward && opps > V_icmplim)
+                       log(LOG_NOTICE, "Limiting %s from %d to %d 
packets/sec\n",
+                               r->type, opps, V_icmplim);
+       }
+       return 0;                       /* okay to send packet */
+#undef N
+}
diff -u -r sys_org/netinet/ip_input.c /router/usr/src/sys/netinet/ip_input.c
--- sys_org/netinet/ip_input.c  2012-11-08 15:15:11.000000000 +0100
+++ /router/usr/src/sys/netinet/ip_input.c      2012-11-08 15:33:31.000000000 
+0100
@@ -70,6 +70,7 @@
 #include <netinet/ip_var.h>
 #include <netinet/ip_fw.h>
 #include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
 #include <netinet/ip_options.h>
 #include <machine/in_cksum.h>
 #include <netinet/ip_carp.h>
@@ -1370,6 +1371,7 @@
        struct in_addr dest;
        struct route ro;
        int error, type = 0, code = 0, mtu = 0;
+       int icmp_send = 0;
 
        if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
                IPSTAT_INC(ips_cantforward);
@@ -1380,8 +1382,11 @@
        if (!V_ipstealth) {
 #endif
                if (ip->ip_ttl <= IPTTLDEC) {
-                       icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
-                           0, 0);
+                       if (badport_bandlim_forward(BANDLIM_ICMP_FWD_TIMXCEED) 
< 0)
+                               m_freem(m);
+                       else
+                               icmp_error(m, ICMP_TIMXCEED,
+                                   ICMP_TIMXCEED_INTRANS, 0, 0);
                        return;
                }
 #ifdef IPSTEALTH
@@ -1396,7 +1401,10 @@
         * ip_output in case of outgoing IPsec policy.
         */
        if (!srcrt && ia == NULL) {
-               icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
+               if (badport_bandlim_forward(BANDLIM_ICMP_FWD_UNREACH) < 0)
+                       m_freem(m);
+               else
+                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
                return;
        }
 #endif
@@ -1530,11 +1538,13 @@
        default:
                type = ICMP_UNREACH;
                code = ICMP_UNREACH_HOST;
+               icmp_send = badport_bandlim_forward( BANDLIM_ICMP_FWD_UNREACH);
                break;
 
        case EMSGSIZE:
                type = ICMP_UNREACH;
                code = ICMP_UNREACH_NEEDFRAG;
+               icmp_send = badport_bandlim_forward( BANDLIM_ICMP_FWD_NEEDFRAG);
 
 #ifdef IPSEC
                /* 
@@ -1590,7 +1600,10 @@
        }
        if (ia != NULL)
                ifa_free(&ia->ia_ifa);
-       icmp_error(mcopy, type, code, dest.s_addr, mtu);
+       if (icmp_send < 0)
+               m_freem(m);
+       else
+               icmp_error(mcopy, type, code, dest.s_addr, mtu);
 }
 
 void


>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to