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 const struct nf_afinfo *afinfo; 40 struct flowi6 flow; 41 struct rt6_info *rt; 42 u32 ret = 0; 43 int route_err; 44 45 memset(&flow, 0, sizeof(flow)); 46 flow.daddr = *addr; 47 if (dev) 48 flow.flowi6_oif = dev->ifindex; 49 50 rcu_read_lock(); 51 52 afinfo = nf_get_afinfo(NFPROTO_IPV6); 53 if (afinfo != NULL) { 54 const struct nf_ipv6_ops *v6ops; 55 56 if (dev && (mask & XT_ADDRTYPE_LOCAL)) { 57 v6ops = nf_get_ipv6_ops(); 58 if (v6ops && v6ops->chk_addr(net, addr, dev, true)) 59 ret = XT_ADDRTYPE_LOCAL; 60 } 61 route_err = afinfo->route(net, (struct dst_entry **)&rt, 62 flowi6_to_flowi(&flow), false); 63 } else { 64 route_err = 1; 65 } 66 rcu_read_unlock(); 67 68 if (route_err) 69 return XT_ADDRTYPE_UNREACHABLE; 70 71 if (rt->rt6i_flags & RTF_REJECT) 72 ret = XT_ADDRTYPE_UNREACHABLE; 73 74 if (dev == NULL && rt->rt6i_flags & RTF_LOCAL) 75 ret |= XT_ADDRTYPE_LOCAL; 76 if (ipv6_anycast_destination((struct dst_entry *)rt, addr)) 77 ret |= XT_ADDRTYPE_ANYCAST; 78 79 dst_release(&rt->dst); 80 return ret; 81 } 82 83 static bool match_type6(struct net *net, const struct net_device *dev, 84 const struct in6_addr *addr, u16 mask) 85 { 86 int addr_type = ipv6_addr_type(addr); 87 88 if ((mask & XT_ADDRTYPE_MULTICAST) && 89 !(addr_type & IPV6_ADDR_MULTICAST)) 90 return false; 91 if ((mask & XT_ADDRTYPE_UNICAST) && !(addr_type & IPV6_ADDR_UNICAST)) 92 return false; 93 if ((mask & XT_ADDRTYPE_UNSPEC) && addr_type != IPV6_ADDR_ANY) 94 return false; 95 96 if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST | 97 XT_ADDRTYPE_UNREACHABLE) & mask) 98 return !!(mask & match_lookup_rt6(net, dev, addr, mask)); 99 return true; 100 } 101 102 static bool 103 addrtype_mt6(struct net *net, const struct net_device *dev, 104 const struct sk_buff *skb, const struct xt_addrtype_info_v1 *info) 105 { 106 const struct ipv6hdr *iph = ipv6_hdr(skb); 107 bool ret = true; 108 109 if (info->source) 110 ret &= match_type6(net, dev, &iph->saddr, info->source) ^ 111 (info->flags & XT_ADDRTYPE_INVERT_SOURCE); 112 if (ret && info->dest) 113 ret &= match_type6(net, dev, &iph->daddr, info->dest) ^ 114 !!(info->flags & XT_ADDRTYPE_INVERT_DEST); 115 return ret; 116 } 117 #endif 118 119 static inline bool match_type(struct net *net, const struct net_device *dev, 120 __be32 addr, u_int16_t mask) 121 { 122 return !!(mask & (1 << inet_dev_addr_type(net, dev, addr))); 123 } 124 125 static bool 126 addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) 127 { 128 struct net *net = par->net; 129 const struct xt_addrtype_info *info = par->matchinfo; 130 const struct iphdr *iph = ip_hdr(skb); 131 bool ret = true; 132 133 if (info->source) 134 ret &= match_type(net, NULL, iph->saddr, info->source) ^ 135 info->invert_source; 136 if (info->dest) 137 ret &= match_type(net, NULL, iph->daddr, info->dest) ^ 138 info->invert_dest; 139 140 return ret; 141 } 142 143 static bool 144 addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 145 { 146 struct net *net = par->net; 147 const struct xt_addrtype_info_v1 *info = par->matchinfo; 148 const struct iphdr *iph; 149 const struct net_device *dev = NULL; 150 bool ret = true; 151 152 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) 153 dev = par->in; 154 else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) 155 dev = par->out; 156 157 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 158 if (par->family == NFPROTO_IPV6) 159 return addrtype_mt6(net, dev, skb, info); 160 #endif 161 iph = ip_hdr(skb); 162 if (info->source) 163 ret &= match_type(net, dev, iph->saddr, info->source) ^ 164 (info->flags & XT_ADDRTYPE_INVERT_SOURCE); 165 if (ret && info->dest) 166 ret &= match_type(net, dev, iph->daddr, info->dest) ^ 167 !!(info->flags & XT_ADDRTYPE_INVERT_DEST); 168 return ret; 169 } 170 171 static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par) 172 { 173 struct xt_addrtype_info_v1 *info = par->matchinfo; 174 175 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN && 176 info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { 177 pr_info("both incoming and outgoing " 178 "interface limitation cannot be selected\n"); 179 return -EINVAL; 180 } 181 182 if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | 183 (1 << NF_INET_LOCAL_IN)) && 184 info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) { 185 pr_info("output interface limitation " 186 "not valid in PREROUTING and INPUT\n"); 187 return -EINVAL; 188 } 189 190 if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | 191 (1 << NF_INET_LOCAL_OUT)) && 192 info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) { 193 pr_info("input interface limitation " 194 "not valid in POSTROUTING and OUTPUT\n"); 195 return -EINVAL; 196 } 197 198 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 199 if (par->family == NFPROTO_IPV6) { 200 if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) { 201 pr_err("ipv6 BLACKHOLE matching not supported\n"); 202 return -EINVAL; 203 } 204 if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) { 205 pr_err("ipv6 PROHIBIT (THROW, NAT ..) matching not supported\n"); 206 return -EINVAL; 207 } 208 if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) { 209 pr_err("ipv6 does not support BROADCAST matching\n"); 210 return -EINVAL; 211 } 212 } 213 #endif 214 return 0; 215 } 216 217 static struct xt_match addrtype_mt_reg[] __read_mostly = { 218 { 219 .name = "addrtype", 220 .family = NFPROTO_IPV4, 221 .match = addrtype_mt_v0, 222 .matchsize = sizeof(struct xt_addrtype_info), 223 .me = THIS_MODULE 224 }, 225 { 226 .name = "addrtype", 227 .family = NFPROTO_UNSPEC, 228 .revision = 1, 229 .match = addrtype_mt_v1, 230 .checkentry = addrtype_mt_checkentry_v1, 231 .matchsize = sizeof(struct xt_addrtype_info_v1), 232 .me = THIS_MODULE 233 } 234 }; 235 236 static int __init addrtype_mt_init(void) 237 { 238 return xt_register_matches(addrtype_mt_reg, 239 ARRAY_SIZE(addrtype_mt_reg)); 240 } 241 242 static void __exit addrtype_mt_exit(void) 243 { 244 xt_unregister_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); 245 } 246 247 module_init(addrtype_mt_init); 248 module_exit(addrtype_mt_exit); 249