aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2014-09-19 10:38:40 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-23 12:47:38 -0400
commit4cdf507d54525842dfd9f6313fdafba039084046 (patch)
tree3ea6c335251ee0b0bdb404df727ca307d55a9de9 /net
parente8b56d55a30afe588d905913d011678235dda437 (diff)
icmp: add a global rate limitation
Current ICMP rate limiting uses inetpeer cache, which is an RBL tree protected by a lock, meaning that hosts can be stuck hard if all cpus want to check ICMP limits. When say a DNS or NTP server process is restarted, inetpeer tree grows quick and machine comes to its knees. iptables can not help because the bottleneck happens before ICMP messages are even cooked and sent. This patch adds a new global limitation, using a token bucket filter, controlled by two new sysctl : icmp_msgs_per_sec - INTEGER Limit maximal number of ICMP packets sent per second from this host. Only messages whose type matches icmp_ratemask are controlled by this limit. Default: 1000 icmp_msgs_burst - INTEGER icmp_msgs_per_sec controls number of ICMP packets sent per second, while icmp_msgs_burst controls the burst size of these packets. Default: 50 Note that if we really want to send millions of ICMP messages per second, we might extend idea and infra added in commit 04ca6973f7c1a ("ip: make IP identifiers less predictable") : add a token bucket in the ip_idents hash and no longer rely on inetpeer. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/icmp.c64
-rw-r--r--net/ipv4/sysctl_net_ipv4.c16
-rw-r--r--net/ipv6/icmp.c20
3 files changed, 88 insertions, 12 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index ea7d4afe8205..5882f584910e 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -231,12 +231,62 @@ static inline void icmp_xmit_unlock(struct sock *sk)
231 spin_unlock_bh(&sk->sk_lock.slock); 231 spin_unlock_bh(&sk->sk_lock.slock);
232} 232}
233 233
234int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
235int sysctl_icmp_msgs_burst __read_mostly = 50;
236
237static struct {
238 spinlock_t lock;
239 u32 credit;
240 u32 stamp;
241} icmp_global = {
242 .lock = __SPIN_LOCK_UNLOCKED(icmp_global.lock),
243};
244
245/**
246 * icmp_global_allow - Are we allowed to send one more ICMP message ?
247 *
248 * Uses a token bucket to limit our ICMP messages to sysctl_icmp_msgs_per_sec.
249 * Returns false if we reached the limit and can not send another packet.
250 * Note: called with BH disabled
251 */
252bool icmp_global_allow(void)
253{
254 u32 credit, delta, incr = 0, now = (u32)jiffies;
255 bool rc = false;
256
257 /* Check if token bucket is empty and cannot be refilled
258 * without taking the spinlock.
259 */
260 if (!icmp_global.credit) {
261 delta = min_t(u32, now - icmp_global.stamp, HZ);
262 if (delta < HZ / 50)
263 return false;
264 }
265
266 spin_lock(&icmp_global.lock);
267 delta = min_t(u32, now - icmp_global.stamp, HZ);
268 if (delta >= HZ / 50) {
269 incr = sysctl_icmp_msgs_per_sec * delta / HZ ;
270 if (incr)
271 icmp_global.stamp = now;
272 }
273 credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst);
274 if (credit) {
275 credit--;
276 rc = true;
277 }
278 icmp_global.credit = credit;
279 spin_unlock(&icmp_global.lock);
280 return rc;
281}
282EXPORT_SYMBOL(icmp_global_allow);
283
234/* 284/*
235 * Send an ICMP frame. 285 * Send an ICMP frame.
236 */ 286 */
237 287
238static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, 288static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
239 struct flowi4 *fl4, int type, int code) 289 struct flowi4 *fl4, int type, int code)
240{ 290{
241 struct dst_entry *dst = &rt->dst; 291 struct dst_entry *dst = &rt->dst;
242 bool rc = true; 292 bool rc = true;
@@ -253,8 +303,14 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
253 goto out; 303 goto out;
254 304
255 /* Limit if icmp type is enabled in ratemask. */ 305 /* Limit if icmp type is enabled in ratemask. */
256 if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) { 306 if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask))
257 struct inet_peer *peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1); 307 goto out;
308
309 rc = false;
310 if (icmp_global_allow()) {
311 struct inet_peer *peer;
312
313 peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1);
258 rc = inet_peer_xrlim_allow(peer, 314 rc = inet_peer_xrlim_allow(peer,
259 net->ipv4.sysctl_icmp_ratelimit); 315 net->ipv4.sysctl_icmp_ratelimit);
260 if (peer) 316 if (peer)
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1599966f4639..8a25509c35b3 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -731,6 +731,22 @@ static struct ctl_table ipv4_table[] = {
731 .extra2 = &one, 731 .extra2 = &one,
732 }, 732 },
733 { 733 {
734 .procname = "icmp_msgs_per_sec",
735 .data = &sysctl_icmp_msgs_per_sec,
736 .maxlen = sizeof(int),
737 .mode = 0644,
738 .proc_handler = proc_dointvec_minmax,
739 .extra1 = &zero,
740 },
741 {
742 .procname = "icmp_msgs_burst",
743 .data = &sysctl_icmp_msgs_burst,
744 .maxlen = sizeof(int),
745 .mode = 0644,
746 .proc_handler = proc_dointvec_minmax,
747 .extra1 = &zero,
748 },
749 {
734 .procname = "udp_mem", 750 .procname = "udp_mem",
735 .data = &sysctl_udp_mem, 751 .data = &sysctl_udp_mem,
736 .maxlen = sizeof(sysctl_udp_mem), 752 .maxlen = sizeof(sysctl_udp_mem),
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 394bb824fe4b..141e1f3ab74e 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -170,11 +170,11 @@ static bool is_ineligible(const struct sk_buff *skb)
170/* 170/*
171 * Check the ICMP output rate limit 171 * Check the ICMP output rate limit
172 */ 172 */
173static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type, 173static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
174 struct flowi6 *fl6) 174 struct flowi6 *fl6)
175{ 175{
176 struct dst_entry *dst;
177 struct net *net = sock_net(sk); 176 struct net *net = sock_net(sk);
177 struct dst_entry *dst;
178 bool res = false; 178 bool res = false;
179 179
180 /* Informational messages are not limited. */ 180 /* Informational messages are not limited. */
@@ -199,16 +199,20 @@ static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
199 } else { 199 } else {
200 struct rt6_info *rt = (struct rt6_info *)dst; 200 struct rt6_info *rt = (struct rt6_info *)dst;
201 int tmo = net->ipv6.sysctl.icmpv6_time; 201 int tmo = net->ipv6.sysctl.icmpv6_time;
202 struct inet_peer *peer;
203 202
204 /* Give more bandwidth to wider prefixes. */ 203 /* Give more bandwidth to wider prefixes. */
205 if (rt->rt6i_dst.plen < 128) 204 if (rt->rt6i_dst.plen < 128)
206 tmo >>= ((128 - rt->rt6i_dst.plen)>>5); 205 tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
207 206
208 peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); 207 if (icmp_global_allow()) {
209 res = inet_peer_xrlim_allow(peer, tmo); 208 struct inet_peer *peer;
210 if (peer) 209
211 inet_putpeer(peer); 210 peer = inet_getpeer_v6(net->ipv6.peers,
211 &rt->rt6i_dst.addr, 1);
212 res = inet_peer_xrlim_allow(peer, tmo);
213 if (peer)
214 inet_putpeer(peer);
215 }
212 } 216 }
213 dst_release(dst); 217 dst_release(dst);
214 return res; 218 return res;