Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipv6: Add rate limit mask for ICMPv6 messages

To make ICMPv6 closer to ICMPv4, add ratemask parameter. Since the ICMP
message types use larger numeric values, a simple bitmask doesn't fit.
I use large bitmap. The input and output are the in form of list of
ranges. Set the default to rate limit all error messages but Packet Too
Big. For Packet Too Big, use ratemask instead of hard-coded.

There are functions where icmpv6_xrlim_allow() and icmpv6_global_allow()
aren't called. This patch only adds them to icmpv6_echo_reply().

Rate limiting error messages is mandated by RFC 4443 but RFC 4890 says
that it is also acceptable to rate limit informational messages. Thus,
I removed the current hard-coded behavior of icmpv6_mask_allow() that
doesn't rate limit informational messages.

v2: Add dummy function proc_do_large_bitmap() if CONFIG_PROC_SYSCTL
isn't defined, expand the description in ip-sysctl.txt and remove
unnecessary conditional before kfree().
v3: Inline the bitmap instead of dynamically allocated. Still is a
pointer to it is needed because of the way proc_do_large_bitmap work.

Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Stephen Suryaputra and committed by
David S. Miller
0bc19985 4cf2d206

+60 -10
+16 -1
Documentation/networking/ip-sysctl.txt
··· 1913 1913 1914 1914 icmp/*: 1915 1915 ratelimit - INTEGER 1916 - Limit the maximal rates for sending ICMPv6 packets. 1916 + Limit the maximal rates for sending ICMPv6 messages. 1917 1917 0 to disable any limiting, 1918 1918 otherwise the minimal space between responses in milliseconds. 1919 1919 Default: 1000 1920 + 1921 + ratemask - list of comma separated ranges 1922 + For ICMPv6 message types matching the ranges in the ratemask, limit 1923 + the sending of the message according to ratelimit parameter. 1924 + 1925 + The format used for both input and output is a comma separated 1926 + list of ranges (e.g. "0-127,129" for ICMPv6 message type 0 to 127 and 1927 + 129). Writing to the file will clear all previous ranges of ICMPv6 1928 + message types and update the current list with the input. 1929 + 1930 + Refer to: https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml 1931 + for numerical values of ICMPv6 message types, e.g. echo request is 128 1932 + and echo reply is 129. 1933 + 1934 + Default: 0-1,3-127 (rate limit ICMPv6 errors except Packet Too Big) 1920 1935 1921 1936 echo_ignore_all - BOOLEAN 1922 1937 If set non-zero, then the kernel will ignore all ICMP ECHO
+3
include/net/netns/ipv6.h
··· 8 8 #ifndef __NETNS_IPV6_H__ 9 9 #define __NETNS_IPV6_H__ 10 10 #include <net/dst_ops.h> 11 + #include <uapi/linux/icmpv6.h> 11 12 12 13 struct ctl_table_header; 13 14 ··· 36 35 int icmpv6_echo_ignore_all; 37 36 int icmpv6_echo_ignore_multicast; 38 37 int icmpv6_echo_ignore_anycast; 38 + DECLARE_BITMAP(icmpv6_ratemask, ICMPV6_MSG_MAX + 1); 39 + unsigned long *icmpv6_ratemask_ptr; 39 40 int anycast_src_echo_reply; 40 41 int ip_nonlocal_bind; 41 42 int fwmark_reflect;
+4
include/uapi/linux/icmpv6.h
··· 90 90 #define ICMPV6_TIME_EXCEED 3 91 91 #define ICMPV6_PARAMPROB 4 92 92 93 + #define ICMPV6_ERRMSG_MAX 127 94 + 93 95 #define ICMPV6_INFOMSG_MASK 0x80 94 96 95 97 #define ICMPV6_ECHO_REQUEST 128 ··· 111 109 #define ICMPV6_MOBILE_PREFIX_ADV 147 112 110 113 111 #define ICMPV6_MRDISC_ADV 151 112 + 113 + #define ICMPV6_MSG_MAX 255 114 114 115 115 /* 116 116 * Codes for Destination Unreachable
+6
kernel/sysctl.c
··· 3326 3326 return -ENOSYS; 3327 3327 } 3328 3328 3329 + int proc_do_large_bitmap(struct ctl_table *table, int write, 3330 + void __user *buffer, size_t *lenp, loff_t *ppos) 3331 + { 3332 + return -ENOSYS; 3333 + } 3329 3334 3330 3335 #endif /* CONFIG_PROC_SYSCTL */ 3331 3336 ··· 3371 3366 EXPORT_SYMBOL(proc_dostring); 3372 3367 EXPORT_SYMBOL(proc_doulongvec_minmax); 3373 3368 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); 3369 + EXPORT_SYMBOL(proc_do_large_bitmap);
+9
net/ipv6/af_inet6.c
··· 850 850 net->ipv6.sysctl.icmpv6_echo_ignore_all = 0; 851 851 net->ipv6.sysctl.icmpv6_echo_ignore_multicast = 0; 852 852 net->ipv6.sysctl.icmpv6_echo_ignore_anycast = 0; 853 + 854 + /* By default, rate limit error messages. 855 + * Except for pmtu discovery, it would break it. 856 + * proc_do_large_bitmap needs pointer to the bitmap. 857 + */ 858 + bitmap_set(net->ipv6.sysctl.icmpv6_ratemask, 0, ICMPV6_ERRMSG_MAX + 1); 859 + bitmap_clear(net->ipv6.sysctl.icmpv6_ratemask, ICMPV6_PKT_TOOBIG, 1); 860 + net->ipv6.sysctl.icmpv6_ratemask_ptr = net->ipv6.sysctl.icmpv6_ratemask; 861 + 853 862 net->ipv6.sysctl.flowlabel_consistency = 1; 854 863 net->ipv6.sysctl.auto_flowlabels = IP6_DEFAULT_AUTO_FLOW_LABELS; 855 864 net->ipv6.sysctl.idgen_retries = 3;
+22 -9
net/ipv6/icmp.c
··· 168 168 return false; 169 169 } 170 170 171 - static bool icmpv6_mask_allow(int type) 171 + static bool icmpv6_mask_allow(struct net *net, int type) 172 172 { 173 - /* Informational messages are not limited. */ 174 - if (type & ICMPV6_INFOMSG_MASK) 173 + if (type > ICMPV6_MSG_MAX) 175 174 return true; 176 175 177 - /* Do not limit pmtu discovery, it would break it. */ 178 - if (type == ICMPV6_PKT_TOOBIG) 176 + /* Limit if icmp type is set in ratemask. */ 177 + if (!test_bit(type, net->ipv6.sysctl.icmpv6_ratemask)) 179 178 return true; 180 179 181 180 return false; 182 181 } 183 182 184 - static bool icmpv6_global_allow(int type) 183 + static bool icmpv6_global_allow(struct net *net, int type) 185 184 { 186 - if (icmpv6_mask_allow(type)) 185 + if (icmpv6_mask_allow(net, type)) 187 186 return true; 188 187 189 188 if (icmp_global_allow()) ··· 201 202 struct dst_entry *dst; 202 203 bool res = false; 203 204 204 - if (icmpv6_mask_allow(type)) 205 + if (icmpv6_mask_allow(net, type)) 205 206 return true; 206 207 207 208 /* ··· 510 511 local_bh_disable(); 511 512 512 513 /* Check global sysctl_icmp_msgs_per_sec ratelimit */ 513 - if (!(skb->dev->flags&IFF_LOOPBACK) && !icmpv6_global_allow(type)) 514 + if (!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, type)) 514 515 goto out_bh_enable; 515 516 516 517 mip6_addr_swap(skb); ··· 730 731 if (IS_ERR(dst)) 731 732 goto out; 732 733 734 + /* Check the ratelimit */ 735 + if ((!(skb->dev->flags & IFF_LOOPBACK) && !icmpv6_global_allow(net, ICMPV6_ECHO_REPLY)) || 736 + !icmpv6_xrlim_allow(sk, ICMPV6_ECHO_REPLY, &fl6)) 737 + goto out_dst_release; 738 + 733 739 idev = __in6_dev_get(skb->dev); 734 740 735 741 msg.skb = skb; ··· 755 751 icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, 756 752 skb->len + sizeof(struct icmp6hdr)); 757 753 } 754 + out_dst_release: 758 755 dst_release(dst); 759 756 out: 760 757 icmpv6_xmit_unlock(sk); ··· 1142 1137 .mode = 0644, 1143 1138 .proc_handler = proc_dointvec, 1144 1139 }, 1140 + { 1141 + .procname = "ratemask", 1142 + .data = &init_net.ipv6.sysctl.icmpv6_ratemask_ptr, 1143 + .maxlen = ICMPV6_MSG_MAX + 1, 1144 + .mode = 0644, 1145 + .proc_handler = proc_do_large_bitmap, 1146 + }, 1145 1147 { }, 1146 1148 }; 1147 1149 ··· 1165 1153 table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all; 1166 1154 table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast; 1167 1155 table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast; 1156 + table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr; 1168 1157 } 1169 1158 return table; 1170 1159 }