Suleiman Souhlal napsal(a):
Hi,

On Wed, 2004-12-08 at 09:51, Michal Mertl wrote:

What do you think?


Wouldn't it be better to move all the calls to badport_bandlim() to
inside icmp_error()?

It makes sense, yes. Unfortunately it isn't possible in most cases - echo/tstamp call icmp_reflect instead of icmp_errror from inside icmp_input. TCP RSTs aren't in fact ICMP packets. The only case, where it's easily doable is in udp_input for ICMP_PORT_UNREACHABLES.


I changed my patch quite a bit after Andre's suggestions. I'm sending you the new version.

--
Michal Mertl
Index: icmp_var.h
===================================================================
RCS file: /home/fcvs/cvs/src/sys/netinet/icmp_var.h,v
retrieving revision 1.24
diff -u -r1.24 icmp_var.h
--- icmp_var.h  16 Aug 2004 18:32:07 -0000      1.24
+++ icmp_var.h  10 Dec 2004 16:57:49 -0000
@@ -57,32 +57,16 @@
        u_long  icps_noroute;           /* no route back */
 };
 
-/*
- * Names for ICMP sysctl objects
- */
-#define        ICMPCTL_MASKREPL        1       /* allow replies to netmask 
requests */
-#define        ICMPCTL_STATS           2       /* statistics (read-only) */
-#define ICMPCTL_ICMPLIM                3
-#define ICMPCTL_MAXID          4
-
-#define ICMPCTL_NAMES { \
-       { 0, 0 }, \
-       { "maskrepl", CTLTYPE_INT }, \
-       { "stats", CTLTYPE_STRUCT }, \
-       { "icmplim", CTLTYPE_INT }, \
-}
-
 #ifdef _KERNEL
 SYSCTL_DECL(_net_inet_icmp);
 extern struct icmpstat icmpstat;       /* icmp statistics */
 extern int badport_bandlim(int);
 #define BANDLIM_UNLIMITED -1
-#define BANDLIM_ICMP_UNREACH 0
-#define BANDLIM_ICMP_ECHO 1
-#define BANDLIM_ICMP_TSTAMP 2
-#define BANDLIM_RST_CLOSEDPORT 3 /* No connection, and no listeners */
-#define BANDLIM_RST_OPENPORT 4   /* No connection, listener */
-#define BANDLIM_MAX 4
+#define BANDLIM_ICMP_UNREACH_PORT 0
+#define BANDLIM_ICMP_UNREACH 1
+#define BANDLIM_ICMP_ECHO 2
+#define BANDLIM_RST_CLOSEDPORT 3       /* No connection, and no listeners */
+#define BANDLIM_RST_OPENPORT 4         /* No connection, listener */
 #endif
 
 #endif
Index: ip_icmp.c
===================================================================
RCS file: /home/fcvs/cvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.97
diff -u -r1.97 ip_icmp.c
--- ip_icmp.c   15 Sep 2004 20:13:26 -0000      1.97
+++ ip_icmp.c   10 Dec 2004 16:59:19 -0000
@@ -79,11 +79,11 @@
  */
 
 struct icmpstat icmpstat;
