1 /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 2 * Copyright (C) 2013 Smoothwall Ltd. <vytas.dauksa@smoothwall.net> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 /* Kernel module implementing an IP set type: the hash:ip,mark type */ 10 11 #include <linux/jhash.h> 12 #include <linux/module.h> 13 #include <linux/ip.h> 14 #include <linux/skbuff.h> 15 #include <linux/errno.h> 16 #include <linux/random.h> 17 #include <net/ip.h> 18 #include <net/ipv6.h> 19 #include <net/netlink.h> 20 #include <net/tcp.h> 21 22 #include <linux/netfilter.h> 23 #include <linux/netfilter/ipset/pfxlen.h> 24 #include <linux/netfilter/ipset/ip_set.h> 25 #include <linux/netfilter/ipset/ip_set_hash.h> 26 27 #define IPSET_TYPE_REV_MIN 0 28 /* 1 Forceadd support */ 29 #define IPSET_TYPE_REV_MAX 2 /* skbinfo support */ 30 31 MODULE_LICENSE("GPL"); 32 MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>"); 33 IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); 34 MODULE_ALIAS("ip_set_hash:ip,mark"); 35 36 /* Type specific function prefix */ 37 #define HTYPE hash_ipmark 38 #define IP_SET_HASH_WITH_MARKMASK 39 40 /* IPv4 variant */ 41 42 /* Member elements */ 43 struct hash_ipmark4_elem { 44 __be32 ip; 45 __u32 mark; 46 }; 47 48 /* Common functions */ 49 50 static inline bool 51 hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1, 52 const struct hash_ipmark4_elem *ip2, 53 u32 *multi) 54 { 55 return ip1->ip == ip2->ip && 56 ip1->mark == ip2->mark; 57 } 58 59 static bool 60 hash_ipmark4_data_list(struct sk_buff *skb, 61 const struct hash_ipmark4_elem *data) 62 { 63 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || 64 nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) 65 goto nla_put_failure; 66 return false; 67 68 nla_put_failure: 69 return true; 70 } 71 72 static inline void 73 hash_ipmark4_data_next(struct hash_ipmark4_elem *next, 74 const struct hash_ipmark4_elem *d) 75 { 76 next->ip = d->ip; 77 } 78 79 #define MTYPE hash_ipmark4 80 #define HOST_MASK 32 81 #include "ip_set_hash_gen.h" 82 83 static int 84 hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb, 85 const struct xt_action_param *par, 86 enum ipset_adt adt, struct ip_set_adt_opt *opt) 87 { 88 const struct hash_ipmark *h = set->data; 89 ipset_adtfn adtfn = set->variant->adt[adt]; 90 struct hash_ipmark4_elem e = { }; 91 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 92 93 e.mark = skb->mark; 94 e.mark &= h->markmask; 95 96 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); 97 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 98 } 99 100 static int 101 hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], 102 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 103 { 104 const struct hash_ipmark *h = set->data; 105 ipset_adtfn adtfn = set->variant->adt[adt]; 106 struct hash_ipmark4_elem e = { }; 107 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 108 u32 ip, ip_to = 0; 109 int ret; 110 111 if (tb[IPSET_ATTR_LINENO]) 112 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 113 114 if (unlikely(!tb[IPSET_ATTR_IP] || 115 !ip_set_attr_netorder(tb, IPSET_ATTR_MARK))) 116 return -IPSET_ERR_PROTOCOL; 117 118 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip); 119 if (ret) 120 return ret; 121 122 ret = ip_set_get_extensions(set, tb, &ext); 123 if (ret) 124 return ret; 125 126 e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK])); 127 e.mark &= h->markmask; 128 129 if (adt == IPSET_TEST || 130 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { 131 ret = adtfn(set, &e, &ext, &ext, flags); 132 return ip_set_eexist(ret, flags) ? 0 : ret; 133 } 134 135 ip_to = ip = ntohl(e.ip); 136 if (tb[IPSET_ATTR_IP_TO]) { 137 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); 138 if (ret) 139 return ret; 140 if (ip > ip_to) 141 swap(ip, ip_to); 142 } else if (tb[IPSET_ATTR_CIDR]) { 143 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 144 145 if (!cidr || cidr > HOST_MASK) 146 return -IPSET_ERR_INVALID_CIDR; 147 ip_set_mask_from_to(ip, ip_to, cidr); 148 } 149 150 if (retried) 151 ip = ntohl(h->next.ip); 152 for (; !before(ip_to, ip); ip++) { 153 e.ip = htonl(ip); 154 ret = adtfn(set, &e, &ext, &ext, flags); 155 156 if (ret && !ip_set_eexist(ret, flags)) 157 return ret; 158 159 ret = 0; 160 } 161 return ret; 162 } 163 164 /* IPv6 variant */ 165 166 struct hash_ipmark6_elem { 167 union nf_inet_addr ip; 168 __u32 mark; 169 }; 170 171 /* Common functions */ 172 173 static inline bool 174 hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1, 175 const struct hash_ipmark6_elem *ip2, 176 u32 *multi) 177 { 178 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && 179 ip1->mark == ip2->mark; 180 } 181 182 static bool 183 hash_ipmark6_data_list(struct sk_buff *skb, 184 const struct hash_ipmark6_elem *data) 185 { 186 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || 187 nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) 188 goto nla_put_failure; 189 return false; 190 191 nla_put_failure: 192 return true; 193 } 194 195 static inline void 196 hash_ipmark6_data_next(struct hash_ipmark4_elem *next, 197 const struct hash_ipmark6_elem *d) 198 { 199 } 200 201 #undef MTYPE 202 #undef HOST_MASK 203 204 #define MTYPE hash_ipmark6 205 #define HOST_MASK 128 206 #define IP_SET_EMIT_CREATE 207 #include "ip_set_hash_gen.h" 208 209 static int 210 hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb, 211 const struct xt_action_param *par, 212 enum ipset_adt adt, struct ip_set_adt_opt *opt) 213 { 214 const struct hash_ipmark *h = set->data; 215 ipset_adtfn adtfn = set->variant->adt[adt]; 216 struct hash_ipmark6_elem e = { }; 217 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 218 219 e.mark = skb->mark; 220 e.mark &= h->markmask; 221 222 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 223 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 224 } 225 226 static int 227 hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], 228 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 229 { 230 const struct hash_ipmark *h = set->data; 231 ipset_adtfn adtfn = set->variant->adt[adt]; 232 struct hash_ipmark6_elem e = { }; 233 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 234 int ret; 235 236 if (tb[IPSET_ATTR_LINENO]) 237 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 238 239 if (unlikely(!tb[IPSET_ATTR_IP] || 240 !ip_set_attr_netorder(tb, IPSET_ATTR_MARK))) 241 return -IPSET_ERR_PROTOCOL; 242 if (unlikely(tb[IPSET_ATTR_IP_TO])) 243 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; 244 if (unlikely(tb[IPSET_ATTR_CIDR])) { 245 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 246 247 if (cidr != HOST_MASK) 248 return -IPSET_ERR_INVALID_CIDR; 249 } 250 251 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip); 252 if (ret) 253 return ret; 254 255 ret = ip_set_get_extensions(set, tb, &ext); 256 if (ret) 257 return ret; 258 259 e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK])); 260 e.mark &= h->markmask; 261 262 if (adt == IPSET_TEST) { 263 ret = adtfn(set, &e, &ext, &ext, flags); 264 return ip_set_eexist(ret, flags) ? 0 : ret; 265 } 266 267 ret = adtfn(set, &e, &ext, &ext, flags); 268 if (ret && !ip_set_eexist(ret, flags)) 269 return ret; 270 271 return 0; 272 } 273 274 static struct ip_set_type hash_ipmark_type __read_mostly = { 275 .name = "hash:ip,mark", 276 .protocol = IPSET_PROTOCOL, 277 .features = IPSET_TYPE_IP | IPSET_TYPE_MARK, 278 .dimension = IPSET_DIM_TWO, 279 .family = NFPROTO_UNSPEC, 280 .revision_min = IPSET_TYPE_REV_MIN, 281 .revision_max = IPSET_TYPE_REV_MAX, 282 .create = hash_ipmark_create, 283 .create_policy = { 284 [IPSET_ATTR_MARKMASK] = { .type = NLA_U32 }, 285 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, 286 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, 287 [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, 288 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, 289 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 290 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 291 }, 292 .adt_policy = { 293 [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 294 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 295 [IPSET_ATTR_MARK] = { .type = NLA_U32 }, 296 [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 297 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 298 [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 299 [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 300 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 301 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING, 302 .len = IPSET_MAX_COMMENT_SIZE }, 303 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, 304 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, 305 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, 306 }, 307 .me = THIS_MODULE, 308 }; 309 310 static int __init 311 hash_ipmark_init(void) 312 { 313 return ip_set_type_register(&hash_ipmark_type); 314 } 315 316 static void __exit 317 hash_ipmark_fini(void) 318 { 319 rcu_barrier(); 320 ip_set_type_unregister(&hash_ipmark_type); 321 } 322 323 module_init(hash_ipmark_init); 324 module_exit(hash_ipmark_fini); 325