Page MenuHomeFreeBSD

D10388.diff
No OneTemporary

D10388.diff

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

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)

Event Timeline