Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107068776
D44482.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D44482.diff
View Options
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -143,18 +143,6 @@
VNET_DECLARE(struct inpcbinfo, ripcbinfo);
#define V_ripcbinfo VNET(ripcbinfo)
-VNET_DEFINE_STATIC(int, icmp6errppslim) = 100;
-#define V_icmp6errppslim VNET(icmp6errppslim)
-SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, errppslimit,
- CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6errppslim), 0,
- "Maximum number of ICMPv6 error messages per second");
-
-VNET_DEFINE_STATIC(int, icmp6errpps_count) = 0;
-VNET_DEFINE_STATIC(struct timeval, icmp6errppslim_last);
-
-#define V_icmp6errpps_count VNET(icmp6errpps_count)
-#define V_icmp6errppslim_last VNET(icmp6errppslim_last)
-
static void icmp6_errcount(int, int);
static int icmp6_rip6_input(struct mbuf **, int);
static void icmp6_reflect(struct mbuf *, size_t);
@@ -2743,6 +2731,126 @@
return (error);
}
+static int sysctl_icmp6lim_and_jitter(SYSCTL_HANDLER_ARGS);
+VNET_DEFINE_STATIC(u_int, icmp6errppslim) = 100;
+#define V_icmp6errppslim VNET(icmp6errppslim)
+SYSCTL_PROC(_net_inet6_icmp6, ICMPV6CTL_ERRPPSLIMIT, errppslimit,
+ CTLTYPE_UINT | CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6errppslim), 0,
+ &sysctl_icmp6lim_and_jitter, "IU",
+ "Maximum number of ICMPv6 error/reply messages per second");
+
+VNET_DEFINE_STATIC(int, icmp6lim_curr_jitter) = 0;
+#define V_icmp6lim_curr_jitter VNET(icmp6lim_curr_jitter)
+
+VNET_DEFINE_STATIC(u_int, icmp6lim_jitter) = 8;
+#define V_icmp6lim_jitter VNET(icmp6lim_jitter)
+SYSCTL_PROC(_net_inet6_icmp6, OID_AUTO, icmp6lim_jitter, CTLTYPE_UINT |
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6lim_jitter), 0,
+ &sysctl_icmp6lim_and_jitter, "IU",
+ "Random errppslimit jitter adjustment limit");
+
+VNET_DEFINE_STATIC(int, icmp6lim_output) = 1;
+#define V_icmp6lim_output VNET(icmp6lim_output)
+SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, icmp6lim_output,
+ CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6lim_output), 0,
+ "Enable logging of ICMPv6 response rate limiting");
+
+typedef enum {
+ RATELIM_PARAM_PROB = 0,
+ RATELIM_TOO_BIG,
+ RATELIM_UNREACH,
+ RATELIM_TEXCEED,
+ RATELIM_REDIR,
+ RATELIM_REPLY,
+ RATELIM_OTHER,
+ RATELIM_MAX
+} ratelim_which;
+
+static const char *icmp6_rate_descrs[RATELIM_MAX] = {
+ [RATELIM_PARAM_PROB] = "bad IPv6 header",
+ [RATELIM_TOO_BIG] = "packet too big",
+ [RATELIM_UNREACH] = "destination unreachable",
+ [RATELIM_TEXCEED] = "time exceeded",
+ [RATELIM_REPLY] = "echo reply",
+ [RATELIM_REDIR] = "neighbor discovery redirect",
+ [RATELIM_OTHER] = "(other)",
+};
+
+static void
+icmp6lim_new_jitter(void)
+{
+ /*
+ * Adjust limit +/- to jitter the measurement to deny a side-channel
+ * port scan as in https://dl.acm.org/doi/10.1145/3372297.3417280
+ */
+ if (V_icmp6lim_jitter > 0)
+ V_icmp6lim_curr_jitter =
+ arc4random_uniform(V_icmp6lim_jitter * 2 + 1) -
+ V_icmp6lim_jitter;
+}
+
+static int
+sysctl_icmp6lim_and_jitter(SYSCTL_HANDLER_ARGS)
+{
+ uint32_t new;
+ int error;
+ bool lim;
+
+ MPASS(oidp->oid_arg1 == &VNET_NAME(icmp6errppslim) ||
+ oidp->oid_arg1 == &VNET_NAME(icmp6lim_jitter));
+
+ lim = (oidp->oid_arg1 == &VNET_NAME(icmp6errppslim));
+ new = lim ? V_icmp6errppslim : V_icmp6lim_jitter;
+ error = sysctl_handle_int(oidp, &new, 0, req);
+ if (error == 0 && req->newptr) {
+ if (lim) {
+ if (new <= V_icmp6lim_jitter)
+ error = EINVAL;
+ else
+ V_icmp6errppslim = new;
+ } else {
+ if (new >= V_icmp6errppslim)
+ error = EINVAL;
+ else {
+ V_icmp6lim_jitter = new;
+ icmp6lim_new_jitter();
+ }
+ }
+ }
+ MPASS(V_icmp6errppslim + V_icmp6lim_curr_jitter > 0);
+
+ return (error);
+}
+
+
+VNET_DEFINE_STATIC(struct counter_rate, icmp6_rates[RATELIM_MAX]);
+#define V_icmp6_rates VNET(icmp6_rates)
+
+static void
+icmp6_ratelimit_init(void)
+{
+
+ for (int i = 0; i < RATELIM_MAX; i++) {
+ V_icmp6_rates[i].cr_rate = counter_u64_alloc(M_WAITOK);
+ V_icmp6_rates[i].cr_ticks = ticks;
+ }
+ icmp6lim_new_jitter();
+}
+VNET_SYSINIT(icmp6_ratelimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY,
+ icmp6_ratelimit_init, NULL);
+
+#ifdef VIMAGE
+static void
+icmp6_ratelimit_uninit(void)
+{
+
+ for (int i = 0; i < RATELIM_MAX; i++)
+ counter_u64_free(V_icmp6_rates[i].cr_rate);
+}
+VNET_SYSUNINIT(icmp6_ratelimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
+ icmp6_ratelimit_uninit, NULL);
+#endif
+
/*
* Perform rate limit check.
* Returns 0 if it is okay to send the icmp6 packet.
@@ -2752,24 +2860,55 @@
* XXX per-destination/type check necessary?
*
* dst - not used at this moment
- * type - not used at this moment
* code - not used at this moment
*/
int
-icmp6_ratelimit(const struct in6_addr *dst, const int type,
- const int code)
+icmp6_ratelimit(const struct in6_addr *dst, const int type, const int code)
{
- int ret;
+ ratelim_which which;
+ int64_t pps;
- ret = 0; /* okay to send */
+ if (V_icmp6errppslim == 0)
+ return (0);
- /* PPS limit */
- if (!ppsratecheck(&V_icmp6errppslim_last, &V_icmp6errpps_count,
- V_icmp6errppslim)) {
- /* The packet is subject to rate limit */
- ret++;
+ switch (type) {
+ case ICMP6_PARAM_PROB:
+ which = RATELIM_PARAM_PROB;
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ which = RATELIM_TOO_BIG;
+ break;
+ case ICMP6_DST_UNREACH:
+ which = RATELIM_UNREACH;
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ which = RATELIM_TEXCEED;
+ break;
+ case ND_REDIRECT:
+ which = RATELIM_REDIR;
+ break;
+ case ICMP6_ECHO_REPLY:
+ which = RATELIM_REPLY;
+ break;
+ default:
+ which = RATELIM_OTHER;
+ break;
+ };
+
+ pps = counter_ratecheck(&V_icmp6_rates[which], V_icmp6errppslim +
+ V_icmp6lim_curr_jitter);
+ if (pps > 0) {
+ if (V_icmp6lim_output)
+ log(LOG_NOTICE, "Limiting ICMPv6 %s output from %jd "
+ "to %d packets/sec\n", icmp6_rate_descrs[which],
+ (intmax_t )pps, V_icmp6errppslim +
+ V_icmp6lim_curr_jitter);
+ icmp6lim_new_jitter();
+ }
+ if (pps == -1) {
ICMP6STAT_INC(icp6s_toofreq);
+ return (-1);
}
- return ret;
+ return (0);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 10, 3:07 PM (15 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15743622
Default Alt Text
D44482.diff (5 KB)
Attached To
Mode
D44482: icmp6: bring rate limiting on a par with IPv4
Attached
Detach File
Event Timeline
Log In to Comment