-SYSCTL_STRUCT(_net_inet_icmp, ICMPCTL_STATS, stats, CTLFLAG_RW,
+SYSCTL_STRUCT(_net_inet_icmp, OID_AUTO, stats, CTLFLAG_RW,
        &icmpstat, icmpstat, "");
 
 static int     icmpmaskrepl = 0;
-SYSCTL_INT(_net_inet_icmp, ICMPCTL_MASKREPL, maskrepl, CTLFLAG_RW,
+SYSCTL_INT(_net_inet_icmp, OID_AUTO, maskrepl, CTLFLAG_RW,
        &icmpmaskrepl, 0, "Reply to ICMP Address Mask Request packets.");
 
 static u_int   icmpmaskfake = 0;
@@ -98,9 +98,28 @@
 SYSCTL_INT(_net_inet_icmp, OID_AUTO, log_redirect, CTLFLAG_RW,
        &log_redirect, 0, "");
 
-static int      icmplim = 200;
-SYSCTL_INT(_net_inet_icmp, ICMPCTL_ICMPLIM, icmplim, CTLFLAG_RW,
-       &icmplim, 0, "");
+SYSCTL_NODE(_net_inet_icmp, OID_AUTO, limit, CTLFLAG_RW, 0,
+    "ICMP replies limits");
+
+static int      icmplim_unreach = 200;
+SYSCTL_INT(_net_inet_icmp_limit, OID_AUTO, unreach,
+       CTLFLAG_RW, &icmplim_unreach, 0,
+       "Maximum rate of ICMP unreachables");
+
+static int      icmplim_echo = 200;
+SYSCTL_INT(_net_inet_icmp_limit, OID_AUTO, echo,
+       CTLFLAG_RW, &icmplim_echo, 0,
+       "Maximum rate of ICMP echo/tstamp replies");
+
+static int      icmplim_tcp = 200;
+SYSCTL_INT(_net_inet_icmp_limit, OID_AUTO, tcp,
+       CTLFLAG_RW, &icmplim_tcp, 0,
+       "Maximum rate of TCP RSTs");
+
+static int      icmplim_udp = 200;
+SYSCTL_INT(_net_inet_icmp_limit, OID_AUTO, udp,
+       CTLFLAG_RW, &icmplim_udp, 0,
+       "Maximum rate of ICMP port unreachables");
 
 static int     icmplim_output = 1;
 SYSCTL_INT(_net_inet_icmp, OID_AUTO, icmplim_output, CTLFLAG_RW,
@@ -171,6 +190,23 @@
        /* Don't send error in response to a multicast or broadcast packet */
        if (n->m_flags & (M_BCAST|M_MCAST))
                goto freeit;
+
+       if (type == ICMP_UNREACH && code != ICMP_UNREACH_NEEDFRAG)
+       /*
+        * Limit sending of ICMP unreachable messages except of
+        * ICMP_UNREACH_NEEDFRAG.
+        * This includes packets generated by firewall packages when
+        * dropping a packet.
+        * E.g.: "ipfw add 110 unreach filter-prohib tcp from any to any 25"
+        * It also limits sending of ICMP host unreachable messages
+        * generated if we are acting as a router and someone is doing a sweep
+        * scan (eg. nmap and/or numerous windows worms) for destinations
+        * we are the gateway for but are not reachable (ie. a /24 on a
+        * interface and only a couple of hosts on the ethernet) we would
+        * generate a storm of ICMP host unreachable messages.
+        */
+               if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0)
+                       goto freeit;
        /*
         * First, formulate icmp message
         */
@@ -489,7 +525,7 @@
                icp->icmp_type = ICMP_TSTAMPREPLY;
                icp->icmp_rtime = iptime();
                icp->icmp_ttime = icp->icmp_rtime;      /* bogus, do later! */
-               if (badport_bandlim(BANDLIM_ICMP_TSTAMP) < 0)
+               if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0)
                        goto freeit;
                else
                        goto reflect;
@@ -887,37 +923,55 @@
 int
 badport_bandlim(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] = {
+       } rates[] = {
+               { "icmp port unreach response" },
                { "icmp unreach response" },
-               { "icmp ping response" },
-               { "icmp tstamp response" },
+               { "icmp echo/tstamp response" },
                { "closed port RST response" },
                { "open port RST response" }
        };
-
-       /*
-        * Return ok status if feature disabled or argument out of range.
-        */
-       if (icmplim > 0 && (u_int) which < N(rates)) {
-               struct rate *r = &rates[which];
-               int opps = r->curpps;
-
-               if (!ppsratecheck(&r->lasttime, &r->curpps, 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 (icmplim_output && opps > icmplim)
-                       printf("Limiting %s from %d to %d packets/sec\n",
-                               r->type, opps, icmplim);
+       struct rate     *r;
+       int              opps;
+       int              limit;
+
+       /* Return ok status if argument is out of range. */
+       switch (which) {
+       case BANDLIM_ICMP_UNREACH_PORT:
+               limit = icmplim_udp;
+               break;
+       case BANDLIM_ICMP_UNREACH:
+               limit = icmplim_unreach;
+               break;
+       case BANDLIM_ICMP_ECHO:
+               limit = icmplim_echo;
+               break;
+       case BANDLIM_RST_CLOSEDPORT:
+       case BANDLIM_RST_OPENPORT:
+               limit = icmplim_tcp;
+               break;
+       default:
+               return (0);
        }
+       /* Return ok status if limit is <=0 (unlimited) */
+       if (limit <= 0)
+               return (0);
+
+       /* Do the actual rate check */
+       r = &rates[which];
+       opps = r->curpps;
+       if (!ppsratecheck(&r->lasttime, &r->curpps, limit))
+               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 (icmplim_output && opps > limit)
+               printf("Limiting %s from %d to %d packets/sec\n",
+                       r->type, opps, limit);
        return 0;                       /* okay to send packet */
-#undef N
 }
Index: udp_usrreq.c
===================================================================
RCS file: /home/fcvs/cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.170
diff -u -r1.170 udp_usrreq.c
--- udp_usrreq.c        8 Nov 2004 14:44:53 -0000       1.170
+++ udp_usrreq.c        10 Dec 2004 16:14:10 -0000
@@ -375,7 +375,7 @@
                }
                if (blackhole)
                        goto badheadlocked;
-               if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0)
+               if (badport_bandlim(BANDLIM_ICMP_UNREACH_PORT) < 0)
                        goto badheadlocked;
                *ip = save_ip;
                ip->ip_len += iphlen;
_______________________________________________
[EMAIL PROTECTED] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to