aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesper Dangaard Brouer <brouer@redhat.com>2017-06-14 07:27:37 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-14 15:33:58 -0400
commit849a44de91636c24cea799cb8ad8c36433feb913 (patch)
tree401229e174fa94ffe0234295777b5c4df181fafd
parentc4f65b09b459c6f0ec27b1a1a65302f7fea5c96f (diff)
net: don't global ICMP rate limit packets originating from loopback
Florian Weimer seems to have a glibc test-case which requires that loopback interfaces does not get ICMP ratelimited. This was broken by commit c0303efeab73 ("net: reduce cycles spend on ICMP replies that gets rate limited"). An ICMP response will usually be routed back-out the same incoming interface. Thus, take advantage of this and skip global ICMP ratelimit when the incoming device is loopback. In the unlikely event that the outgoing it not loopback, due to strange routing policy rules, ICMP rate limiting still works via peer ratelimiting via icmpv4_xrlim_allow(). Thus, we should still comply with RFC1812 (section 4.3.2.8 "Rate Limiting"). This seems to fix the reproducer given by Florian. While still avoiding to perform expensive and unneeded outgoing route lookup for rate limited packets (in the non-loopback case). Fixes: c0303efeab73 ("net: reduce cycles spend on ICMP replies that gets rate limited") Reported-by: Florian Weimer <fweimer@redhat.com> Reported-by: "H.J. Lu" <hjl.tools@gmail.com> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/icmp.c8
-rw-r--r--net/ipv6/icmp.c2
2 files changed, 7 insertions, 3 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 43318b5f5647..9144fa7df2ad 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -657,8 +657,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
657 /* Needed by both icmp_global_allow and icmp_xmit_lock */ 657 /* Needed by both icmp_global_allow and icmp_xmit_lock */
658 local_bh_disable(); 658 local_bh_disable();
659 659
660 /* Check global sysctl_icmp_msgs_per_sec ratelimit */ 660 /* Check global sysctl_icmp_msgs_per_sec ratelimit, unless
661 if (!icmpv4_global_allow(net, type, code)) 661 * incoming dev is loopback. If outgoing dev change to not be
662 * loopback, then peer ratelimit still work (in icmpv4_xrlim_allow)
663 */
664 if (!(skb_in->dev && (skb_in->dev->flags&IFF_LOOPBACK)) &&
665 !icmpv4_global_allow(net, type, code))
662 goto out_bh_enable; 666 goto out_bh_enable;
663 667
664 sk = icmp_xmit_lock(net); 668 sk = icmp_xmit_lock(net);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 230b5aac9f03..8d7b113958b1 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -491,7 +491,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
491 local_bh_disable(); 491 local_bh_disable();
492 492
493 /* Check global sysctl_icmp_msgs_per_sec ratelimit */ 493 /* Check global sysctl_icmp_msgs_per_sec ratelimit */
494 if (!icmpv6_global_allow(type)) 494 if (!(skb->dev->flags&IFF_LOOPBACK) && !icmpv6_global_allow(type))
495 goto out_bh_enable; 495 goto out_bh_enable;
496 496
497 mip6_addr_swap(skb); 497 mip6_addr_swap(skb);