Loading net/netfilter/ipset/ip_set_hash_ip.c +69 −237 Original line number Diff line number Diff line /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as Loading @@ -21,7 +21,6 @@ #include <linux/netfilter.h> #include <linux/netfilter/ipset/pfxlen.h> #include <linux/netfilter/ipset/ip_set.h> #include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_hash.h> #define REVISION_MIN 0 Loading @@ -33,58 +32,36 @@ IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX); MODULE_ALIAS("ip_set_hash:ip"); /* Type specific function prefix */ #define TYPE hash_ip static bool hash_ip_same_set(const struct ip_set *a, const struct ip_set *b); #define hash_ip4_same_set hash_ip_same_set #define hash_ip6_same_set hash_ip_same_set #define HTYPE hash_ip #define IP_SET_HASH_WITH_NETMASK /* The type variant functions: IPv4 */ /* IPv4 variants */ /* Member elements without timeout */ /* Member elements */ struct hash_ip4_elem { /* Zero valued IP addresses cannot be stored */ __be32 ip; }; /* Member elements with timeout support */ struct hash_ip4_telem { struct hash_ip4t_elem { __be32 ip; unsigned long timeout; }; static inline bool hash_ip4_data_equal(const struct hash_ip4_elem *ip1, const struct hash_ip4_elem *ip2, u32 *multi) { return ip1->ip == ip2->ip; } /* Common functions */ static inline bool hash_ip4_data_isnull(const struct hash_ip4_elem *elem) { return elem->ip == 0; } static inline void hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src) { dst->ip = src->ip; } /* Zero valued IP addresses cannot be stored */ static inline void hash_ip4_data_zero_out(struct hash_ip4_elem *elem) hash_ip4_data_equal(const struct hash_ip4_elem *e1, const struct hash_ip4_elem *e2, u32 *multi) { elem->ip = 0; return e1->ip == e2->ip; } static inline bool hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data) hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *e) { if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip)) if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, e->ip)) goto nla_put_failure; return 0; Loading @@ -92,41 +69,26 @@ nla_put_failure: return 1; } static bool hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data) static inline void hash_ip4_data_next(struct hash_ip4_elem *next, const struct hash_ip4_elem *e) { const struct hash_ip4_telem *tdata = (const struct hash_ip4_telem *)data; if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) || nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout)))) goto nla_put_failure; return 0; nla_put_failure: return 1; next->ip = e->ip; } #define IP_SET_HASH_WITH_NETMASK #define MTYPE hash_ip4 #define PF 4 #define HOST_MASK 32 #include <linux/netfilter/ipset/ip_set_ahash.h> static inline void hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d) { h->next.ip = d->ip; } #include "ip_set_hash_gen.h" static int hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, enum ipset_adt adt, const struct ip_set_adt_opt *opt) enum ipset_adt adt, struct ip_set_adt_opt *opt) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ip4_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); __be32 ip; ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip); Loading @@ -134,17 +96,19 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, if (ip == 0) return -EINVAL; return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags); e.ip = ip; return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); } static int hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; u32 ip, ip_to, hosts, timeout = h->timeout; __be32 nip; struct hash_ip4_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_UEXT(h); u32 ip, ip_to, hosts; int ret = 0; if (unlikely(!tb[IPSET_ATTR_IP] || Loading @@ -154,23 +118,18 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || ip_set_get_extensions(set, tb, &ext); if (ret) return ret; ip &= ip_set_hostmask(h->netmask); if (tb[IPSET_ATTR_TIMEOUT]) { if (!with_timeout(h->timeout)) return -IPSET_ERR_TIMEOUT; timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } if (adt == IPSET_TEST) { nip = htonl(ip); if (nip == 0) e.ip = htonl(ip); if (e.ip == 0) return -IPSET_ERR_HASH_ELEM; return adtfn(set, &nip, timeout, flags); return adtfn(set, &e, &ext, &ext, flags); } ip_to = ip; Loading @@ -193,10 +152,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (retried) ip = ntohl(h->next.ip); for (; !before(ip_to, ip); ip += hosts) { nip = htonl(ip); if (nip == 0) e.ip = htonl(ip); if (e.ip == 0) return -IPSET_ERR_HASH_ELEM; ret = adtfn(set, &nip, timeout, flags); ret = adtfn(set, &e, &ext, &ext, flags); if (ret && !ip_set_eexist(ret, flags)) return ret; Loading @@ -206,29 +165,20 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], return ret; } static bool hash_ip_same_set(const struct ip_set *a, const struct ip_set *b) { const struct ip_set_hash *x = a->data; const struct ip_set_hash *y = b->data; /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout && x->netmask == y->netmask; } /* The type variant functions: IPv6 */ /* IPv6 variants */ /* Member elements */ struct hash_ip6_elem { union nf_inet_addr ip; }; struct hash_ip6_telem { struct hash_ip6t_elem { union nf_inet_addr ip; unsigned long timeout; }; /* Common functions */ static inline bool hash_ip6_data_equal(const struct hash_ip6_elem *ip1, const struct hash_ip6_elem *ip2, Loading @@ -237,28 +187,16 @@ hash_ip6_data_equal(const struct hash_ip6_elem *ip1, return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6); } static inline bool hash_ip6_data_isnull(const struct hash_ip6_elem *elem) { return ipv6_addr_any(&elem->ip.in6); } static inline void hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src) { dst->ip.in6 = src->ip.in6; } static inline void hash_ip6_data_zero_out(struct hash_ip6_elem *elem) hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix) { ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0); ip6_netmask(ip, prefix); } static bool hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data) hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e) { if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6)) if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6)) goto nla_put_failure; return 0; Loading @@ -266,65 +204,49 @@ nla_put_failure: return 1; } static bool hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data) static inline void hash_ip6_data_next(struct hash_ip4_elem *next, const struct hash_ip6_elem *e) { const struct hash_ip6_telem *e = (const struct hash_ip6_telem *)data; if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) || nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout)))) goto nla_put_failure; return 0; nla_put_failure: return 1; } #undef MTYPE #undef PF #undef HOST_MASK #undef HKEY_DATALEN #define MTYPE hash_ip6 #define PF 6 #define HOST_MASK 128 #include <linux/netfilter/ipset/ip_set_ahash.h> static inline void hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d) { } #define IP_SET_EMIT_CREATE #include "ip_set_hash_gen.h" static int hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, enum ipset_adt adt, const struct ip_set_adt_opt *opt) enum ipset_adt adt, struct ip_set_adt_opt *opt) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; union nf_inet_addr ip; struct hash_ip6_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6); ip6_netmask(&ip, h->netmask); if (ipv6_addr_any(&ip.in6)) ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); hash_ip6_netmask(&e.ip, h->netmask); if (ipv6_addr_any(&e.ip.in6)) return -EINVAL; return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); } static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, }; static int hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; union nf_inet_addr ip; u32 timeout = h->timeout; struct hash_ip6_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_UEXT(h); int ret; if (unlikely(!tb[IPSET_ATTR_IP] || Loading @@ -336,110 +258,20 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || ip_set_get_extensions(set, tb, &ext); if (ret) return ret; ip6_netmask(&ip, h->netmask); if (ipv6_addr_any(&ip.in6)) hash_ip6_netmask(&e.ip, h->netmask); if (ipv6_addr_any(&e.ip.in6)) return -IPSET_ERR_HASH_ELEM; if (tb[IPSET_ATTR_TIMEOUT]) { if (!with_timeout(h->timeout)) return -IPSET_ERR_TIMEOUT; timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } ret = adtfn(set, &ip, timeout, flags); ret = adtfn(set, &e, &ext, &ext, flags); return ip_set_eexist(ret, flags) ? 0 : ret; } /* Create hash:ip type of sets */ static int hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 netmask, hbits; size_t hsize; struct ip_set_hash *h; if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; netmask = set->family == NFPROTO_IPV4 ? 32 : 128; pr_debug("Create set %s with family %s\n", set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6"); if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_HASHSIZE]) { hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); if (hashsize < IPSET_MIMINAL_HASHSIZE) hashsize = IPSET_MIMINAL_HASHSIZE; } if (tb[IPSET_ATTR_MAXELEM]) maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]); if (tb[IPSET_ATTR_NETMASK]) { netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); if ((set->family == NFPROTO_IPV4 && netmask > 32) || (set->family == NFPROTO_IPV6 && netmask > 128) || netmask == 0) return -IPSET_ERR_INVALID_NETMASK; } h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; h->maxelem = maxelem; h->netmask = netmask; get_random_bytes(&h->initval, sizeof(h->initval)); h->timeout = IPSET_NO_TIMEOUT; hbits = htable_bits(hashsize); hsize = htable_size(hbits); if (hsize == 0) { kfree(h); return -ENOMEM; } h->table = ip_set_alloc(hsize); if (!h->table) { kfree(h); return -ENOMEM; } h->table->htable_bits = hbits; set->data = h; if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); set->variant = set->family == NFPROTO_IPV4 ? &hash_ip4_tvariant : &hash_ip6_tvariant; if (set->family == NFPROTO_IPV4) hash_ip4_gc_init(set); else hash_ip6_gc_init(set); } else { set->variant = set->family == NFPROTO_IPV4 ? &hash_ip4_variant : &hash_ip6_variant; } pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", set->name, jhash_size(h->table->htable_bits), h->table->htable_bits, h->maxelem, set->data, h->table); return 0; } static struct ip_set_type hash_ip_type __read_mostly = { .name = "hash:ip", .protocol = IPSET_PROTOCOL, Loading Loading
net/netfilter/ipset/ip_set_hash_ip.c +69 −237 Original line number Diff line number Diff line /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as Loading @@ -21,7 +21,6 @@ #include <linux/netfilter.h> #include <linux/netfilter/ipset/pfxlen.h> #include <linux/netfilter/ipset/ip_set.h> #include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_hash.h> #define REVISION_MIN 0 Loading @@ -33,58 +32,36 @@ IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX); MODULE_ALIAS("ip_set_hash:ip"); /* Type specific function prefix */ #define TYPE hash_ip static bool hash_ip_same_set(const struct ip_set *a, const struct ip_set *b); #define hash_ip4_same_set hash_ip_same_set #define hash_ip6_same_set hash_ip_same_set #define HTYPE hash_ip #define IP_SET_HASH_WITH_NETMASK /* The type variant functions: IPv4 */ /* IPv4 variants */ /* Member elements without timeout */ /* Member elements */ struct hash_ip4_elem { /* Zero valued IP addresses cannot be stored */ __be32 ip; }; /* Member elements with timeout support */ struct hash_ip4_telem { struct hash_ip4t_elem { __be32 ip; unsigned long timeout; }; static inline bool hash_ip4_data_equal(const struct hash_ip4_elem *ip1, const struct hash_ip4_elem *ip2, u32 *multi) { return ip1->ip == ip2->ip; } /* Common functions */ static inline bool hash_ip4_data_isnull(const struct hash_ip4_elem *elem) { return elem->ip == 0; } static inline void hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src) { dst->ip = src->ip; } /* Zero valued IP addresses cannot be stored */ static inline void hash_ip4_data_zero_out(struct hash_ip4_elem *elem) hash_ip4_data_equal(const struct hash_ip4_elem *e1, const struct hash_ip4_elem *e2, u32 *multi) { elem->ip = 0; return e1->ip == e2->ip; } static inline bool hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data) hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *e) { if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip)) if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, e->ip)) goto nla_put_failure; return 0; Loading @@ -92,41 +69,26 @@ nla_put_failure: return 1; } static bool hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data) static inline void hash_ip4_data_next(struct hash_ip4_elem *next, const struct hash_ip4_elem *e) { const struct hash_ip4_telem *tdata = (const struct hash_ip4_telem *)data; if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) || nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout)))) goto nla_put_failure; return 0; nla_put_failure: return 1; next->ip = e->ip; } #define IP_SET_HASH_WITH_NETMASK #define MTYPE hash_ip4 #define PF 4 #define HOST_MASK 32 #include <linux/netfilter/ipset/ip_set_ahash.h> static inline void hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d) { h->next.ip = d->ip; } #include "ip_set_hash_gen.h" static int hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, enum ipset_adt adt, const struct ip_set_adt_opt *opt) enum ipset_adt adt, struct ip_set_adt_opt *opt) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ip4_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); __be32 ip; ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip); Loading @@ -134,17 +96,19 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, if (ip == 0) return -EINVAL; return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags); e.ip = ip; return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); } static int hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; u32 ip, ip_to, hosts, timeout = h->timeout; __be32 nip; struct hash_ip4_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_UEXT(h); u32 ip, ip_to, hosts; int ret = 0; if (unlikely(!tb[IPSET_ATTR_IP] || Loading @@ -154,23 +118,18 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || ip_set_get_extensions(set, tb, &ext); if (ret) return ret; ip &= ip_set_hostmask(h->netmask); if (tb[IPSET_ATTR_TIMEOUT]) { if (!with_timeout(h->timeout)) return -IPSET_ERR_TIMEOUT; timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } if (adt == IPSET_TEST) { nip = htonl(ip); if (nip == 0) e.ip = htonl(ip); if (e.ip == 0) return -IPSET_ERR_HASH_ELEM; return adtfn(set, &nip, timeout, flags); return adtfn(set, &e, &ext, &ext, flags); } ip_to = ip; Loading @@ -193,10 +152,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], if (retried) ip = ntohl(h->next.ip); for (; !before(ip_to, ip); ip += hosts) { nip = htonl(ip); if (nip == 0) e.ip = htonl(ip); if (e.ip == 0) return -IPSET_ERR_HASH_ELEM; ret = adtfn(set, &nip, timeout, flags); ret = adtfn(set, &e, &ext, &ext, flags); if (ret && !ip_set_eexist(ret, flags)) return ret; Loading @@ -206,29 +165,20 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], return ret; } static bool hash_ip_same_set(const struct ip_set *a, const struct ip_set *b) { const struct ip_set_hash *x = a->data; const struct ip_set_hash *y = b->data; /* Resizing changes htable_bits, so we ignore it */ return x->maxelem == y->maxelem && x->timeout == y->timeout && x->netmask == y->netmask; } /* The type variant functions: IPv6 */ /* IPv6 variants */ /* Member elements */ struct hash_ip6_elem { union nf_inet_addr ip; }; struct hash_ip6_telem { struct hash_ip6t_elem { union nf_inet_addr ip; unsigned long timeout; }; /* Common functions */ static inline bool hash_ip6_data_equal(const struct hash_ip6_elem *ip1, const struct hash_ip6_elem *ip2, Loading @@ -237,28 +187,16 @@ hash_ip6_data_equal(const struct hash_ip6_elem *ip1, return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6); } static inline bool hash_ip6_data_isnull(const struct hash_ip6_elem *elem) { return ipv6_addr_any(&elem->ip.in6); } static inline void hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src) { dst->ip.in6 = src->ip.in6; } static inline void hash_ip6_data_zero_out(struct hash_ip6_elem *elem) hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix) { ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0); ip6_netmask(ip, prefix); } static bool hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data) hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e) { if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6)) if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6)) goto nla_put_failure; return 0; Loading @@ -266,65 +204,49 @@ nla_put_failure: return 1; } static bool hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data) static inline void hash_ip6_data_next(struct hash_ip4_elem *next, const struct hash_ip6_elem *e) { const struct hash_ip6_telem *e = (const struct hash_ip6_telem *)data; if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) || nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout)))) goto nla_put_failure; return 0; nla_put_failure: return 1; } #undef MTYPE #undef PF #undef HOST_MASK #undef HKEY_DATALEN #define MTYPE hash_ip6 #define PF 6 #define HOST_MASK 128 #include <linux/netfilter/ipset/ip_set_ahash.h> static inline void hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d) { } #define IP_SET_EMIT_CREATE #include "ip_set_hash_gen.h" static int hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, enum ipset_adt adt, const struct ip_set_adt_opt *opt) enum ipset_adt adt, struct ip_set_adt_opt *opt) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; union nf_inet_addr ip; struct hash_ip6_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6); ip6_netmask(&ip, h->netmask); if (ipv6_addr_any(&ip.in6)) ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); hash_ip6_netmask(&e.ip, h->netmask); if (ipv6_addr_any(&e.ip.in6)) return -EINVAL; return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags); return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); } static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { [IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, }; static int hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { const struct ip_set_hash *h = set->data; const struct hash_ip *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; union nf_inet_addr ip; u32 timeout = h->timeout; struct hash_ip6_elem e = {}; struct ip_set_ext ext = IP_SET_INIT_UEXT(h); int ret; if (unlikely(!tb[IPSET_ATTR_IP] || Loading @@ -336,110 +258,20 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || ip_set_get_extensions(set, tb, &ext); if (ret) return ret; ip6_netmask(&ip, h->netmask); if (ipv6_addr_any(&ip.in6)) hash_ip6_netmask(&e.ip, h->netmask); if (ipv6_addr_any(&e.ip.in6)) return -IPSET_ERR_HASH_ELEM; if (tb[IPSET_ATTR_TIMEOUT]) { if (!with_timeout(h->timeout)) return -IPSET_ERR_TIMEOUT; timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } ret = adtfn(set, &ip, timeout, flags); ret = adtfn(set, &e, &ext, &ext, flags); return ip_set_eexist(ret, flags) ? 0 : ret; } /* Create hash:ip type of sets */ static int hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 netmask, hbits; size_t hsize; struct ip_set_hash *h; if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) return -IPSET_ERR_INVALID_FAMILY; netmask = set->family == NFPROTO_IPV4 ? 32 : 128; pr_debug("Create set %s with family %s\n", set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6"); if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_HASHSIZE]) { hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); if (hashsize < IPSET_MIMINAL_HASHSIZE) hashsize = IPSET_MIMINAL_HASHSIZE; } if (tb[IPSET_ATTR_MAXELEM]) maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]); if (tb[IPSET_ATTR_NETMASK]) { netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); if ((set->family == NFPROTO_IPV4 && netmask > 32) || (set->family == NFPROTO_IPV6 && netmask > 128) || netmask == 0) return -IPSET_ERR_INVALID_NETMASK; } h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; h->maxelem = maxelem; h->netmask = netmask; get_random_bytes(&h->initval, sizeof(h->initval)); h->timeout = IPSET_NO_TIMEOUT; hbits = htable_bits(hashsize); hsize = htable_size(hbits); if (hsize == 0) { kfree(h); return -ENOMEM; } h->table = ip_set_alloc(hsize); if (!h->table) { kfree(h); return -ENOMEM; } h->table->htable_bits = hbits; set->data = h; if (tb[IPSET_ATTR_TIMEOUT]) { h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); set->variant = set->family == NFPROTO_IPV4 ? &hash_ip4_tvariant : &hash_ip6_tvariant; if (set->family == NFPROTO_IPV4) hash_ip4_gc_init(set); else hash_ip6_gc_init(set); } else { set->variant = set->family == NFPROTO_IPV4 ? &hash_ip4_variant : &hash_ip6_variant; } pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", set->name, jhash_size(h->table->htable_bits), h->table->htable_bits, h->maxelem, set->data, h->table); return 0; } static struct ip_set_type hash_ip_type __read_mostly = { .name = "hash:ip", .protocol = IPSET_PROTOCOL, Loading