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

xtables: move icmp/icmpv6 logic to xt_tcpudp

icmp/icmp6 matches are baked into ip(6)_tables.ko.

This means that even if iptables-nft is used, a rule like
"-p icmp --icmp-type 1" will load the ip(6)tables modules.

Move them to xt_tcpdudp.ko instead to avoid this.

This will also allow to eventually add kconfig knobs to build kernels
that support iptables-nft but not iptables-legacy (old set/getsockopt
interface).

Signed-off-by: Florian Westphal <fw@strlen.de>

+112 -134
+1 -67
net/ipv4/netfilter/ip_tables.c
··· 14 14 #include <linux/vmalloc.h> 15 15 #include <linux/netdevice.h> 16 16 #include <linux/module.h> 17 - #include <linux/icmp.h> 18 17 #include <net/ip.h> 19 18 #include <net/compat.h> 20 19 #include <linux/uaccess.h> ··· 30 31 MODULE_LICENSE("GPL"); 31 32 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 32 33 MODULE_DESCRIPTION("IPv4 packet filter"); 33 - MODULE_ALIAS("ipt_icmp"); 34 34 35 35 void *ipt_alloc_initial_table(const struct xt_table *info) 36 36 { ··· 1797 1799 __ipt_unregister_table(net, table); 1798 1800 } 1799 1801 1800 - /* Returns 1 if the type and code is matched by the range, 0 otherwise */ 1801 - static inline bool 1802 - icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code, 1803 - u_int8_t type, u_int8_t code, 1804 - bool invert) 1805 - { 1806 - return ((test_type == 0xFF) || 1807 - (type == test_type && code >= min_code && code <= max_code)) 1808 - ^ invert; 1809 - } 1810 - 1811 - static bool 1812 - icmp_match(const struct sk_buff *skb, struct xt_action_param *par) 1813 - { 1814 - const struct icmphdr *ic; 1815 - struct icmphdr _icmph; 1816 - const struct ipt_icmp *icmpinfo = par->matchinfo; 1817 - 1818 - /* Must not be a fragment. */ 1819 - if (par->fragoff != 0) 1820 - return false; 1821 - 1822 - ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph); 1823 - if (ic == NULL) { 1824 - /* We've been asked to examine this packet, and we 1825 - * can't. Hence, no choice but to drop. 1826 - */ 1827 - par->hotdrop = true; 1828 - return false; 1829 - } 1830 - 1831 - return icmp_type_code_match(icmpinfo->type, 1832 - icmpinfo->code[0], 1833 - icmpinfo->code[1], 1834 - ic->type, ic->code, 1835 - !!(icmpinfo->invflags&IPT_ICMP_INV)); 1836 - } 1837 - 1838 - static int icmp_checkentry(const struct xt_mtchk_param *par) 1839 - { 1840 - const struct ipt_icmp *icmpinfo = par->matchinfo; 1841 - 1842 - /* Must specify no unknown invflags */ 1843 - return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0; 1844 - } 1845 - 1846 1802 static struct xt_target ipt_builtin_tg[] __read_mostly = { 1847 1803 { 1848 1804 .name = XT_STANDARD_TARGET, ··· 1827 1875 .owner = THIS_MODULE, 1828 1876 }; 1829 1877 1830 - static struct xt_match ipt_builtin_mt[] __read_mostly = { 1831 - { 1832 - .name = "icmp", 1833 - .match = icmp_match, 1834 - .matchsize = sizeof(struct ipt_icmp), 1835 - .checkentry = icmp_checkentry, 1836 - .proto = IPPROTO_ICMP, 1837 - .family = NFPROTO_IPV4, 1838 - .me = THIS_MODULE, 1839 - }, 1840 - }; 1841 - 1842 1878 static int __net_init ip_tables_net_init(struct net *net) 1843 1879 { 1844 1880 return xt_proto_init(net, NFPROTO_IPV4); ··· 1854 1914 ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg)); 1855 1915 if (ret < 0) 1856 1916 goto err2; 1857 - ret = xt_register_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt)); 1858 - if (ret < 0) 1859 - goto err4; 1860 1917 1861 1918 /* Register setsockopt */ 1862 1919 ret = nf_register_sockopt(&ipt_sockopts); 1863 1920 if (ret < 0) 1864 - goto err5; 1921 + goto err4; 1865 1922 1866 1923 return 0; 1867 1924 1868 - err5: 1869 - xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt)); 1870 1925 err4: 1871 1926 xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg)); 1872 1927 err2: ··· 1874 1939 { 1875 1940 nf_unregister_sockopt(&ipt_sockopts); 1876 1941 1877 - xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt)); 1878 1942 xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg)); 1879 1943 unregister_pernet_subsys(&ip_tables_net_ops); 1880 1944 }
+1 -67
net/ipv6/netfilter/ip6_tables.c
··· 18 18 #include <linux/netdevice.h> 19 19 #include <linux/module.h> 20 20 #include <linux/poison.h> 21 - #include <linux/icmpv6.h> 22 21 #include <net/ipv6.h> 23 22 #include <net/compat.h> 24 23 #include <linux/uaccess.h> ··· 34 35 MODULE_LICENSE("GPL"); 35 36 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 36 37 MODULE_DESCRIPTION("IPv6 packet filter"); 37 - MODULE_ALIAS("ip6t_icmp6"); 38 38 39 39 void *ip6t_alloc_initial_table(const struct xt_table *info) 40 40 { ··· 1803 1805 __ip6t_unregister_table(net, table); 1804 1806 } 1805 1807 1806 - /* Returns 1 if the type and code is matched by the range, 0 otherwise */ 1807 - static inline bool 1808 - icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code, 1809 - u_int8_t type, u_int8_t code, 1810 - bool invert) 1811 - { 1812 - return (type == test_type && code >= min_code && code <= max_code) 1813 - ^ invert; 1814 - } 1815 - 1816 - static bool 1817 - icmp6_match(const struct sk_buff *skb, struct xt_action_param *par) 1818 - { 1819 - const struct icmp6hdr *ic; 1820 - struct icmp6hdr _icmph; 1821 - const struct ip6t_icmp *icmpinfo = par->matchinfo; 1822 - 1823 - /* Must not be a fragment. */ 1824 - if (par->fragoff != 0) 1825 - return false; 1826 - 1827 - ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph); 1828 - if (ic == NULL) { 1829 - /* We've been asked to examine this packet, and we 1830 - * can't. Hence, no choice but to drop. 1831 - */ 1832 - par->hotdrop = true; 1833 - return false; 1834 - } 1835 - 1836 - return icmp6_type_code_match(icmpinfo->type, 1837 - icmpinfo->code[0], 1838 - icmpinfo->code[1], 1839 - ic->icmp6_type, ic->icmp6_code, 1840 - !!(icmpinfo->invflags&IP6T_ICMP_INV)); 1841 - } 1842 - 1843 - /* Called when user tries to insert an entry of this type. */ 1844 - static int icmp6_checkentry(const struct xt_mtchk_param *par) 1845 - { 1846 - const struct ip6t_icmp *icmpinfo = par->matchinfo; 1847 - 1848 - /* Must specify no unknown invflags */ 1849 - return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0; 1850 - } 1851 - 1852 1808 /* The built-in targets: standard (NULL) and error. */ 1853 1809 static struct xt_target ip6t_builtin_tg[] __read_mostly = { 1854 1810 { ··· 1834 1882 .owner = THIS_MODULE, 1835 1883 }; 1836 1884 1837 - static struct xt_match ip6t_builtin_mt[] __read_mostly = { 1838 - { 1839 - .name = "icmp6", 1840 - .match = icmp6_match, 1841 - .matchsize = sizeof(struct ip6t_icmp), 1842 - .checkentry = icmp6_checkentry, 1843 - .proto = IPPROTO_ICMPV6, 1844 - .family = NFPROTO_IPV6, 1845 - .me = THIS_MODULE, 1846 - }, 1847 - }; 1848 - 1849 1885 static int __net_init ip6_tables_net_init(struct net *net) 1850 1886 { 1851 1887 return xt_proto_init(net, NFPROTO_IPV6); ··· 1861 1921 ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); 1862 1922 if (ret < 0) 1863 1923 goto err2; 1864 - ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt)); 1865 - if (ret < 0) 1866 - goto err4; 1867 1924 1868 1925 /* Register setsockopt */ 1869 1926 ret = nf_register_sockopt(&ip6t_sockopts); 1870 1927 if (ret < 0) 1871 - goto err5; 1928 + goto err4; 1872 1929 1873 1930 return 0; 1874 1931 1875 - err5: 1876 - xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt)); 1877 1932 err4: 1878 1933 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); 1879 1934 err2: ··· 1881 1946 { 1882 1947 nf_unregister_sockopt(&ip6t_sockopts); 1883 1948 1884 - xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt)); 1885 1949 xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg)); 1886 1950 unregister_pernet_subsys(&ip6_tables_net_ops); 1887 1951 }
+110
net/netfilter/xt_tcpudp.c
··· 4 4 #include <linux/module.h> 5 5 #include <net/ip.h> 6 6 #include <linux/ipv6.h> 7 + #include <linux/icmp.h> 7 8 #include <net/ipv6.h> 8 9 #include <net/tcp.h> 9 10 #include <net/udp.h> ··· 21 20 MODULE_ALIAS("ipt_tcp"); 22 21 MODULE_ALIAS("ip6t_udp"); 23 22 MODULE_ALIAS("ip6t_tcp"); 23 + MODULE_ALIAS("ipt_icmp"); 24 + MODULE_ALIAS("ip6t_icmp6"); 24 25 25 26 /* Returns 1 if the port is matched by the range, 0 otherwise */ 26 27 static inline bool ··· 164 161 return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0; 165 162 } 166 163 164 + /* Returns 1 if the type and code is matched by the range, 0 otherwise */ 165 + static bool type_code_in_range(u8 test_type, u8 min_code, u8 max_code, 166 + u8 type, u8 code) 167 + { 168 + return type == test_type && code >= min_code && code <= max_code; 169 + } 170 + 171 + static bool icmp_type_code_match(u8 test_type, u8 min_code, u8 max_code, 172 + u8 type, u8 code, bool invert) 173 + { 174 + return (test_type == 0xFF || 175 + type_code_in_range(test_type, min_code, max_code, type, code)) 176 + ^ invert; 177 + } 178 + 179 + static bool icmp6_type_code_match(u8 test_type, u8 min_code, u8 max_code, 180 + u8 type, u8 code, bool invert) 181 + { 182 + return type_code_in_range(test_type, min_code, max_code, type, code) ^ invert; 183 + } 184 + 185 + static bool 186 + icmp_match(const struct sk_buff *skb, struct xt_action_param *par) 187 + { 188 + const struct icmphdr *ic; 189 + struct icmphdr _icmph; 190 + const struct ipt_icmp *icmpinfo = par->matchinfo; 191 + 192 + /* Must not be a fragment. */ 193 + if (par->fragoff != 0) 194 + return false; 195 + 196 + ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph); 197 + if (!ic) { 198 + /* We've been asked to examine this packet, and we 199 + * can't. Hence, no choice but to drop. 200 + */ 201 + par->hotdrop = true; 202 + return false; 203 + } 204 + 205 + return icmp_type_code_match(icmpinfo->type, 206 + icmpinfo->code[0], 207 + icmpinfo->code[1], 208 + ic->type, ic->code, 209 + !!(icmpinfo->invflags & IPT_ICMP_INV)); 210 + } 211 + 212 + static bool 213 + icmp6_match(const struct sk_buff *skb, struct xt_action_param *par) 214 + { 215 + const struct icmp6hdr *ic; 216 + struct icmp6hdr _icmph; 217 + const struct ip6t_icmp *icmpinfo = par->matchinfo; 218 + 219 + /* Must not be a fragment. */ 220 + if (par->fragoff != 0) 221 + return false; 222 + 223 + ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph); 224 + if (!ic) { 225 + /* We've been asked to examine this packet, and we 226 + * can't. Hence, no choice but to drop. 227 + */ 228 + par->hotdrop = true; 229 + return false; 230 + } 231 + 232 + return icmp6_type_code_match(icmpinfo->type, 233 + icmpinfo->code[0], 234 + icmpinfo->code[1], 235 + ic->icmp6_type, ic->icmp6_code, 236 + !!(icmpinfo->invflags & IP6T_ICMP_INV)); 237 + } 238 + 239 + static int icmp_checkentry(const struct xt_mtchk_param *par) 240 + { 241 + const struct ipt_icmp *icmpinfo = par->matchinfo; 242 + 243 + return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0; 244 + } 245 + 246 + static int icmp6_checkentry(const struct xt_mtchk_param *par) 247 + { 248 + const struct ip6t_icmp *icmpinfo = par->matchinfo; 249 + 250 + return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0; 251 + } 252 + 167 253 static struct xt_match tcpudp_mt_reg[] __read_mostly = { 168 254 { 169 255 .name = "tcp", ··· 307 215 .matchsize = sizeof(struct xt_udp), 308 216 .proto = IPPROTO_UDPLITE, 309 217 .me = THIS_MODULE, 218 + }, 219 + { 220 + .name = "icmp", 221 + .match = icmp_match, 222 + .matchsize = sizeof(struct ipt_icmp), 223 + .checkentry = icmp_checkentry, 224 + .proto = IPPROTO_ICMP, 225 + .family = NFPROTO_IPV4, 226 + .me = THIS_MODULE, 227 + }, 228 + { 229 + .name = "icmp6", 230 + .match = icmp6_match, 231 + .matchsize = sizeof(struct ip6t_icmp), 232 + .checkentry = icmp6_checkentry, 233 + .proto = IPPROTO_ICMPV6, 234 + .family = NFPROTO_IPV6, 235 + .me = THIS_MODULE, 310 236 }, 311 237 }; 312 238