1 /* 2 * iptables module to match inet_addr_type() of an ip. 3 * 4 * Copyright (c) 2004 Patrick McHardy <kaber@trash.net> 5 * (C) 2007 Laszlo Attila Toth <panther@balabit.hu> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/skbuff.h> 15 #include <linux/netdevice.h> 16 #include <linux/ip.h> 17 #include <net/route.h> 18 19 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 20 #include <net/ipv6.h> 21 #include <net/ip6_route.h> 22 #include <net/ip6_fib.h> 23 #endif 24 25 #include <linux/netfilter_ipv6.h> 26 #include <linux/netfilter/xt_addrtype.h> 27 #include <linux/netfilter/x_tables.h> 28 29 MODULE_LICENSE("GPL"); 30 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 31 MODULE_DESCRIPTION("Xtables: address type match"); 32 MODULE_ALIAS("ipt_addrtype"); 33 MODULE_ALIAS("ip6t_addrtype"); 34 35 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 36 static u32 match_lookup_rt6(struct net *net, const struct net_device *dev, 37 const struct in6_addr *addr, u16 mask) 38 { 39 struct flowi6 flow; 40 struct rt6_info *rt; 41 u32 ret = 0; 42 int route_err; 43 44 memset(&flow, 0, sizeof(flow)); 45 flow.daddr = *addr; 46 if (dev) 47 flow.flowi6_oif = dev->ifindex; 48 49 if (dev && (mask & XT_ADDRTYPE_LOCAL)) { 50 if (nf_ipv6_chk_addr(net, addr, dev, true)) 51 ret = XT_ADDRTYPE_LOCAL; 52 } 53 54 route_err = nf_ip6_route(net, (struct dst_entry **)&rt, 55 flowi6_to_flowi(&flow), false); 56 if (route_err) 57 return XT_ADDRTYPE_UNREACHABLE; 58 59 if (rt->rt6i_flags & RTF_REJECT) 60 ret = XT_ADDRTYPE_UNREACHABLE; 61 62 if (dev == NULL && rt->rt6i_flags & RTF_LOCAL) 63 ret |= XT_ADDRTYPE_LOCAL; 64 if (ipv6_anycast_destination((struct dst_entry *)rt, addr)) 65 ret |= XT_ADDRTYPE_ANYCAST; 66 67 dst_release(&rt->dst); 68 return ret; 69 } 70 71 static bool match_type6(struct net *net, const struct net_device *dev, 72 const struct in6_addr *addr, u16 mask) 73 { 74 int addr_type = ipv6_addr_type(addr); 75 76 if ((mask & XT_ADDRTYPE_MULTICAST) && 77 !(addr_type & IPV6_ADDR_MULTICAST)) 78 return false; 79 if ((mask & XT_ADDRTYPE_UNICAST) && !(addr_type & IPV6_ADDR_UNICAST)) 80 return false; 81 if ((mask & XT_ADDRTYPE_UNSPEC) && addr_type != IPV6_ADDR_ANY) 82 return false; 83 84 if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST | 85 XT_ADDRTYPE_UNREACHABLE) & mask) 86 return !!(mask & match_lookup_rt6(net, dev, addr, mask)); 87 return true; 88 } 89 90 static bool 91 addrtype_mt6(struct net *net, const struct net_device *dev, 92 const struct sk_buff *skb, const struct xt_addrtype_info_v1 *info) 93 { 94 const struct ipv6hdr *iph = ipv6_hdr(skb); 95 bool ret = true; 96 97 if (info->source) 98 ret &= match_type6(net, dev, &iph->saddr, info->source) ^ 99 (info->flags & XT_ADDRTYPE_INVERT_SOURCE); 100 if (ret && info->dest) 101 ret &= match_type6(net, dev, &iph->daddr, info->dest) ^ 102 !!(info->flags & XT_ADDRTYPE_INVERT_DEST); 103 return ret; 104 } 105 #endif 106 107 static inline bool match_type(struct net *net, const struct net_device *dev, 108 __be32 addr, u_int16_t mask) 109 { 110 return !!(mask & (1 << inet_dev_addr_type(net, dev, addr))); 111 } 112 113 static bool 114 addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) 115 { 116 struct net *net = xt_net(par); 117 const struct xt_addrtype_info *info = par->matchinfo; 118 const struct iphdr *iph = ip_hdr(skb); 119 bool ret = true; 120 121 if (info->source) 122 ret &= match_type(net, NULL, iph->saddr, info->source) ^ 123 info->invert_source; 124 if (info->dest) 125 ret &= match_type(net, NULL, iph->daddr, info->dest) ^ 126 info->invert_dest; 127 128 return ret; 129 } 130 131 static bool 132 addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 133 { 134 struct net *net = xt_net(par); 135 const struct xt_addrtype_info_v1 *info = par->matchinfo; 136 const struct iphdr *iph; 137 const struct net_device *dev = NULL; 138 bool ret = true; 139 140 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) 141 dev = xt_in(par); 142 else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) 143 dev = xt_out(par); 144 145 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 146 if (xt_family(par) == NFPROTO_IPV6) 147 return addrtype_mt6(net, dev, skb, info); 148 #endif 149 iph = ip_hdr(skb); 150 if (info->source) 151 ret &= match_type(net, dev, iph->saddr, info->source) ^ 152 (info->flags & XT_ADDRTYPE_INVERT_SOURCE); 153 if (ret && info->dest) 154 ret &= match_type(net, dev, iph->daddr, info->dest) ^ 155 !!(info->flags & XT_ADDRTYPE_INVERT_DEST); 156 return ret; 157 } 158 159 static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par) 160 { 161 const char *errmsg = "both incoming and outgoing interface limitation cannot be selected"; 162 struct xt_addrtype_info_v1 *info = par->matchinfo; 163 164 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN && 165 info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) 166 goto err; 167 168 if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | 169 (1 << NF_INET_LOCAL_IN)) && 170 info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { 171 errmsg = "output interface limitation not valid in PREROUTING and INPUT"; 172 goto err; 173 } 174 175 if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | 176 (1 << NF_INET_LOCAL_OUT)) && 177 info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) { 178 errmsg = "input interface limitation not valid in POSTROUTING and OUTPUT"; 179 goto err; 180 } 181 182 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 183 if (par->family == NFPROTO_IPV6) { 184 if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) { 185 errmsg = "ipv6 BLACKHOLE matching not supported"; 186 goto err; 187 } 188 if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) { 189 errmsg = "ipv6 PROHIBIT (THROW, NAT ..) matching not supported"; 190 goto err; 191 } 192 if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) { 193 errmsg = "ipv6 does not support BROADCAST matching"; 194 goto err; 195 } 196 } 197 #endif 198 return 0; 199 err: 200 pr_info_ratelimited("%s\n", errmsg); 201 return -EINVAL; 202 } 203 204 static struct xt_match addrtype_mt_reg[] __read_mostly = { 205 { 206 .name = "addrtype", 207 .family = NFPROTO_IPV4, 208 .match = addrtype_mt_v0, 209 .matchsize = sizeof(struct xt_addrtype_info), 210 .me = THIS_MODULE 211 }, 212 { 213 .name = "addrtype", 214 .family = NFPROTO_UNSPEC, 215 .revision = 1, 216 .match = addrtype_mt_v1, 217 .checkentry = addrtype_mt_checkentry_v1, 218 .matchsize = sizeof(struct xt_addrtype_info_v1), 219 .me = THIS_MODULE 220 } 221 }; 222 223 static int __init addrtype_mt_init(void) 224 { 225 return xt_register_matches(addrtype_mt_reg, 226 ARRAY_SIZE(addrtype_mt_reg)); 227 } 228 229 static void __exit addrtype_mt_exit(void) 230 { 231 xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); 232 } 233 234 module_init(addrtype_mt_init); 235 module_exit(addrtype_mt_exit); 236