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

netfilter: xt_addrtype: ipv6 support

The kernel will refuse certain types that do not work in ipv6 mode.
We can then add these features incrementally without risk of userspace
breakage.

Signed-off-by: Florian Westphal <fwestphal@astaro.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Florian Westphal and committed by
Patrick McHardy
2f5dc631 de81bbea

+114 -2
+17
include/linux/netfilter/xt_addrtype.h
··· 10 10 XT_ADDRTYPE_LIMIT_IFACE_OUT = 0x0008, 11 11 }; 12 12 13 + 14 + /* rtn_type enum values from rtnetlink.h, but shifted */ 15 + enum { 16 + XT_ADDRTYPE_UNSPEC = 1 << 0, 17 + XT_ADDRTYPE_UNICAST = 1 << 1, /* 1 << RTN_UNICAST */ 18 + XT_ADDRTYPE_LOCAL = 1 << 2, /* 1 << RTN_LOCAL, etc */ 19 + XT_ADDRTYPE_BROADCAST = 1 << 3, 20 + XT_ADDRTYPE_ANYCAST = 1 << 4, 21 + XT_ADDRTYPE_MULTICAST = 1 << 5, 22 + XT_ADDRTYPE_BLACKHOLE = 1 << 6, 23 + XT_ADDRTYPE_UNREACHABLE = 1 << 7, 24 + XT_ADDRTYPE_PROHIBIT = 1 << 8, 25 + XT_ADDRTYPE_THROW = 1 << 9, 26 + XT_ADDRTYPE_NAT = 1 << 10, 27 + XT_ADDRTYPE_XRESOLVE = 1 << 11, 28 + }; 29 + 13 30 struct xt_addrtype_info_v1 { 14 31 __u16 source; /* source-type mask */ 15 32 __u16 dest; /* dest-type mask */
+1
net/netfilter/Kconfig
··· 652 652 config NETFILTER_XT_MATCH_ADDRTYPE 653 653 tristate '"addrtype" address type match support' 654 654 depends on NETFILTER_ADVANCED 655 + depends on (IPV6 || IPV6=n) 655 656 ---help--- 656 657 This option allows you to match what routing thinks of an address, 657 658 eg. UNICAST, LOCAL, BROADCAST, ...
+96 -2
net/netfilter/xt_addrtype.c
··· 16 16 #include <linux/ip.h> 17 17 #include <net/route.h> 18 18 19 + #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) 20 + #include <net/ipv6.h> 21 + #include <net/ip6_route.h> 22 + #include <net/ip6_fib.h> 23 + #endif 24 + 19 25 #include <linux/netfilter/xt_addrtype.h> 20 26 #include <linux/netfilter/x_tables.h> 21 27 ··· 29 23 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 30 24 MODULE_DESCRIPTION("Xtables: address type match"); 31 25 MODULE_ALIAS("ipt_addrtype"); 26 + MODULE_ALIAS("ip6t_addrtype"); 27 + 28 + #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) 29 + static u32 xt_addrtype_rt6_to_type(const struct rt6_info *rt) 30 + { 31 + u32 ret; 32 + 33 + if (!rt) 34 + return XT_ADDRTYPE_UNREACHABLE; 35 + 36 + if (rt->rt6i_flags & RTF_REJECT) 37 + ret = XT_ADDRTYPE_UNREACHABLE; 38 + else 39 + ret = 0; 40 + 41 + if (rt->rt6i_flags & RTF_LOCAL) 42 + ret |= XT_ADDRTYPE_LOCAL; 43 + if (rt->rt6i_flags & RTF_ANYCAST) 44 + ret |= XT_ADDRTYPE_ANYCAST; 45 + return ret; 46 + } 47 + 48 + static bool match_type6(struct net *net, const struct net_device *dev, 49 + const struct in6_addr *addr, u16 mask) 50 + { 51 + int addr_type = ipv6_addr_type(addr); 52 + 53 + if ((mask & XT_ADDRTYPE_MULTICAST) && 54 + !(addr_type & IPV6_ADDR_MULTICAST)) 55 + return false; 56 + if ((mask & XT_ADDRTYPE_UNICAST) && !(addr_type & IPV6_ADDR_UNICAST)) 57 + return false; 58 + if ((mask & XT_ADDRTYPE_UNSPEC) && addr_type != IPV6_ADDR_ANY) 59 + return false; 60 + 61 + if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST | 62 + XT_ADDRTYPE_UNREACHABLE) & mask) { 63 + struct rt6_info *rt; 64 + u32 type; 65 + int ifindex = dev ? dev->ifindex : 0; 66 + 67 + rt = rt6_lookup(net, addr, NULL, ifindex, !!dev); 68 + 69 + type = xt_addrtype_rt6_to_type(rt); 70 + 71 + dst_release(&rt->dst); 72 + return !!(mask & type); 73 + } 74 + return true; 75 + } 76 + 77 + static bool 78 + addrtype_mt6(struct net *net, const struct net_device *dev, 79 + const struct sk_buff *skb, const struct xt_addrtype_info_v1 *info) 80 + { 81 + const struct ipv6hdr *iph = ipv6_hdr(skb); 82 + bool ret = true; 83 + 84 + if (info->source) 85 + ret &= match_type6(net, dev, &iph->saddr, info->source) ^ 86 + (info->flags & XT_ADDRTYPE_INVERT_SOURCE); 87 + if (ret && info->dest) 88 + ret &= match_type6(net, dev, &iph->daddr, info->dest) ^ 89 + !!(info->flags & XT_ADDRTYPE_INVERT_DEST); 90 + return ret; 91 + } 92 + #endif 32 93 33 94 static inline bool match_type(struct net *net, const struct net_device *dev, 34 95 __be32 addr, u_int16_t mask) ··· 126 53 { 127 54 struct net *net = dev_net(par->in ? par->in : par->out); 128 55 const struct xt_addrtype_info_v1 *info = par->matchinfo; 129 - const struct iphdr *iph = ip_hdr(skb); 56 + const struct iphdr *iph; 130 57 const struct net_device *dev = NULL; 131 58 bool ret = true; 132 59 ··· 135 62 else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) 136 63 dev = par->out; 137 64 65 + #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) 66 + if (par->family == NFPROTO_IPV6) 67 + return addrtype_mt6(net, dev, skb, info); 68 + #endif 69 + iph = ip_hdr(skb); 138 70 if (info->source) 139 71 ret &= match_type(net, dev, iph->saddr, info->source) ^ 140 72 (info->flags & XT_ADDRTYPE_INVERT_SOURCE); ··· 176 98 return -EINVAL; 177 99 } 178 100 101 + #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) 102 + if (par->family == NFPROTO_IPV6) { 103 + if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) { 104 + pr_err("ipv6 BLACKHOLE matching not supported\n"); 105 + return -EINVAL; 106 + } 107 + if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) { 108 + pr_err("ipv6 PROHIBT (THROW, NAT ..) matching not supported\n"); 109 + return -EINVAL; 110 + } 111 + if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) { 112 + pr_err("ipv6 does not support BROADCAST matching\n"); 113 + return -EINVAL; 114 + } 115 + } 116 + #endif 179 117 return 0; 180 118 } 181 119 ··· 205 111 }, 206 112 { 207 113 .name = "addrtype", 208 - .family = NFPROTO_IPV4, 114 + .family = NFPROTO_UNSPEC, 209 115 .revision = 1, 210 116 .match = addrtype_mt_v1, 211 117 .checkentry = addrtype_mt_checkentry_v1,