Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167616493
D10388.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D10388.diff
View Options
Index: UPDATING
===================================================================
--- UPDATING
+++ UPDATING
@@ -51,6 +51,18 @@
****************************** SPECIAL WARNING: ******************************
+20170413:
+ A number of rate limits were previously controlled via the
+ net.inet.icmp.icmplim and net.inet.icmp.icmplim_output sysctls.
+ This functionality has now been split into separate sysctls
+ for the impacted protocols:
+ - net.inet.tcp.rstlim and net.inet.tcp.rstlim_output
+ - net.inet.sctp.badport_lim and net.inet.sctp.badport_lim_output
+
+ Additionally, there is now a rate limit on ICMP6 informational
+ replies, which is controlled through the net.inet6.icmp6.infoppslimit
+ sysctl.
+
20170407:
arm64 builds now use the base system LLD 4.0.0 linker by default,
instead of requiring that the aarch64-binutils port or package be
Index: share/man/man4/tcp.4
===================================================================
--- share/man/man4/tcp.4
+++ share/man/man4/tcp.4
@@ -34,7 +34,7 @@
.\" From: @(#)tcp.4 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd February 6, 2017
+.Dd April 13, 2017
.Dt TCP 4
.Os
.Sh NAME
@@ -592,6 +592,19 @@
.It Va insecure_syn
Use criteria defined in RFC793 instead of RFC5961 for accepting SYN segments.
Default is false.
+.It Va rstlim
+The maximum number of RSTs per second that the TCP stack will send per second
+for invalid segments.
+The same limit is used for segments destined to closed ports and for invalid
+segments destined for open ports.
+However, the limit is tracked separately for those two classes of segments, and
+the system will send up to
+.Va rstlim
+RSTs per second for each class.
+.It Va rstlim_output
+If non-zero, the system will create a log message when the
+.Va rstlim
+limit is exceeded.
.El
.Sh ERRORS
A socket operation may fail with one of the following errors returned:
Index: share/man/man9/counter.9
===================================================================
--- share/man/man9/counter.9
+++ share/man/man9/counter.9
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 22, 2017
+.Dd April 13, 2017
.Dt COUNTER 9
.Os
.Sh NAME
@@ -52,7 +52,11 @@
.Ft void
.Fn counter_u64_zero "counter_u64_t c"
.Ft int64_t
-.Fn counter_ratecheck "struct counter_rate *cr" "int64_t limit"
+.Fn counter_ratecheck "int which"
+.Ft void
+.Fn counter_rate_register "int which" "const char *descr" "int *limitp" "int *logp"
+.Ft void
+.Fn counter_rate_unregister "int which"
.In sys/sysctl.h
.Fn SYSCTL_COUNTER_U64 parent nbr name access ptr descr
.Fn SYSCTL_ADD_COUNTER_U64 ctx parent nbr name access ptr descr
@@ -130,18 +134,71 @@
Clear the counter
.Fa c
and set it to zero.
-.It Fn counter_ratecheck cr limit
+.It Fn counter_ratecheck which
The function is a multiprocessor-friendly version of
.Fn ppsratecheck ,
which uses
.Nm
internally.
+The
+.Fa which
+argument defines the appropriate rate-limiting configuration.
+(See sys/counter.h for valid
+.Fa which
+values.)
Returns non-negative value if the rate is not yet reached during the current
second, and a negative value otherwise.
If the limit was reached on previous second, but was just reset back to zero,
then
.Fn counter_ratecheck
returns number of events since previous reset.
+.It Fn counter_rate_register which descr limitp logp
+The function initializes the rate limit configuration for
+.Fa which .
+The
+.Fa descr
+argument must point to a description for the rate limit.
+The
+.Fa limitp
+argument points to a limit which will be used for this rate limit configuration.
+If
+.Fa limitp
+is NULL or points to a integer which has a non-positive value, then there is no
+rate limit.
+The
+.Fa logp
+argument points to an integer which controls whether
+.Fn counter_ratecheck
+should generate log messages when the limit is exceeded.
+If
+.Fa logp
+is NULL or points to an integer with a zero value, then log messages will be
+suppressed.
+.Fn counter_ratecheck
+checks the value of the
+.Fa limitp
+and
+.Fa logp
+variables on each invocation.
+Therefore, changes to the value of the variables to which
+.Fa limitp
+and
+.Fa logp
+point will take effect immediately.
+.It Fn counter_rate_unregister which
+The function removes the rate-limiting configuration for
+.Fa which .
+There should be one call to
+.Fn counter_rate_unregister
+for each call to
+.Fn counter_rate_register .
+The code should not call
+.Fn counter_rate_unregister
+at the same time other threads may be calling
+.Fn counter_ratecheck
+for the same
+.Fa which
+value.
.It Fn SYSCTL_COUNTER_U64 parent nbr name access ptr descr
Declare a static
.Xr sysctl 9
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -4084,7 +4084,7 @@
netinet/ip_ecn.c optional inet | inet6
netinet/ip_encap.c optional inet | inet6
netinet/ip_fastfwd.c optional inet
-netinet/ip_icmp.c optional inet | inet6
+netinet/ip_icmp.c optional inet
netinet/ip_input.c optional inet
netinet/ip_mroute.c optional mrouting inet
netinet/ip_options.c optional inet
Index: sys/kern/subr_counter.c
===================================================================
--- sys/kern/subr_counter.c
+++ sys/kern/subr_counter.c
@@ -36,6 +36,8 @@
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <net/vnet.h>
#include <vm/uma.h>
#define IN_SUBR_COUNTER_C
@@ -120,6 +122,9 @@
return (0);
}
+static VNET_DEFINE(struct counter_rate, counter_rates[BANDLIM_MAX]);
+#define V_counter_rates VNET(counter_rates)
+
/*
* MP-friendly version of ppsratecheck().
*
@@ -130,11 +135,26 @@
* is number of events since last reset.
*/
int64_t
-counter_ratecheck(struct counter_rate *cr, int64_t limit)
+counter_ratecheck(int which)
{
+ struct counter_rate *cr;
+ int64_t limit;
int64_t val;
int now;
+ if (which == BANDLIM_UNLIMITED)
+ return (0);
+
+ KASSERT(which >= 0 && which < BANDLIM_MAX,
+ ("%s: which value %d is out of range (0-%d)", __func__, which,
+ BANDLIM_MAX));
+
+ cr = &V_counter_rates[which];
+
+ /* Missing, negative, or 0 limit implies there is no limit. */
+ if (cr->cr_limitp == NULL || (limit = *cr->cr_limitp) <= 0)
+ return (0);
+
val = cr->cr_over;
now = ticks;
@@ -164,7 +184,7 @@
* be running counter_u64_zero(), so it is not safe
* to do an update, we skip it.
*/
- return (val);
+ goto done;
}
counter_u64_add(cr->cr_rate, 1);
@@ -173,5 +193,79 @@
if (counter_u64_fetch(cr->cr_rate) > limit)
val = cr->cr_over = -1;
+done:
+ if (val > 0 && cr->cr_logp != NULL && *cr->cr_logp)
+ log(LOG_NOTICE, "Limited %s from %jd to %jd packets/sec\n",
+ cr->cr_descr, (intmax_t)val, (intmax_t)limit);
return (val);
}
+
+/*
+ * Register a counter rate limit.
+ *
+ * Arguments:
+ * which: One of the BANDLIM_* values (required).
+ * descr: A pointer to a description for the rate (required).
+ * limitp: A pointer to the limit value (no limit if NULL.
+ * logp: A pointer to an integer to control logging (if logging if NULL;
+ * otherwise, log is *logp is non-0).
+ */
+void
+counter_rate_register(int which, const char *descr, int *limitp, int *logp)
+{
+ struct counter_rate *cr;
+
+ KASSERT(which >= 0 && which < BANDLIM_MAX,
+ ("%s: which value %d is out of range (0-%d)", __func__, which,
+ BANDLIM_MAX));
+ KASSERT(descr != NULL, ("%s: NULL description", __func__));
+ KASSERT(V_counter_rates[which].cr_descr == NULL,
+ ("%s: attempt to reinitialize rate %d", __func__, which));
+
+ cr = &V_counter_rates[which];
+ cr->cr_rate = counter_u64_alloc(M_WAITOK);
+ cr->cr_ticks = ticks;
+ cr->cr_limitp = limitp;
+ cr->cr_descr = descr;
+ cr->cr_logp = logp;
+}
+
+/*
+ * Unregister a counter rate limit.
+ *
+ * This must be called one time for each counter_rate_register() call.
+ */
+void
+counter_rate_unregister(int which)
+{
+ struct counter_rate *cr;
+
+ KASSERT(which >= 0 && which < BANDLIM_MAX,
+ ("%s: which value %d is out of range (0-%d)", __func__, which,
+ BANDLIM_MAX));
+ KASSERT(V_counter_rates[which].cr_descr != NULL,
+ ("%s: attempt to unregister unintialized rate %d", __func__,
+ which));
+
+ cr = &V_counter_rates[which];
+ counter_u64_free(cr->cr_rate);
+ cr->cr_limitp = NULL;
+ cr->cr_descr = NULL;
+ cr->cr_logp = NULL;
+}
+
+#if defined(VIMAGE) && defined(INVARIANTS)
+static void
+counter_rate_uninit(void)
+{
+ int i;
+
+ for (i = 0; i < BANDLIM_MAX; i++)
+ KASSERT(V_counter_rates[i].cr_descr == NULL,
+ ("%s: Attempt to deinitialize VNET without deregistering "
+ "rate %d", __func__, i));
+}
+
+VNET_SYSUNINIT(counter_ratelimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
+ counter_rate_uninit, NULL);
+#endif
Index: sys/netinet/icmp6.h
===================================================================
--- sys/netinet/icmp6.h
+++ sys/netinet/icmp6.h
@@ -680,6 +680,9 @@
#define ICMPV6CTL_ND6_MAXQLEN 24
#define ICMPV6CTL_NODEINFO_OLDMCPREFIX 25
#define ICMPV6CTL_MAXID 26
+#define ICMPV6CTL_INFOPPSLIMIT 27
+#define ICMPV6CTL_ERRPPSOUTPUT 28
+#define ICMPV6CTL_INFOPPSOUTPUT 29
#define RTF_PROBEMTU RTF_PROTO1
Index: sys/netinet/icmp_var.h
===================================================================
--- sys/netinet/icmp_var.h
+++ sys/netinet/icmp_var.h
@@ -86,17 +86,6 @@
#ifdef _KERNEL
SYSCTL_DECL(_net_inet_icmp);
-
-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_ICMP6_UNREACH 5
-#define BANDLIM_SCTP_OOTB 6
-#define BANDLIM_MAX 7
#endif
#endif
Index: sys/netinet/ip_icmp.c
===================================================================
--- sys/netinet/ip_icmp.c
+++ sys/netinet/ip_icmp.c
@@ -540,11 +540,10 @@
ICMPSTAT_INC(icps_bmcastecho);
break;
}
- icp->icmp_type = ICMP_ECHOREPLY;
- if (badport_bandlim(BANDLIM_ICMP_ECHO) < 0)
+ if (counter_ratecheck(BANDLIM_ICMP_ECHO) < 0)
goto freeit;
- else
- goto reflect;
+ icp->icmp_type = ICMP_ECHOREPLY;
+ goto reflect;
case ICMP_TSTAMP:
if (V_icmptstamprepl == 0)
@@ -558,13 +557,12 @@
ICMPSTAT_INC(icps_badlen);
break;
}
+ if (counter_ratecheck(BANDLIM_ICMP_TSTAMP) < 0)
+ goto freeit;
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)
- goto freeit;
- else
- goto reflect;
+ goto reflect;
case ICMP_MASKREQ:
if (V_icmpmaskrepl == 0)
@@ -960,47 +958,16 @@
#endif /* INET */
-/*
- * badport_bandlim() - 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.
- */
-struct icmp_rate {
- const char *descr;
- struct counter_rate cr;
-};
-static VNET_DEFINE(struct icmp_rate, icmp_rates[BANDLIM_MAX]) = {
- { "icmp unreach response" },
- { "icmp ping response" },
- { "icmp tstamp response" },
- { "closed port RST response" },
- { "open port RST response" },
- { "icmp6 unreach response" },
- { "sctp ootb response" }
-};
-#define V_icmp_rates VNET(icmp_rates)
-
static void
icmp_bandlimit_init(void)
{
- for (int i = 0; i < BANDLIM_MAX; i++) {
- V_icmp_rates[i].cr.cr_rate = counter_u64_alloc(M_WAITOK);
- V_icmp_rates[i].cr.cr_ticks = ticks;
- }
+ counter_rate_register(BANDLIM_ICMP_UNREACH, "icmp unreach response",
+ &V_icmplim, &V_icmplim_output);
+ counter_rate_register(BANDLIM_ICMP_ECHO, "icmp ping response",
+ &V_icmplim, &V_icmplim_output);
+ counter_rate_register(BANDLIM_ICMP_TSTAMP, "icmp tstamp response",
+ &V_icmplim, &V_icmplim_output);
}
VNET_SYSINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY,
icmp_bandlimit_init, NULL);
@@ -1009,28 +976,10 @@
icmp_bandlimit_uninit(void)
{
- for (int i = 0; i < BANDLIM_MAX; i++)
- counter_u64_free(V_icmp_rates[i].cr.cr_rate);
+ counter_rate_unregister(BANDLIM_ICMP_UNREACH);
+ counter_rate_unregister(BANDLIM_ICMP_ECHO);
+ counter_rate_unregister(BANDLIM_ICMP_TSTAMP);
}
VNET_SYSUNINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
icmp_bandlimit_uninit, NULL);
-int
-badport_bandlim(int which)
-{
- int64_t pps;
-
- if (V_icmplim == 0 || which == BANDLIM_UNLIMITED)
- return (0);
-
- KASSERT(which >= 0 && which < BANDLIM_MAX,
- ("%s: which %d", __func__, which));
-
- pps = counter_ratecheck(&V_icmp_rates[which].cr, V_icmplim);
- if (pps == -1)
- return (-1);
- if (pps > 0 && V_icmplim_output)
- log(LOG_NOTICE, "Limiting %s from %jd to %d packets/sec\n",
- V_icmp_rates[which].descr, (intmax_t )pps, V_icmplim);
- return (0);
-}
Index: sys/netinet/sctp_input.c
===================================================================
--- sys/netinet/sctp_input.c
+++ sys/netinet/sctp_input.c
@@ -5762,7 +5762,7 @@
}
if (inp == NULL) {
SCTP_STAT_INCR(sctps_noport);
- if (badport_bandlim(BANDLIM_SCTP_OOTB) < 0) {
+ if (counter_ratecheck(BANDLIM_SCTP_OOTB) < 0) {
goto out;
}
if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
Index: sys/netinet/sctp_os_bsd.h
===================================================================
--- sys/netinet/sctp_os_bsd.h
+++ sys/netinet/sctp_os_bsd.h
@@ -79,7 +79,6 @@
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
-#include <netinet/icmp_var.h>
#ifdef INET6
#include <sys/domain.h>
Index: sys/netinet/sctp_sysctl.h
===================================================================
--- sys/netinet/sctp_sysctl.h
+++ sys/netinet/sctp_sysctl.h
@@ -114,6 +114,8 @@
uint32_t sctp_buffer_splitting;
uint32_t sctp_initial_cwnd;
uint32_t sctp_blackhole;
+ int sctp_badport_lim;
+ int sctp_badport_lim_output;
#if defined(SCTP_DEBUG)
uint32_t sctp_debug_on;
#endif
@@ -536,6 +538,16 @@
#define SCTPCTL_BLACKHOLE_MAX 2
#define SCTPCTL_BLACKHOLE_DEFAULT SCTPCTL_BLACKHOLE_MIN
+#define SCTPCTL_BADPORT_LIM_DESC "Number of responses per second for segments to closed ports"
+#define SCTPCTL_BADPORT_LIM_MIN -1
+#define SCTPCTL_BADPORT_LIM_MAX INT_MAX
+#define SCTPCTL_BADPORT_LIM_DEFAULT 200
+
+#define SCTPCTL_BADPORT_LIM_OUTPUT_DESC "Enable logging of rate limiting for responses to for segments to closed ports"
+#define SCTPCTL_BADPORT_LIM_OUTPUT_MIN INT_MIN
+#define SCTPCTL_BADPORT_LIM_OUTPUT_MAX INT_MAX
+#define SCTPCTL_BADPORT_LIM_OUTPUT_DEFAULT 1
+
#define SCTPCTL_DIAG_INFO_CODE_DESC "Diagnostic information error cause code"
#define SCTPCTL_DIAG_INFO_CODE_MIN 0
#define SCTPCTL_DIAG_INFO_CODE_MAX 65535
Index: sys/netinet/sctp_sysctl.c
===================================================================
--- sys/netinet/sctp_sysctl.c
+++ sys/netinet/sctp_sysctl.c
@@ -117,6 +117,8 @@
SCTP_BASE_SYSCTL(sctp_steady_step) = SCTPCTL_RTTVAR_STEADYS_DEFAULT;
SCTP_BASE_SYSCTL(sctp_use_dccc_ecn) = SCTPCTL_RTTVAR_DCCCECN_DEFAULT;
SCTP_BASE_SYSCTL(sctp_blackhole) = SCTPCTL_BLACKHOLE_DEFAULT;
+ SCTP_BASE_SYSCTL(sctp_badport_lim) = SCTPCTL_BADPORT_LIM_DEFAULT;
+ SCTP_BASE_SYSCTL(sctp_badport_lim_output) = SCTPCTL_BADPORT_LIM_OUTPUT_DEFAULT;
SCTP_BASE_SYSCTL(sctp_diag_info_code) = SCTPCTL_DIAG_INFO_CODE_DEFAULT;
#if defined(SCTP_LOCAL_TRACE_BUF)
memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log));
@@ -851,6 +853,29 @@
CTLFLAG_VNET|CTLTYPE_UINT|CTLFLAG_RW, NULL, 0, \
sctp_sysctl_handle_##mib_name, "UI", prefix##_DESC);
+#define SCTP_INT_SYSCTL(mib_name, var_name, prefix) \
+ static int \
+ sctp_sysctl_handle_##mib_name(SYSCTL_HANDLER_ARGS) \
+ { \
+ int error; \
+ int new; \
+ \
+ new = SCTP_BASE_SYSCTL(var_name); \
+ error = sysctl_handle_int(oidp, &new, 0, req); \
+ if ((error == 0) && (req->newptr != NULL)) { \
+ if ((new < prefix##_MIN) || \
+ (new > prefix##_MAX)) { \
+ error = EINVAL; \
+ } else { \
+ SCTP_BASE_SYSCTL(var_name) = new; \
+ } \
+ } \
+ return (error); \
+ } \
+ SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mib_name, \
+ CTLFLAG_VNET|CTLTYPE_INT|CTLFLAG_RW, NULL, 0, \
+ sctp_sysctl_handle_##mib_name, "I", prefix##_DESC);
+
/*
* sysctl definitions
*/
@@ -931,6 +956,8 @@
SCTP_UINT_SYSCTL(rttvar_steady_step, sctp_steady_step, SCTPCTL_RTTVAR_STEADYS)
SCTP_UINT_SYSCTL(use_dcccecn, sctp_use_dccc_ecn, SCTPCTL_RTTVAR_DCCCECN)
SCTP_UINT_SYSCTL(blackhole, sctp_blackhole, SCTPCTL_BLACKHOLE)
+SCTP_INT_SYSCTL(badport_lim, sctp_badport_lim, SCTPCTL_BADPORT_LIM)
+SCTP_INT_SYSCTL(badport_lim_output, sctp_badport_lim_output, SCTPCTL_BADPORT_LIM_OUTPUT)
SCTP_UINT_SYSCTL(diag_info_code, sctp_diag_info_code, SCTPCTL_DIAG_INFO_CODE)
#ifdef SCTP_DEBUG
SCTP_UINT_SYSCTL(debug, sctp_debug_on, SCTPCTL_DEBUG)
Index: sys/netinet/sctp_usrreq.c
===================================================================
--- sys/netinet/sctp_usrreq.c
+++ sys/netinet/sctp_usrreq.c
@@ -81,6 +81,9 @@
SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
SCTP_BASE_VAR(first_time) = 0;
SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
+ counter_rate_register(BANDLIM_SCTP_OOTB, "sctp ootb response",
+ &SCTP_BASE_SYSCTL(sctp_badport_lim),
+ &SCTP_BASE_SYSCTL(sctp_badport_lim_output));
sctp_pcb_init();
#if defined(SCTP_PACKET_LOGGING)
SCTP_BASE_VAR(packet_log_writers) = 0;
@@ -94,6 +97,7 @@
sctp_finish(void *unused __unused)
{
sctp_pcb_finish();
+ counter_rate_unregister(BANDLIM_SCTP_OOTB);
}
VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL);
Index: sys/netinet/tcp_input.c
===================================================================
--- sys/netinet/tcp_input.c
+++ sys/netinet/tcp_input.c
@@ -88,8 +88,6 @@
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#include <netinet/ip_icmp.h> /* required for icmp_var.h */
-#include <netinet/icmp_var.h> /* for ICMP_BANDLIM */
#include <netinet/ip_var.h>
#include <netinet/ip_options.h>
#include <netinet/ip6.h>
@@ -3324,7 +3322,7 @@
#endif
/* Perform bandwidth limiting. */
- if (badport_bandlim(rstreason) < 0)
+ if (counter_ratecheck(rstreason) < 0)
goto drop;
/* tcp_respond consumes the mbuf chain. */
Index: sys/netinet/tcp_subr.c
===================================================================
--- sys/netinet/tcp_subr.c
+++ sys/netinet/tcp_subr.c
@@ -232,6 +232,18 @@
VNET_DEFINE(struct hhook_head *, tcp_hhh[HHOOK_TCP_LAST+1]);
#endif
+static VNET_DEFINE(int, tcprstlim) = 200;
+#define V_tcprstlim VNET(tcprstlim)
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, rstlim, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(tcprstlim), 0,
+ "Number of RSTs per second for invalid segments to open and closed ports");
+
+static VNET_DEFINE(int, tcprstlim_output) = 1;
+#define V_tcprstlim_output VNET(tcprstlim_output)
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, rstlim_output, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(tcprstlim_output), 0,
+ "Enable logging of RST rate limiting");
+
static struct inpcb *tcp_notify(struct inpcb *, int);
static struct inpcb *tcp_mtudisc_notify(struct inpcb *, int);
static void tcp_mtudisc(struct inpcb *, int);
@@ -669,6 +681,11 @@
tcp_fastopen_init();
#endif
+ counter_rate_register(BANDLIM_RST_CLOSEDPORT,
+ "closed port RST response", &V_tcprstlim, &V_tcprstlim_output);
+ counter_rate_register(BANDLIM_RST_OPENPORT,
+ "open port RST response", &V_tcprstlim, &V_tcprstlim_output);
+
/* Skip initialization of globals for non-default instances. */
if (!IS_DEFAULT_VNET(curvnet))
return;
@@ -776,6 +793,9 @@
HHOOK_TYPE_TCP, HHOOK_TCP_EST_OUT, error);
}
#endif
+
+ counter_rate_unregister(BANDLIM_RST_CLOSEDPORT);
+ counter_rate_unregister(BANDLIM_RST_OPENPORT);
}
VNET_SYSUNINIT(tcp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, tcp_destroy, NULL);
#endif
Index: sys/netinet/udp_usrreq.c
===================================================================
--- sys/netinet/udp_usrreq.c
+++ sys/netinet/udp_usrreq.c
@@ -81,7 +81,6 @@
#include <netinet/ip6.h>
#endif
#include <netinet/ip_icmp.h>
-#include <netinet/icmp_var.h>
#include <netinet/ip_var.h>
#include <netinet/ip_options.h>
#ifdef INET6
@@ -690,7 +689,7 @@
}
if (V_udp_blackhole)
goto badunlocked;
- if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0)
+ if (counter_ratecheck(BANDLIM_ICMP_UNREACH) < 0)
goto badunlocked;
*ip = save_ip;
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
Index: sys/netinet6/icmp6.c
===================================================================
--- sys/netinet6/icmp6.c
+++ sys/netinet6/icmp6.c
@@ -122,20 +122,21 @@
VNET_DECLARE(struct inpcbinfo, ripcbinfo);
VNET_DECLARE(struct inpcbhead, ripcb);
VNET_DECLARE(int, icmp6errppslim);
-static VNET_DEFINE(int, icmp6errpps_count) = 0;
-static VNET_DEFINE(struct timeval, icmp6errppslim_last);
+VNET_DECLARE(int, icmp6infoppslim);
+VNET_DECLARE(int, icmp6errppslim_output);
+VNET_DECLARE(int, icmp6infoppslim_output);
VNET_DECLARE(int, icmp6_nodeinfo);
#define V_ripcbinfo VNET(ripcbinfo)
#define V_ripcb VNET(ripcb)
#define V_icmp6errppslim VNET(icmp6errppslim)
-#define V_icmp6errpps_count VNET(icmp6errpps_count)
-#define V_icmp6errppslim_last VNET(icmp6errppslim_last)
+#define V_icmp6infoppslim VNET(icmp6infoppslim)
+#define V_icmp6errppslim_output VNET(icmp6errppslim_output)
+#define V_icmp6infoppslim_output VNET(icmp6infoppslim_output)
#define V_icmp6_nodeinfo VNET(icmp6_nodeinfo)
static void icmp6_errcount(int, int);
static int icmp6_rip6_input(struct mbuf **, int);
-static int icmp6_ratelimit(const struct in6_addr *, const int, const int);
static const char *icmp6_redirect_diag(struct in6_addr *,
struct in6_addr *, struct in6_addr *);
static struct mbuf *ni6_input(struct mbuf *, int);
@@ -350,7 +351,7 @@
oip6 = mtod(m, struct ip6_hdr *); /* adjust pointer */
/* Finally, do rate limitation check. */
- if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
+ if (counter_ratecheck(BANDLIM_ICMP6_ERRORS) < 0) {
ICMP6STAT_INC(icp6s_toofreq);
goto freeit;
}
@@ -554,6 +555,8 @@
icmp6_ifstat_inc(ifp, ifs6_in_echo);
if (code != 0)
goto badcode;
+ if (counter_ratecheck(BANDLIM_ICMP6_INFOREPLIES) < 0)
+ break;
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) == NULL) {
/* Give up remote */
break;
@@ -638,6 +641,8 @@
if (!V_icmp6_nodeinfo)
break;
+ if (counter_ratecheck(BANDLIM_ICMP6_INFOREPLIES) < 0)
+ break;
if (icmp6len == sizeof(struct icmp6_hdr) + 4)
mode = WRU;
@@ -2463,7 +2468,7 @@
goto fail; /* what should we do here? */
/* rate limit */
- if (icmp6_ratelimit(&sip6->ip6_src, ND_REDIRECT, 0))
+ if (counter_ratecheck(BANDLIM_ICMP6_ERRORS) < 0)
goto fail;
/*
@@ -2782,32 +2787,26 @@
return (error);
}
-/*
- * Perform rate limit check.
- * Returns 0 if it is okay to send the icmp6 packet.
- * Returns 1 if the router SHOULD NOT send this icmp6 packet due to rate
- * limitation.
- *
- * XXX per-destination/type check necessary?
- *
- * dst - not used at this moment
- * type - not used at this moment
- * code - not used at this moment
- */
-static int
-icmp6_ratelimit(const struct in6_addr *dst, const int type,
- const int code)
+static void
+icmp6_bandlimit_init(void)
{
- int ret;
- ret = 0; /* okay to send */
+ counter_rate_register(BANDLIM_ICMP6_INFOREPLIES,
+ "icmp6 informational responses", &V_icmp6infoppslim,
+ &V_icmp6errppslim_output);
+ counter_rate_register(BANDLIM_ICMP6_ERRORS,
+ "icmp6 error responses", &V_icmp6errppslim,
+ &V_icmp6errppslim_output);
+}
+VNET_SYSINIT(icmp6_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY,
+ icmp6_bandlimit_init, NULL);
- /* PPS limit */
- if (!ppsratecheck(&V_icmp6errppslim_last, &V_icmp6errpps_count,
- V_icmp6errppslim)) {
- /* The packet is subject to rate limit */
- ret++;
- }
+static void
+icmp6_bandlimit_uninit(void)
+{
- return ret;
+ counter_rate_unregister(BANDLIM_ICMP6_INFOREPLIES);
+ counter_rate_unregister(BANDLIM_ICMP6_ERRORS);
}
+VNET_SYSUNINIT(icmp6_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
+ icmp6_bandlimit_uninit, NULL);
Index: sys/netinet6/in6_proto.c
===================================================================
--- sys/netinet6/in6_proto.c
+++ sys/netinet6/in6_proto.c
@@ -419,6 +419,9 @@
VNET_DEFINE(int, icmp6_rediraccept) = 1;/* accept and process redirects */
VNET_DEFINE(int, icmp6_redirtimeout) = 10 * 60; /* 10 minutes */
VNET_DEFINE(int, icmp6errppslim) = 100; /* 100pps */
+VNET_DEFINE(int, icmp6infoppslim) = 100; /* 100pps */
+VNET_DEFINE(int, icmp6errppslim_output) = 1;
+VNET_DEFINE(int, icmp6infoppslim_output) = 1;
/* control how to respond to NI queries */
VNET_DEFINE(int, icmp6_nodeinfo) =
(ICMP6_NODEINFO_FQDNOK|ICMP6_NODEINFO_NODEADDROK);
@@ -607,6 +610,15 @@
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, errppslimit,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6errppslim), 0,
"Maximum number of ICMPv6 error messages per second");
+SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSOUTPUT, errppslimit_output,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6errppslim_output), 0,
+ "Enable logging of ICMPv6 error message rate limiting");
+SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_INFOPPSLIMIT, infoppslimit,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6infoppslim), 0,
+ "Maximum number of ICMPv6 informational response messages per second");
+SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_INFOPPSOUTPUT, infoppslimit_output,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6infoppslim_output), 0,
+ "Enable logging of ICMPv6 informational response rate limiting");
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_MAXNUDHINT, nd6_maxnudhint,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(nd6_maxnudhint), 0,
""); /* XXX unused */
Index: sys/netinet6/udp6_usrreq.c
===================================================================
--- sys/netinet6/udp6_usrreq.c
+++ sys/netinet6/udp6_usrreq.c
@@ -104,9 +104,7 @@
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
#include <netinet/ip6.h>
-#include <netinet/icmp_var.h>
#include <netinet/icmp6.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
@@ -481,8 +479,6 @@
}
if (V_udp_blackhole)
goto badunlocked;
- if (badport_bandlim(BANDLIM_ICMP6_UNREACH) < 0)
- goto badunlocked;
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
return (IPPROTO_DONE);
}
Index: sys/sys/counter.h
===================================================================
--- sys/sys/counter.h
+++ sys/sys/counter.h
@@ -65,12 +65,33 @@
*/
struct counter_rate {
counter_u64_t cr_rate; /* Events since last second */
+ int *cr_limitp; /* Pointer to limit */
+ const char *cr_descr; /* Description */
+ int *cr_logp; /* Whether to log failures */
volatile int cr_lock; /* Lock to clean the struct */
int cr_ticks; /* Ticks on last clean */
int cr_over; /* Over limit since cr_ticks? */
};
-int64_t counter_ratecheck(struct counter_rate *, int64_t);
+int64_t counter_ratecheck(int which);
+void counter_rate_register(int which, const char *descr, int *limitp,
+ int *logp);
+void counter_rate_unregister(int which);
+
+#define BANDLIM_UNLIMITED -1
+enum counter_rate_specs {
+ BANDLIM_ICMP_UNREACH = 0,
+ BANDLIM_ICMP_ECHO,
+ BANDLIM_ICMP_TSTAMP,
+ BANDLIM_RST_CLOSEDPORT,
+ BANDLIM_RST_OPENPORT,
+ BANDLIM_SCTP_OOTB,
+ BANDLIM_ICMP6_INFOREPLIES,
+ BANDLIM_ICMP6_ERRORS,
+
+ /* Add new entries before BANDLIM_MAX. */
+ BANDLIM_MAX
+};
#endif /* _KERNEL */
#endif /* ! __SYS_COUNTER_H__ */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Aug 24, 4:42 AM (21 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37173798
Default Alt Text
D10388.diff (27 KB)
Attached To
Mode
D10388: ICMP6 rate-limit enhancements
Attached
Detach File
Event Timeline
Log In to Comment