aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/ratelimiter.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2016-11-25 21:14:50 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2016-11-29 13:18:33 +0100
commite1f203488cc652bbb6b062bf1eb454982e95cca6 (patch)
tree4bd4b17848a983aaad7b1fc024ba21ef8afffd42 /src/ratelimiter.c
parentdevice: conntrack is optional (diff)
downloadwireguard-monolithic-historical-e1f203488cc652bbb6b062bf1eb454982e95cca6.tar.xz
wireguard-monolithic-historical-e1f203488cc652bbb6b062bf1eb454982e95cca6.zip
ratelimiter: load hashlimit at modinsert time
This fixes a potential race with net_lock and rtnl_lock.
Diffstat (limited to 'src/ratelimiter.c')
-rw-r--r--src/ratelimiter.c81
1 files changed, 46 insertions, 35 deletions
diff --git a/src/ratelimiter.c b/src/ratelimiter.c
index 8bfe46b..7c23d55 100644
--- a/src/ratelimiter.c
+++ b/src/ratelimiter.c
@@ -15,6 +15,11 @@
#error "WireGuard requires CONFIG_IP6_NF_IPTABLES when using CONFIG_IPV6."
#endif
+static struct xt_match *v4_match;
+#if IS_ENABLED(CONFIG_IPV6)
+static struct xt_match *v6_match;
+#endif
+
enum {
RATELIMITER_PACKETS_PER_SECOND = 75,
RATELIMITER_PACKETS_BURSTABLE = 5
@@ -44,47 +49,29 @@ int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *w
memset(ratelimiter, 0, sizeof(struct ratelimiter));
cfg_init(&ratelimiter->v4_info.cfg, NFPROTO_IPV4);
- cfg_init(&ratelimiter->v6_info.cfg, NFPROTO_IPV6);
memcpy(ratelimiter->v4_info.name, dev->name, IFNAMSIZ);
- memcpy(ratelimiter->v6_info.name, dev->name, IFNAMSIZ);
-
- ratelimiter->v4_match = xt_request_find_match(NFPROTO_IPV4, "hashlimit", 1);
- if (IS_ERR(ratelimiter->v4_match)) {
- pr_err("The xt_hashlimit module for IPv4 is required");
- return PTR_ERR(ratelimiter->v4_match);
- }
-
chk.matchinfo = &ratelimiter->v4_info;
- chk.match = ratelimiter->v4_match;
+ chk.match = v4_match;
chk.family = NFPROTO_IPV4;
- ret = ratelimiter->v4_match->checkentry(&chk);
- if (ret < 0) {
- module_put(ratelimiter->v4_match->me);
+ ret = v4_match->checkentry(&chk);
+ if (ret < 0)
return ret;
- }
#if IS_ENABLED(CONFIG_IPV6)
- ratelimiter->v6_match = xt_request_find_match(NFPROTO_IPV6, "hashlimit", 1);
- if (IS_ERR(ratelimiter->v6_match)) {
- pr_err("The xt_hashlimit module for IPv6 is required");
- module_put(ratelimiter->v4_match->me);
- return PTR_ERR(ratelimiter->v6_match);
- }
-
+ cfg_init(&ratelimiter->v6_info.cfg, NFPROTO_IPV6);
+ memcpy(ratelimiter->v6_info.name, dev->name, IFNAMSIZ);
chk.matchinfo = &ratelimiter->v6_info;
- chk.match = ratelimiter->v6_match;
+ chk.match = v6_match;
chk.family = NFPROTO_IPV6;
- ret = ratelimiter->v6_match->checkentry(&chk);
+ ret = v6_match->checkentry(&chk);
if (ret < 0) {
struct xt_mtdtor_param dtor_v4 = {
.net = wg->creating_net,
- .match = ratelimiter->v4_match,
+ .match = v4_match,
.matchinfo = &ratelimiter->v4_info,
.family = NFPROTO_IPV4
};
- ratelimiter->v4_match->destroy(&dtor_v4);
- module_put(ratelimiter->v4_match->me);
- module_put(ratelimiter->v6_match->me);
+ v4_match->destroy(&dtor_v4);
return ret;
}
#endif
@@ -97,18 +84,16 @@ void ratelimiter_uninit(struct ratelimiter *ratelimiter)
{
struct xt_mtdtor_param dtor = { .net = ratelimiter->net };
- dtor.match = ratelimiter->v4_match;
+ dtor.match = v4_match;
dtor.matchinfo = &ratelimiter->v4_info;
dtor.family = NFPROTO_IPV4;
- ratelimiter->v4_match->destroy(&dtor);
- module_put(ratelimiter->v4_match->me);
+ v4_match->destroy(&dtor);
#if IS_ENABLED(CONFIG_IPV6)
- dtor.match = ratelimiter->v6_match;
+ dtor.match = v6_match;
dtor.matchinfo = &ratelimiter->v6_info;
dtor.family = NFPROTO_IPV6;
- ratelimiter->v6_match->destroy(&dtor);
- module_put(ratelimiter->v6_match->me);
+ v6_match->destroy(&dtor);
#endif
}
@@ -118,14 +103,14 @@ bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb)
if (unlikely(skb->len < sizeof(struct iphdr)))
return false;
if (ip_hdr(skb)->version == 4) {
- action.match = ratelimiter->v4_match;
+ action.match = v4_match;
action.matchinfo = &ratelimiter->v4_info;
action.thoff = ip_hdrlen(skb);
action.family = NFPROTO_IPV4;
}
#if IS_ENABLED(CONFIG_IPV6)
else if (ip_hdr(skb)->version == 6) {
- action.match = ratelimiter->v6_match;
+ action.match = v6_match;
action.matchinfo = &ratelimiter->v6_info;
action.family = NFPROTO_IPV6;
}
@@ -134,3 +119,29 @@ bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb)
return false;
return action.match->match(skb, &action);
}
+
+int ratelimiter_module_init(void)
+{
+ v4_match = xt_request_find_match(NFPROTO_IPV4, "hashlimit", 1);
+ if (IS_ERR(v4_match)) {
+ pr_err("The xt_hashlimit module for IPv4 is required");
+ return PTR_ERR(v4_match);
+ }
+#if IS_ENABLED(CONFIG_IPV6)
+ v6_match = xt_request_find_match(NFPROTO_IPV6, "hashlimit", 1);
+ if (IS_ERR(v6_match)) {
+ pr_err("The xt_hashlimit module for IPv6 is required");
+ module_put(v4_match->me);
+ return PTR_ERR(v6_match);
+ }
+#endif
+ return 0;
+}
+
+void ratelimiter_module_deinit(void)
+{
+ module_put(v4_match->me);
+#if IS_ENABLED(CONFIG_IPV6)
+ module_put(v6_match->me);
+#endif
+}