1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */ 3 4 /* Kernel module implementing an IP set type: the hash:net type */ 5 6 #include <linux/jhash.h> 7 #include <linux/module.h> 8 #include <linux/ip.h> 9 #include <linux/skbuff.h> 10 #include <linux/errno.h> 11 #include <linux/random.h> 12 #include <net/ip.h> 13 #include <net/ipv6.h> 14 #include <net/netlink.h> 15 16 #include <linux/netfilter.h> 17 #include <linux/netfilter/ipset/pfxlen.h> 18 #include <linux/netfilter/ipset/ip_set.h> 19 #include <linux/netfilter/ipset/ip_set_hash.h> 20 21 #define IPSET_TYPE_REV_MIN 0 22 /* 1 Range as input support for IPv4 added */ 23 /* 2 nomatch flag support added */ 24 /* 3 Counters support added */ 25 /* 4 Comments support added */ 26 /* 5 Forceadd support added */ 27 /* 6 skbinfo support added */ 28 #define IPSET_TYPE_REV_MAX 7 /* bucketsize, initval support added */ 29 30 MODULE_LICENSE("GPL"); 31 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>"); 32 IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); 33 MODULE_ALIAS("ip_set_hash:net"); 34 35 /* Type specific function prefix */ 36 #define HTYPE hash_net 37 #define IP_SET_HASH_WITH_NETS 38 39 /* IPv4 variant */ 40 41 /* Member elements */ 42 struct hash_net4_elem { 43 __be32 ip; 44 u16 padding0; 45 u8 nomatch; 46 u8 cidr; 47 }; 48 49 /* Common functions */ 50 51 static bool 52 hash_net4_data_equal(const struct hash_net4_elem *ip1, 53 const struct hash_net4_elem *ip2, 54 u32 *multi) 55 { 56 return ip1->ip == ip2->ip && 57 ip1->cidr == ip2->cidr; 58 } 59 60 static int 61 hash_net4_do_data_match(const struct hash_net4_elem *elem) 62 { 63 return elem->nomatch ? -ENOTEMPTY : 1; 64 } 65 66 static void 67 hash_net4_data_set_flags(struct hash_net4_elem *elem, u32 flags) 68 { 69 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH; 70 } 71 72 static void 73 hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags) 74 { 75 swap(*flags, elem->nomatch); 76 } 77 78 static void 79 hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr) 80 { 81 elem->ip &= ip_set_netmask(cidr); 82 elem->cidr = cidr; 83 } 84 85 static bool 86 hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) 87 { 88 u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; 89 90 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || 91 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) || 92 (flags && 93 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) 94 goto nla_put_failure; 95 return false; 96 97 nla_put_failure: 98 return true; 99 } 100 101 static void 102 hash_net4_data_next(struct hash_net4_elem *next, 103 const struct hash_net4_elem *d) 104 { 105 next->ip = d->ip; 106 } 107 108 #define MTYPE hash_net4 109 #define HOST_MASK 32 110 #include "ip_set_hash_gen.h" 111 112 static int 113 hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, 114 const struct xt_action_param *par, 115 enum ipset_adt adt, struct ip_set_adt_opt *opt) 116 { 117 const struct hash_net4 *h = set->data; 118 ipset_adtfn adtfn = set->variant->adt[adt]; 119 struct hash_net4_elem e = { 120 .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), 121 }; 122 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 123 124 if (e.cidr == 0) 125 return -EINVAL; 126 if (adt == IPSET_TEST) 127 e.cidr = HOST_MASK; 128 129 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); 130 e.ip &= ip_set_netmask(e.cidr); 131 132 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 133 } 134 135 static int 136 hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], 137 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 138 { 139 const struct hash_net4 *h = set->data; 140 ipset_adtfn adtfn = set->variant->adt[adt]; 141 struct hash_net4_elem e = { .cidr = HOST_MASK }; 142 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 143 u32 ip = 0, ip_to = 0, ipn, n = 0; 144 int ret; 145 146 if (tb[IPSET_ATTR_LINENO]) 147 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 148 149 if (unlikely(!tb[IPSET_ATTR_IP] || 150 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) 151 return -IPSET_ERR_PROTOCOL; 152 153 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); 154 if (ret) 155 return ret; 156 157 ret = ip_set_get_extensions(set, tb, &ext); 158 if (ret) 159 return ret; 160 161 if (tb[IPSET_ATTR_CIDR]) { 162 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 163 if (!e.cidr || e.cidr > HOST_MASK) 164 return -IPSET_ERR_INVALID_CIDR; 165 } 166 167 if (tb[IPSET_ATTR_CADT_FLAGS]) { 168 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); 169 170 if (cadt_flags & IPSET_FLAG_NOMATCH) 171 flags |= (IPSET_FLAG_NOMATCH << 16); 172 } 173 174 if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { 175 e.ip = htonl(ip & ip_set_hostmask(e.cidr)); 176 ret = adtfn(set, &e, &ext, &ext, flags); 177 return ip_set_enomatch(ret, flags, adt, set) ? -ret : 178 ip_set_eexist(ret, flags) ? 0 : ret; 179 } 180 181 ip_to = ip; 182 if (tb[IPSET_ATTR_IP_TO]) { 183 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); 184 if (ret) 185 return ret; 186 if (ip_to < ip) 187 swap(ip, ip_to); 188 if (ip + UINT_MAX == ip_to) 189 return -IPSET_ERR_HASH_RANGE; 190 } 191 ipn = ip; 192 do { 193 ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr); 194 n++; 195 } while (ipn++ < ip_to); 196 197 if (n > IPSET_MAX_RANGE) 198 return -ERANGE; 199 200 if (retried) 201 ip = ntohl(h->next.ip); 202 do { 203 e.ip = htonl(ip); 204 ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr); 205 ret = adtfn(set, &e, &ext, &ext, flags); 206 if (ret && !ip_set_eexist(ret, flags)) 207 return ret; 208 209 ret = 0; 210 } while (ip++ < ip_to); 211 return ret; 212 } 213 214 /* IPv6 variant */ 215 216 struct hash_net6_elem { 217 union nf_inet_addr ip; 218 u16 padding0; 219 u8 nomatch; 220 u8 cidr; 221 }; 222 223 /* Common functions */ 224 225 static bool 226 hash_net6_data_equal(const struct hash_net6_elem *ip1, 227 const struct hash_net6_elem *ip2, 228 u32 *multi) 229 { 230 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && 231 ip1->cidr == ip2->cidr; 232 } 233 234 static int 235 hash_net6_do_data_match(const struct hash_net6_elem *elem) 236 { 237 return elem->nomatch ? -ENOTEMPTY : 1; 238 } 239 240 static void 241 hash_net6_data_set_flags(struct hash_net6_elem *elem, u32 flags) 242 { 243 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH; 244 } 245 246 static void 247 hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags) 248 { 249 swap(*flags, elem->nomatch); 250 } 251 252 static void 253 hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr) 254 { 255 ip6_netmask(&elem->ip, cidr); 256 elem->cidr = cidr; 257 } 258 259 static bool 260 hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) 261 { 262 u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; 263 264 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || 265 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) || 266 (flags && 267 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) 268 goto nla_put_failure; 269 return false; 270 271 nla_put_failure: 272 return true; 273 } 274 275 static void 276 hash_net6_data_next(struct hash_net6_elem *next, 277 const struct hash_net6_elem *d) 278 { 279 } 280 281 #undef MTYPE 282 #undef HOST_MASK 283 284 #define MTYPE hash_net6 285 #define HOST_MASK 128 286 #define IP_SET_EMIT_CREATE 287 #include "ip_set_hash_gen.h" 288 289 static int 290 hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, 291 const struct xt_action_param *par, 292 enum ipset_adt adt, struct ip_set_adt_opt *opt) 293 { 294 const struct hash_net6 *h = set->data; 295 ipset_adtfn adtfn = set->variant->adt[adt]; 296 struct hash_net6_elem e = { 297 .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), 298 }; 299 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 300 301 if (e.cidr == 0) 302 return -EINVAL; 303 if (adt == IPSET_TEST) 304 e.cidr = HOST_MASK; 305 306 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 307 ip6_netmask(&e.ip, e.cidr); 308 309 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 310 } 311 312 static int 313 hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], 314 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 315 { 316 ipset_adtfn adtfn = set->variant->adt[adt]; 317 struct hash_net6_elem e = { .cidr = HOST_MASK }; 318 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 319 int ret; 320 321 if (tb[IPSET_ATTR_LINENO]) 322 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 323 324 if (unlikely(!tb[IPSET_ATTR_IP] || 325 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) 326 return -IPSET_ERR_PROTOCOL; 327 if (unlikely(tb[IPSET_ATTR_IP_TO])) 328 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; 329 330 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip); 331 if (ret) 332 return ret; 333 334 ret = ip_set_get_extensions(set, tb, &ext); 335 if (ret) 336 return ret; 337 338 if (tb[IPSET_ATTR_CIDR]) { 339 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 340 if (!e.cidr || e.cidr > HOST_MASK) 341 return -IPSET_ERR_INVALID_CIDR; 342 } 343 344 ip6_netmask(&e.ip, e.cidr); 345 346 if (tb[IPSET_ATTR_CADT_FLAGS]) { 347 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); 348 349 if (cadt_flags & IPSET_FLAG_NOMATCH) 350 flags |= (IPSET_FLAG_NOMATCH << 16); 351 } 352 353 ret = adtfn(set, &e, &ext, &ext, flags); 354 355 return ip_set_enomatch(ret, flags, adt, set) ? -ret : 356 ip_set_eexist(ret, flags) ? 0 : ret; 357 } 358 359 static struct ip_set_type hash_net_type __read_mostly = { 360 .name = "hash:net", 361 .protocol = IPSET_PROTOCOL, 362 .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH, 363 .dimension = IPSET_DIM_ONE, 364 .family = NFPROTO_UNSPEC, 365 .revision_min = IPSET_TYPE_REV_MIN, 366 .revision_max = IPSET_TYPE_REV_MAX, 367 .create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE, 368 .create = hash_net_create, 369 .create_policy = { 370 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, 371 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, 372 [IPSET_ATTR_INITVAL] = { .type = NLA_U32 }, 373 [IPSET_ATTR_BUCKETSIZE] = { .type = NLA_U8 }, 374 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, 375 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 376 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 377 }, 378 .adt_policy = { 379 [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 380 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 381 [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 382 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 383 [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 384 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 385 [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 386 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 387 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING, 388 .len = IPSET_MAX_COMMENT_SIZE }, 389 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, 390 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, 391 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, 392 }, 393 .me = THIS_MODULE, 394 }; 395 396 static int __init 397 hash_net_init(void) 398 { 399 return ip_set_type_register(&hash_net_type); 400 } 401 402 static void __exit 403 hash_net_fini(void) 404 { 405 rcu_barrier(); 406 ip_set_type_unregister(&hash_net_type); 407 } 408 409 module_init(hash_net_init); 410 module_exit(hash_net_fini); 411
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.