ipset: update to 5.4.1

This commit is contained in:
Jan Engelhardt
2011-01-22 15:55:08 +01:00
parent 3141b2ff86
commit 1b53724a61
22 changed files with 982 additions and 961 deletions

View File

@@ -9,6 +9,10 @@ Enhancements:
- Update to ipset 5.3 - Update to ipset 5.3
* make IPv4 and IPv6 address handling similar * make IPv4 and IPv6 address handling similar
* show correct line numbers in restore output for parser errors * show correct line numbers in restore output for parser errors
- Update to ipset 5.4
* fixed ICMP and ICMPv6 handling
* fixed trailing whitespaces and pr_* messages
* fixed module loading at create/header commands
v1.32 (2011-01-04) v1.32 (2011-01-04)

View File

@@ -6,6 +6,6 @@ obj-m += ip_set_bitmap_port.o ip_set_hash_ip.o ip_set_hash_ipport.o
obj-m += ip_set_hash_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o obj-m += ip_set_hash_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o
obj-m += ip_set_hash_netport.o ip_set_list_set.o obj-m += ip_set_hash_netport.o ip_set_list_set.o
ip_set-y := ip_set_core.o pfxlen.o ip_set-y := ip_set_core.o ip_set_getport.o pfxlen.o
EXTRA_CFLAGS += -DLCONFIG_IP_SET_MAX=256 EXTRA_CFLAGS += -DLCONFIG_IP_SET_MAX=256

View File

@@ -11,6 +11,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/netlink.h>
/* The protocol version */ /* The protocol version */
#define IPSET_PROTOCOL 5 #define IPSET_PROTOCOL 5
@@ -292,7 +294,7 @@ struct ip_set {
/* References to the set */ /* References to the set */
atomic_t ref; atomic_t ref;
/* The core set type */ /* The core set type */
const struct ip_set_type *type; struct ip_set_type *type;
/* The type variant doing the real job */ /* The type variant doing the real job */
const struct ip_set_type_variant *variant; const struct ip_set_type_variant *variant;
/* The actual INET family of the set */ /* The actual INET family of the set */
@@ -317,37 +319,22 @@ extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags); u8 family, u8 dim, u8 flags);
/* Allocate members */ /* Utility functions */
static inline void * extern void * ip_set_alloc(size_t size, gfp_t gfp_mask);
ip_set_alloc(size_t size, gfp_t gfp_mask) extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
static inline int
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
{ {
void *members = NULL; __be32 ip;
int ret = ip_set_get_ipaddr4(nla, &ip);
if (size < KMALLOC_MAX_SIZE)
members = kzalloc(size, gfp_mask | __GFP_NOWARN); if (ret)
return ret;
if (members) { *ipaddr = ntohl(ip);
pr_debug("%p: allocated with kmalloc", members); return 0;
return members;
}
members = __vmalloc(size, gfp_mask | __GFP_ZERO, PAGE_KERNEL);
if (!members)
return NULL;
pr_debug("%p: allocated with vmalloc", members);
return members;
}
static inline void
ip_set_free(void *members)
{
pr_debug("%p: free with %s", members,
is_vmalloc_addr(members) ? "vfree" : "kfree");
if (is_vmalloc_addr(members))
vfree(members);
else
kfree(members);
} }
/* Ignore IPSET_ERR_EXIST errors if asked to do so? */ /* Ignore IPSET_ERR_EXIST errors if asked to do so? */
@@ -357,92 +344,47 @@ ip_set_eexist(int ret, u32 flags)
return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST); return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST);
} }
/* Check the NLA_F_NET_BYTEORDER flag */
static inline bool
ip_set_attr_netorder(struct nlattr *tb[], int type)
{
return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER);
}
static inline bool
ip_set_optattr_netorder(struct nlattr *tb[], int type)
{
return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER);
}
/* Useful converters */ /* Useful converters */
static inline u32 static inline u32
ip_set_get_h32(const struct nlattr *attr) ip_set_get_h32(const struct nlattr *attr)
{ {
u32 value = nla_get_u32(attr); return ntohl(nla_get_be32(attr));
return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohl(value) : value;
} }
static inline u16 static inline u16
ip_set_get_h16(const struct nlattr *attr) ip_set_get_h16(const struct nlattr *attr)
{ {
u16 value = nla_get_u16(attr); return ntohs(nla_get_be16(attr));
return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohs(value) : value;
}
static inline u32
ip_set_get_n32(const struct nlattr *attr)
{
u32 value = nla_get_u32(attr);
return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htonl(value);
}
static inline u16
ip_set_get_n16(const struct nlattr *attr)
{
u16 value = nla_get_u16(attr);
return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htons(value);
}
static const struct nla_policy ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] = {
[IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 },
[IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY,
.len = sizeof(struct in6_addr) },
};
static inline int
ip_set_get_ipaddr4(struct nlattr *attr[], int type, u32 *ipaddr)
{
struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {};
if (!attr[type])
return -IPSET_ERR_PROTOCOL;
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX,
nla_data(attr[type]), nla_len(attr[type]),
ipaddr_policy))
return -IPSET_ERR_PROTOCOL;
if (!tb[IPSET_ATTR_IPADDR_IPV4])
return -IPSET_ERR_IPADDR_IPV4;
*ipaddr = ip_set_get_n32(tb[IPSET_ATTR_IPADDR_IPV4]);
return 0;
}
static inline int
ip_set_get_ipaddr6(struct nlattr *attr[], int type, union nf_inet_addr *ipaddr)
{
struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {};
if (!attr[type])
return -IPSET_ERR_PROTOCOL;
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX,
nla_data(attr[type]), nla_len(attr[type]),
ipaddr_policy))
return -IPSET_ERR_PROTOCOL;
if (!tb[IPSET_ATTR_IPADDR_IPV6])
return -IPSET_ERR_IPADDR_IPV6;
memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]),
sizeof(struct in6_addr));
return 0;
} }
#define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED) #define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED)
#define ipset_nest_end(skb, start) nla_nest_end(skb, start) #define ipset_nest_end(skb, start) nla_nest_end(skb, start)
#define NLA_PUT_NET32(skb, type, value) \ #ifndef NLA_PUT_NET16
NLA_PUT_BE32(skb, type | NLA_F_NET_BYTEORDER, value) #define NLA_PUT_NET16(skb, attrtype, value) \
NLA_PUT_BE16(skb, attrtype | NLA_F_NET_BYTEORDER, value)
#define NLA_PUT_NET16(skb, type, value) \ #endif
NLA_PUT_BE16(skb, type | NLA_F_NET_BYTEORDER, value) #ifndef NLA_PUT_NET32
#define NLA_PUT_NET32(skb, attrtype, value) \
NLA_PUT_BE32(skb, attrtype | NLA_F_NET_BYTEORDER, value)
#endif
#ifndef NLA_PUT_NET64
#define NLA_PUT_NET64(skb, attrtype, value) \
NLA_PUT_BE64(skb, attrtype | NLA_F_NET_BYTEORDER, value)
#endif
#define NLA_PUT_IPADDR4(skb, type, ipaddr) \ #define NLA_PUT_IPADDR4(skb, type, ipaddr) \
do { \ do { \
@@ -466,14 +408,14 @@ do { \
} while (0) } while (0)
/* Get address from skbuff */ /* Get address from skbuff */
static inline u32 static inline __be32
ip4addr(const struct sk_buff *skb, bool src) ip4addr(const struct sk_buff *skb, bool src)
{ {
return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
} }
static inline void static inline void
ip4addrptr(const struct sk_buff *skb, bool src, u32 *addr) ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr)
{ {
*addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr; *addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
} }

View File

@@ -63,7 +63,7 @@ struct ip_set_hash {
}; };
/* Compute htable_bits from the user input parameter hashsize */ /* Compute htable_bits from the user input parameter hashsize */
static inline u8 static u8
htable_bits(u32 hashsize) htable_bits(u32 hashsize)
{ {
/* Assume that hashsize == 2^htable_bits */ /* Assume that hashsize == 2^htable_bits */
@@ -81,14 +81,14 @@ htable_bits(u32 hashsize)
/* Network cidr size book keeping when the hash stores different /* Network cidr size book keeping when the hash stores different
* sized networks */ * sized networks */
static inline void static void
add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask) add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
{ {
u8 i; u8 i;
++h->nets[cidr-1].nets; ++h->nets[cidr-1].nets;
pr_debug("add_cidr added %u: %u", cidr, h->nets[cidr-1].nets); pr_debug("add_cidr added %u: %u\n", cidr, h->nets[cidr-1].nets);
if (h->nets[cidr-1].nets > 1) if (h->nets[cidr-1].nets > 1)
return; return;
@@ -103,14 +103,14 @@ add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
h->nets[i].cidr = cidr; h->nets[i].cidr = cidr;
} }
static inline void static void
del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask) del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
{ {
u8 i; u8 i;
--h->nets[cidr-1].nets; --h->nets[cidr-1].nets;
pr_debug("del_cidr deleted %u: %u", cidr, h->nets[cidr-1].nets); pr_debug("del_cidr deleted %u: %u\n", cidr, h->nets[cidr-1].nets);
if (h->nets[cidr-1].nets != 0) if (h->nets[cidr-1].nets != 0)
return; return;
@@ -142,7 +142,7 @@ ahash_destroy(struct htable *t)
} }
/* Calculate the actual memory size of the set data */ /* Calculate the actual memory size of the set data */
static inline size_t static size_t
ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 host_mask) ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 host_mask)
{ {
u32 i; u32 i;
@@ -340,7 +340,7 @@ retry:
/* Give time to other readers of the set */ /* Give time to other readers of the set */
synchronize_rcu_bh(); synchronize_rcu_bh();
pr_debug("set %s resized from %u (%p) to %u (%p)", set->name, pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
orig->htable_bits, orig, t->htable_bits, t); orig->htable_bits, orig, t->htable_bits, t);
ahash_destroy(orig); ahash_destroy(orig);
@@ -436,7 +436,7 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout)
/* Special test function which takes into account the different network /* Special test function which takes into account the different network
* sizes added to the set */ * sizes added to the set */
static inline int static int
type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
{ {
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
@@ -447,7 +447,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
u32 key; u32 key;
u8 host_mask = SET_HOST_MASK(set->family); u8 host_mask = SET_HOST_MASK(set->family);
pr_debug("test by nets"); pr_debug("test by nets\n");
for (; j < host_mask && h->nets[j].cidr; j++) { for (; j < host_mask && h->nets[j].cidr; j++) {
type_pf_data_netmask(d, h->nets[j].cidr); type_pf_data_netmask(d, h->nets[j].cidr);
key = HKEY(d, h->initval, t->htable_bits); key = HKEY(d, h->initval, t->htable_bits);
@@ -546,14 +546,14 @@ type_pf_list(const struct ip_set *set,
atd = ipset_nest_start(skb, IPSET_ATTR_ADT); atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd) if (!atd)
return -EFAULT; return -EFAULT;
pr_debug("list hash set %s", set->name); pr_debug("list hash set %s\n", set->name);
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
incomplete = skb_tail_pointer(skb); incomplete = skb_tail_pointer(skb);
n = hbucket(t, cb->args[2]); n = hbucket(t, cb->args[2]);
pr_debug("cb->args[2]: %lu, t %p n %p", cb->args[2], t, n); pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
for (i = 0; i < n->pos; i++) { for (i = 0; i < n->pos; i++) {
data = ahash_data(n, i); data = ahash_data(n, i);
pr_debug("list hash %lu hbucket %p i %u, data %p", pr_debug("list hash %lu hbucket %p i %u, data %p\n",
cb->args[2], n, i, data); cb->args[2], n, i, data);
nested = ipset_nest_start(skb, IPSET_ATTR_DATA); nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) { if (!nested) {
@@ -686,7 +686,7 @@ type_pf_expire(struct ip_set_hash *h)
for (j = 0; j < n->pos; j++) { for (j = 0; j < n->pos; j++) {
data = ahash_tdata(n, j); data = ahash_tdata(n, j);
if (type_pf_data_expired(data)) { if (type_pf_data_expired(data)) {
pr_debug("expired %u/%u", i, j); pr_debug("expired %u/%u\n", i, j);
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
del_cidr(h, data->cidr, HOST_MASK); del_cidr(h, data->cidr, HOST_MASK);
#endif #endif
@@ -701,7 +701,7 @@ type_pf_expire(struct ip_set_hash *h)
if (n->pos + AHASH_INIT_SIZE < n->size) { if (n->pos + AHASH_INIT_SIZE < n->size) {
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
* sizeof(struct type_pf_telem), * sizeof(struct type_pf_telem),
GFP_KERNEL); GFP_ATOMIC);
if (!tmp) if (!tmp)
/* Still try to delete expired elements */ /* Still try to delete expired elements */
continue; continue;
@@ -807,8 +807,8 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
ret = -IPSET_ERR_EXIST; ret = -IPSET_ERR_EXIST;
goto out; goto out;
} }
} else if (j == AHASH_MAX_SIZE + 1 } else if (j == AHASH_MAX_SIZE + 1 &&
&& type_pf_data_expired(data)) type_pf_data_expired(data))
j = i; j = i;
} }
if (j != AHASH_MAX_SIZE + 1) { if (j != AHASH_MAX_SIZE + 1) {
@@ -881,7 +881,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout)
} }
#ifdef IP_SET_HASH_WITH_NETS #ifdef IP_SET_HASH_WITH_NETS
static inline int static int
type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout) type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
{ {
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
@@ -952,10 +952,10 @@ type_pf_tlist(const struct ip_set *set,
n = hbucket(t, cb->args[2]); n = hbucket(t, cb->args[2]);
for (i = 0; i < n->pos; i++) { for (i = 0; i < n->pos; i++) {
data = ahash_tdata(n, i); data = ahash_tdata(n, i);
pr_debug("list %p %u", n, i); pr_debug("list %p %u\n", n, i);
if (type_pf_data_expired(data)) if (type_pf_data_expired(data))
continue; continue;
pr_debug("do list %p %u", n, i); pr_debug("do list %p %u\n", n, i);
nested = ipset_nest_start(skb, IPSET_ATTR_DATA); nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) { if (!nested) {
if (cb->args[2] == first) { if (cb->args[2] == first) {
@@ -1008,7 +1008,7 @@ type_pf_gc(unsigned long ul_set)
struct ip_set *set = (struct ip_set *) ul_set; struct ip_set *set = (struct ip_set *) ul_set;
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
pr_debug("called"); pr_debug("called\n");
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
type_pf_expire(h); type_pf_expire(h);
write_unlock_bh(&set->lock); write_unlock_bh(&set->lock);
@@ -1017,7 +1017,7 @@ type_pf_gc(unsigned long ul_set)
add_timer(&h->gc); add_timer(&h->gc);
} }
static inline void static void
type_pf_gc_init(struct ip_set *set) type_pf_gc_init(struct ip_set *set)
{ {
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
@@ -1027,7 +1027,7 @@ type_pf_gc_init(struct ip_set *set)
h->gc.function = type_pf_gc; h->gc.function = type_pf_gc;
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
add_timer(&h->gc); add_timer(&h->gc);
pr_debug("gc initialized, run in every %u", pr_debug("gc initialized, run in every %u\n",
IPSET_GC_PERIOD(h->timeout)); IPSET_GC_PERIOD(h->timeout));
} }

View File

@@ -9,7 +9,6 @@
/* Kernel module implementing an IP set type: the bitmap:ip type */ /* Kernel module implementing an IP set type: the bitmap:ip type */
#include "ip_set_kernel.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
@@ -47,9 +46,9 @@ struct bitmap_ip {
}; };
static inline u32 static inline u32
ip_to_id(const struct bitmap_ip *map, u32 ip) ip_to_id(const struct bitmap_ip *m, u32 ip)
{ {
return ((ip & HOSTMASK(map->netmask)) - map->first_ip)/map->hosts; return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
} }
static inline int static inline int
@@ -122,13 +121,15 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
bitmap_ip_adt_policy)) bitmap_ip_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP]))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret) if (ret)
return ret; return ret;
ip = ntohl(ip);
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -142,10 +143,9 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
return bitmap_ip_test(map, ip_to_id(map, ip)); return bitmap_ip_test(map, ip_to_id(map, ip));
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
ip_to = ntohl(ip_to);
if (ip > ip_to) { if (ip > ip_to) {
swap(ip, ip_to); swap(ip, ip_to);
if (ip < map->first_ip) if (ip < map->first_ip)
@@ -156,8 +156,8 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
if (cidr > 32) if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip &= HOSTMASK(cidr); ip &= ip_set_hostmask(cidr);
ip_to = ip | ~HOSTMASK(cidr); ip_to = ip | ~ip_set_hostmask(cidr);
} else } else
ip_to = ip; ip_to = ip;
@@ -264,9 +264,9 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
const struct bitmap_ip *x = a->data; const struct bitmap_ip *x = a->data;
const struct bitmap_ip *y = b->data; const struct bitmap_ip *y = b->data;
return x->first_ip == y->first_ip return x->first_ip == y->first_ip &&
&& x->last_ip == y->last_ip x->last_ip == y->last_ip &&
&& x->netmask == y->netmask; x->netmask == y->netmask;
} }
static const struct ip_set_type_variant bitmap_ip = { static const struct ip_set_type_variant bitmap_ip = {
@@ -362,13 +362,16 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
bitmap_ip_adt_policy)) bitmap_ip_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret) if (ret)
return ret; return ret;
ip = ntohl(ip);
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -378,10 +381,9 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
ip_to_id((const struct bitmap_ip *)map, ip)); ip_to_id((const struct bitmap_ip *)map, ip));
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
ip_to = ntohl(ip_to);
if (ip > ip_to) { if (ip > ip_to) {
swap(ip, ip_to); swap(ip, ip_to);
if (ip < map->first_ip) if (ip < map->first_ip)
@@ -392,8 +394,8 @@ bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
if (cidr > 32) if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip &= HOSTMASK(cidr); ip &= ip_set_hostmask(cidr);
ip_to = ip | ~HOSTMASK(cidr); ip_to = ip | ~ip_set_hostmask(cidr);
} else } else
ip_to = ip; ip_to = ip;
@@ -511,10 +513,10 @@ bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
const struct bitmap_ip_timeout *x = a->data; const struct bitmap_ip_timeout *x = a->data;
const struct bitmap_ip_timeout *y = b->data; const struct bitmap_ip_timeout *y = b->data;
return x->first_ip == y->first_ip return x->first_ip == y->first_ip &&
&& x->last_ip == y->last_ip x->last_ip == y->last_ip &&
&& x->netmask == y->netmask x->netmask == y->netmask &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
static const struct ip_set_type_variant bitmap_ip_timeout = { static const struct ip_set_type_variant bitmap_ip_timeout = {
@@ -547,7 +549,7 @@ bitmap_ip_gc(unsigned long ul_set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static inline void static void
bitmap_ip_gc_init(struct ip_set *set) bitmap_ip_gc_init(struct ip_set *set)
{ {
struct bitmap_ip_timeout *map = set->data; struct bitmap_ip_timeout *map = set->data;
@@ -603,16 +605,18 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
bitmap_ip_create_policy)) bitmap_ip_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip); if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
if (ret) if (ret)
return ret; return ret;
first_ip = ntohl(first_ip);
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
if (ret) if (ret)
return ret; return ret;
last_ip = htonl(last_ip);
if (first_ip > last_ip) { if (first_ip > last_ip) {
u32 tmp = first_ip; u32 tmp = first_ip;
@@ -624,7 +628,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
if (cidr >= 32) if (cidr >= 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
last_ip = first_ip | ~HOSTMASK(cidr); last_ip = first_ip | ~ip_set_hostmask(cidr);
} else } else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -634,8 +638,8 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
if (netmask > 32) if (netmask > 32)
return -IPSET_ERR_INVALID_NETMASK; return -IPSET_ERR_INVALID_NETMASK;
first_ip &= HOSTMASK(netmask); first_ip &= ip_set_hostmask(netmask);
last_ip |= ~HOSTMASK(netmask); last_ip |= ~ip_set_hostmask(netmask);
} }
if (netmask == 32) { if (netmask == 32) {
@@ -647,18 +651,18 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
mask = range_to_mask(first_ip, last_ip, &mask_bits); mask = range_to_mask(first_ip, last_ip, &mask_bits);
if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) ||
|| netmask <= mask_bits) netmask <= mask_bits)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
pr_debug("mask_bits %u, netmask %u", mask_bits, netmask); pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
hosts = 2 << (32 - netmask - 1); hosts = 2 << (32 - netmask - 1);
elements = 2 << (netmask - mask_bits - 1); elements = 2 << (netmask - mask_bits - 1);
} }
if (elements > IPSET_BITMAP_MAX_RANGE + 1) if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE; return -IPSET_ERR_BITMAP_RANGE_SIZE;
pr_debug("hosts %u, elements %u", hosts, elements); pr_debug("hosts %u, elements %u\n", hosts, elements);
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
struct bitmap_ip_timeout *map; struct bitmap_ip_timeout *map;

View File

@@ -10,7 +10,6 @@
/* Kernel module implementing an IP set type: the bitmap:ip,mac type */ /* Kernel module implementing an IP set type: the bitmap:ip,mac type */
#include "ip_set_kernel.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
@@ -95,9 +94,9 @@ bitmap_expired(const struct bitmap_ipmac *map, u32 id)
static inline int static inline int
bitmap_ipmac_exist(const struct ipmac_telem *elem) bitmap_ipmac_exist(const struct ipmac_telem *elem)
{ {
return elem->match == MAC_UNSET return elem->match == MAC_UNSET ||
|| (elem->match == MAC_FILLED (elem->match == MAC_FILLED &&
&& !ip_set_timeout_expired(elem->timeout)); !ip_set_timeout_expired(elem->timeout));
} }
/* Base variant */ /* Base variant */
@@ -114,8 +113,8 @@ bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout)
/* Trigger kernel to fill out the ethernet address */ /* Trigger kernel to fill out the ethernet address */
return -EAGAIN; return -EAGAIN;
case MAC_FILLED: case MAC_FILLED:
return data->ether == NULL return data->ether == NULL ||
|| compare_ether_addr(data->ether, elem->ether) == 0; compare_ether_addr(data->ether, elem->ether) == 0;
} }
return 0; return 0;
} }
@@ -223,9 +222,9 @@ bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
/* Trigger kernel to fill out the ethernet address */ /* Trigger kernel to fill out the ethernet address */
return -EAGAIN; return -EAGAIN;
case MAC_FILLED: case MAC_FILLED:
return (data->ether == NULL return (data->ether == NULL ||
|| compare_ether_addr(data->ether, elem->ether) == 0) compare_ether_addr(data->ether, elem->ether) == 0) &&
&& !bitmap_expired(map, data->id); !bitmap_expired(map, data->id);
} }
return 0; return 0;
} }
@@ -348,8 +347,8 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
/* Backward compatibility: we don't check the second flag */ /* Backward compatibility: we don't check the second flag */
if (skb_mac_header(skb) < skb->head if (skb_mac_header(skb) < skb->head ||
|| (skb_mac_header(skb) + ETH_HLEN) > skb->data) (skb_mac_header(skb) + ETH_HLEN) > skb->data)
return -EINVAL; return -EINVAL;
data.id -= map->first_ip; data.id -= map->first_ip;
@@ -381,13 +380,16 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
bitmap_ipmac_adt_policy)) bitmap_ipmac_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.id); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &data.id);
if (ret) if (ret)
return ret; return ret;
data.id = ntohl(data.id);
if (data.id < map->first_ip || data.id > map->last_ip) if (data.id < map->first_ip || data.id > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -464,12 +466,12 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
const struct bitmap_ipmac *x = a->data; const struct bitmap_ipmac *x = a->data;
const struct bitmap_ipmac *y = b->data; const struct bitmap_ipmac *y = b->data;
return x->first_ip == y->first_ip return x->first_ip == y->first_ip &&
&& x->last_ip == y->last_ip x->last_ip == y->last_ip &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
const struct ip_set_type_variant bitmap_ipmac = { static const struct ip_set_type_variant bitmap_ipmac = {
.kadt = bitmap_ipmac_kadt, .kadt = bitmap_ipmac_kadt,
.uadt = bitmap_ipmac_uadt, .uadt = bitmap_ipmac_uadt,
.adt = { .adt = {
@@ -484,7 +486,7 @@ const struct ip_set_type_variant bitmap_ipmac = {
.same_set = bitmap_ipmac_same_set, .same_set = bitmap_ipmac_same_set,
}; };
const struct ip_set_type_variant bitmap_tipmac = { static const struct ip_set_type_variant bitmap_tipmac = {
.kadt = bitmap_ipmac_kadt, .kadt = bitmap_ipmac_kadt,
.uadt = bitmap_ipmac_uadt, .uadt = bitmap_ipmac_uadt,
.adt = { .adt = {
@@ -512,8 +514,8 @@ bitmap_ipmac_gc(unsigned long ul_set)
read_lock_bh(&set->lock); read_lock_bh(&set->lock);
for (id = 0; id <= last; id++) { for (id = 0; id <= last; id++) {
elem = bitmap_ipmac_elem(map, id); elem = bitmap_ipmac_elem(map, id);
if (elem->match == MAC_FILLED if (elem->match == MAC_FILLED &&
&& ip_set_timeout_expired(elem->timeout)) ip_set_timeout_expired(elem->timeout))
elem->match = MAC_EMPTY; elem->match = MAC_EMPTY;
} }
read_unlock_bh(&set->lock); read_unlock_bh(&set->lock);
@@ -522,7 +524,7 @@ bitmap_ipmac_gc(unsigned long ul_set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static inline void static void
bitmap_ipmac_gc_init(struct ip_set *set) bitmap_ipmac_gc_init(struct ip_set *set)
{ {
struct bitmap_ipmac *map = set->data; struct bitmap_ipmac *map = set->data;
@@ -540,6 +542,7 @@ static const struct nla_policy
bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] = { bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
}; };
@@ -574,16 +577,18 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
bitmap_ipmac_create_policy)) bitmap_ipmac_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip); if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
if (ret) if (ret)
return ret; return ret;
first_ip = ntohl(first_ip);
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
if (ret) if (ret)
return ret; return ret;
last_ip = ntohl(last_ip);
if (first_ip > last_ip) { if (first_ip > last_ip) {
u32 tmp = first_ip; u32 tmp = first_ip;
@@ -595,7 +600,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
if (cidr >= 32) if (cidr >= 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
last_ip = first_ip | ~HOSTMASK(cidr); last_ip = first_ip | ~ip_set_hostmask(cidr);
} else } else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -634,7 +639,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
return 0; return 0;
} }
struct ip_set_type bitmap_ipmac_type = { static struct ip_set_type bitmap_ipmac_type = {
.name = "bitmap:ip,mac", .name = "bitmap:ip,mac",
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC, .features = IPSET_TYPE_IP | IPSET_TYPE_MAC,

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the bitmap:port type */ /* Kernel module implementing an IP set type: the bitmap:port type */
#include "ip_set_kernel.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h> #include <linux/tcp.h>
@@ -71,12 +70,13 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags) enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{ {
struct bitmap_port *map = set->data; struct bitmap_port *map = set->data;
__be16 __port;
u16 port = 0; u16 port = 0;
if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &port)) if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
return -EINVAL; return -EINVAL;
port = ntohs(port); port = ntohs(__port);
if (port < map->first_port || port > map->last_port) if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -116,14 +116,14 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len,
bitmap_port_adt_policy)) bitmap_port_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
if (tb[IPSET_ATTR_PORT]) port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (port < map->first_port || port > map->last_port) if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -246,11 +246,11 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
const struct bitmap_port *x = a->data; const struct bitmap_port *x = a->data;
const struct bitmap_port *y = b->data; const struct bitmap_port *y = b->data;
return x->first_port == y->first_port return x->first_port == y->first_port &&
&& x->last_port == y->last_port; x->last_port == y->last_port;
} }
const struct ip_set_type_variant bitmap_port = { static const struct ip_set_type_variant bitmap_port = {
.kadt = bitmap_port_kadt, .kadt = bitmap_port_kadt,
.uadt = bitmap_port_uadt, .uadt = bitmap_port_uadt,
.destroy = bitmap_port_destroy, .destroy = bitmap_port_destroy,
@@ -308,12 +308,13 @@ bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags) enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{ {
struct bitmap_port_timeout *map = set->data; struct bitmap_port_timeout *map = set->data;
__be16 __port;
u16 port = 0; u16 port = 0;
if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &port)) if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
return -EINVAL; return -EINVAL;
port = ntohs(port); port = ntohs(__port);
if (port < map->first_port || port > map->last_port) if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -346,14 +347,15 @@ bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
bitmap_port_adt_policy)) bitmap_port_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
if (tb[IPSET_ATTR_PORT]) port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (port < map->first_port || port > map->last_port) if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
@@ -483,12 +485,12 @@ bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
const struct bitmap_port_timeout *x = a->data; const struct bitmap_port_timeout *x = a->data;
const struct bitmap_port_timeout *y = b->data; const struct bitmap_port_timeout *y = b->data;
return x->first_port == y->first_port return x->first_port == y->first_port &&
&& x->last_port == y->last_port x->last_port == y->last_port &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
const struct ip_set_type_variant bitmap_port_timeout = { static const struct ip_set_type_variant bitmap_port_timeout = {
.kadt = bitmap_port_timeout_kadt, .kadt = bitmap_port_timeout_kadt,
.uadt = bitmap_port_timeout_uadt, .uadt = bitmap_port_timeout_uadt,
.destroy = bitmap_port_timeout_destroy, .destroy = bitmap_port_timeout_destroy,
@@ -519,7 +521,7 @@ bitmap_port_gc(unsigned long ul_set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static inline void static void
bitmap_port_gc_init(struct ip_set *set) bitmap_port_gc_init(struct ip_set *set)
{ {
struct bitmap_port_timeout *map = set->data; struct bitmap_port_timeout *map = set->data;
@@ -567,21 +569,19 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
bitmap_port_create_policy)) bitmap_port_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PORT]) if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]); !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
else !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PORT_TO]) { first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (first_port > last_port) { if (first_port > last_port) {
u16 tmp = first_port; u16 tmp = first_port;
first_port = last_port; first_port = last_port;
last_port = tmp; last_port = tmp;
} }
} else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
struct bitmap_port_timeout *map; struct bitmap_port_timeout *map;
@@ -611,7 +611,7 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
return -ENOMEM; return -ENOMEM;
map->memsize = bitmap_bytes(0, last_port - first_port); map->memsize = bitmap_bytes(0, last_port - first_port);
pr_debug("memsize: %zu", map->memsize); pr_debug("memsize: %zu\n", map->memsize);
if (!init_map_port(set, map, first_port, last_port)) { if (!init_map_port(set, map, first_port, last_port)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
@@ -622,7 +622,7 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
return 0; return 0;
} }
struct ip_set_type bitmap_port_type = { static struct ip_set_type bitmap_port_type = {
.name = "bitmap:port", .name = "bitmap:port",
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_PORT, .features = IPSET_TYPE_PORT,

View File

@@ -9,7 +9,6 @@
/* Kernel module for IP set management */ /* Kernel module for IP set management */
#include "ip_set_kernel.h"
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
@@ -26,7 +25,7 @@
#include <net/genetlink.h> #include <net/genetlink.h>
#define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN) #define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN)
static struct list_head ip_set_type_list; /* all registered set types */ static LIST_HEAD(ip_set_type_list); /* all registered set types */
static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */
static struct ip_set **ip_set_list; /* all individual sets */ static struct ip_set **ip_set_list; /* all individual sets */
@@ -34,7 +33,7 @@ static ip_set_id_t ip_set_max = LCONFIG_IP_SET_MAX; /* max number of sets */
#define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) #define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0)
static int max_sets; static unsigned int max_sets;
module_param(max_sets, int, 0600); module_param(max_sets, int, 0600);
MODULE_PARM_DESC(max_sets, "maximal number of sets"); MODULE_PARM_DESC(max_sets, "maximal number of sets");
@@ -64,60 +63,77 @@ ip_set_type_unlock(void)
/* Register and deregister settype */ /* Register and deregister settype */
static inline struct ip_set_type * static struct ip_set_type *
find_set_type(const char *name, u8 family, u8 revision) find_set_type(const char *name, u8 family, u8 revision)
{ {
struct ip_set_type *type; struct ip_set_type *type;
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) if (STREQ(type->name, name) &&
&& (type->family == family || type->family == AF_UNSPEC) (type->family == family || type->family == AF_UNSPEC) &&
&& type->revision == revision) type->revision == revision)
return type; return type;
return NULL; return NULL;
} }
/* Find a set type so that rcu_read_lock() is called by the function. /* Unlock, try to load a set type module and lock again */
* If we succeeded, the RCU lock is NOT released and the caller static int
* must release it later. try_to_load_type(const char *name)
*/
static struct ip_set_type *
find_set_type_rcu(const char *name, u8 family, u8 revision)
{ {
struct ip_set_type *type; nfnl_unlock();
pr_debug("try to load ip_set_%s\n", name);
if (request_module("ip_set_%s", name) < 0) {
pr_warning("Can't find ip_set type %s\n", name);
nfnl_lock();
return -IPSET_ERR_FIND_TYPE;
}
nfnl_lock();
return -EAGAIN;
}
/* Find a set type and reference it */
static int
find_set_type_get(const char *name, u8 family, u8 revision,
struct ip_set_type **found)
{
rcu_read_lock(); rcu_read_lock();
type = find_set_type(name, family, revision); *found = find_set_type(name, family, revision);
if (type == NULL) if (*found) {
int err = !try_module_get((*found)->me);
rcu_read_unlock(); rcu_read_unlock();
return err ? -EFAULT : 0;
}
rcu_read_unlock();
return type; return try_to_load_type(name);
} }
/* Find a given set type by name and family. /* Find a given set type by name and family.
* If we succeeded, the supported minimal and maximum revisions are * If we succeeded, the supported minimal and maximum revisions are
* filled out. * filled out.
*/ */
static bool static int
find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max) find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max)
{ {
struct ip_set_type *type; struct ip_set_type *type;
bool ret = false; bool found = false;
*min = *max = 0; *min = *max = 0;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) if (STREQ(type->name, name) &&
&& (type->family == family || type->family == AF_UNSPEC)) { (type->family == family || type->family == AF_UNSPEC)) {
ret = true; found = true;
if (type->revision < *min) if (type->revision < *min)
*min = type->revision; *min = type->revision;
else if (type->revision > *max) else if (type->revision > *max)
*max = type->revision; *max = type->revision;
} }
rcu_read_unlock(); rcu_read_unlock();
if (found)
return 0;
return ret; return try_to_load_type(name);
} }
#define family_name(f) ((f) == AF_INET ? "inet" : \ #define family_name(f) ((f) == AF_INET ? "inet" : \
@@ -149,7 +165,7 @@ ip_set_type_register(struct ip_set_type *type)
goto unlock; goto unlock;
} }
list_add_rcu(&type->list, &ip_set_type_list); list_add_rcu(&type->list, &ip_set_type_list);
pr_debug("type %s, family %s, revision %u registered.", pr_debug("type %s, family %s, revision %u registered.\n",
type->name, family_name(type->family), type->revision); type->name, family_name(type->family), type->revision);
unlock: unlock:
ip_set_type_unlock(); ip_set_type_unlock();
@@ -169,7 +185,7 @@ ip_set_type_unregister(struct ip_set_type *type)
goto unlock; goto unlock;
} }
list_del_rcu(&type->list); list_del_rcu(&type->list);
pr_debug("type %s, family %s, revision %u unregistered.", pr_debug("type %s, family %s, revision %u unregistered.\n",
type->name, family_name(type->family), type->revision); type->name, family_name(type->family), type->revision);
unlock: unlock:
ip_set_type_unlock(); ip_set_type_unlock();
@@ -178,6 +194,92 @@ unlock:
} }
EXPORT_SYMBOL_GPL(ip_set_type_unregister); EXPORT_SYMBOL_GPL(ip_set_type_unregister);
/* Utility functions */
void *
ip_set_alloc(size_t size, gfp_t gfp_mask)
{
void *members = NULL;
if (size < KMALLOC_MAX_SIZE)
members = kzalloc(size, gfp_mask | __GFP_NOWARN);
if (members) {
pr_debug("%p: allocated with kmalloc\n", members);
return members;
}
members = __vmalloc(size, gfp_mask | __GFP_ZERO | __GFP_HIGHMEM,
PAGE_KERNEL);
if (!members)
return NULL;
pr_debug("%p: allocated with vmalloc\n", members);
return members;
}
EXPORT_SYMBOL_GPL(ip_set_alloc);
void
ip_set_free(void *members)
{
pr_debug("%p: free with %s\n", members,
is_vmalloc_addr(members) ? "vfree" : "kfree");
if (is_vmalloc_addr(members))
vfree(members);
else
kfree(members);
}
EXPORT_SYMBOL_GPL(ip_set_free);
static inline bool
flag_nested(const struct nlattr *nla)
{
return nla->nla_type & NLA_F_NESTED;
}
static const struct nla_policy ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] = {
[IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 },
[IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY,
.len = sizeof(struct in6_addr) },
};
int
ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr)
{
struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1];
if (unlikely(!flag_nested(nla)))
return -IPSET_ERR_PROTOCOL;
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla),
ipaddr_policy))
return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4)))
return -IPSET_ERR_PROTOCOL;
*ipaddr = nla_get_be32(tb[IPSET_ATTR_IPADDR_IPV4]);
return 0;
}
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr4);
int
ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
{
struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1];
if (unlikely(!flag_nested(nla)))
return -IPSET_ERR_PROTOCOL;
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla),
ipaddr_policy))
return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6)))
return -IPSET_ERR_PROTOCOL;
memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]),
sizeof(struct in6_addr));
return 0;
}
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
/* /*
* Creating/destroying/renaming/swapping affect the existence and * Creating/destroying/renaming/swapping affect the existence and
* the properties of a set. All of these can be executed from userspace * the properties of a set. All of these can be executed from userspace
@@ -216,10 +318,10 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
int ret = 0; int ret = 0;
BUG_ON(set == NULL || atomic_read(&set->ref) == 0); BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
pr_debug("set %s, index %u", set->name, index); pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension if (dim < set->type->dimension ||
|| !(family == set->family || set->family == AF_UNSPEC)) !(family == set->family || set->family == AF_UNSPEC))
return 0; return 0;
read_lock_bh(&set->lock); read_lock_bh(&set->lock);
@@ -228,7 +330,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
/* Type requests element to be completed */ /* Type requests element to be completed */
pr_debug("element must be competed, ADD is triggered"); pr_debug("element must be competed, ADD is triggered\n");
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags); set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
write_unlock_bh(&set->lock); write_unlock_bh(&set->lock);
@@ -248,10 +350,10 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
int ret; int ret;
BUG_ON(set == NULL || atomic_read(&set->ref) == 0); BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
pr_debug("set %s, index %u", set->name, index); pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension if (dim < set->type->dimension ||
|| !(family == set->family || set->family == AF_UNSPEC)) !(family == set->family || set->family == AF_UNSPEC))
return 0; return 0;
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
@@ -270,10 +372,10 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
int ret = 0; int ret = 0;
BUG_ON(set == NULL || atomic_read(&set->ref) == 0); BUG_ON(set == NULL || atomic_read(&set->ref) == 0);
pr_debug("set %s, index %u", set->name, index); pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension if (dim < set->type->dimension ||
|| !(family == set->family || set->family == AF_UNSPEC)) !(family == set->family || set->family == AF_UNSPEC))
return 0; return 0;
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
@@ -423,8 +525,8 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
static inline bool static inline bool
protocol_failed(struct nlattr *const *tb) protocol_failed(struct nlattr *const *tb)
{ {
return !tb[IPSET_ATTR_PROTOCOL] return !tb[IPSET_ATTR_PROTOCOL] ||
|| nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL; nla_get_u8(tb[IPSET_ATTR_PROTOCOL]) != IPSET_PROTOCOL;
} }
static inline u32 static inline u32
@@ -433,13 +535,7 @@ flag_exist(const struct genlmsghdr *ghdr)
return ghdr->reserved & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST; return ghdr->reserved & NLM_F_EXCL ? 0 : IPSET_FLAG_EXIST;
} }
static inline bool static struct nlmsghdr *
flag_nested(const struct nlattr *nla)
{
return nla->nla_type & NLA_F_NESTED;
}
static void *
start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags,
enum ipset_cmd cmd) enum ipset_cmd cmd)
{ {
@@ -508,13 +604,6 @@ find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set)
return 0; return 0;
} }
static inline void
load_type_module(const char *typename)
{
pr_debug("try to load ip_set_%s", typename);
request_module("ip_set_%s", typename);
}
static int static int
ip_set_create(struct sk_buff *skb, struct genl_info *info) ip_set_create(struct sk_buff *skb, struct genl_info *info)
{ {
@@ -527,20 +616,20 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
u32 flags = flag_exist(info->genlhdr); u32 flags = flag_exist(info->genlhdr);
int ret = 0, len; int ret = 0, len;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL attr[IPSET_ATTR_SETNAME] == NULL ||
|| attr[IPSET_ATTR_TYPENAME] == NULL attr[IPSET_ATTR_TYPENAME] == NULL ||
|| attr[IPSET_ATTR_REVISION] == NULL attr[IPSET_ATTR_REVISION] == NULL ||
|| attr[IPSET_ATTR_FAMILY] == NULL attr[IPSET_ATTR_FAMILY] == NULL ||
|| (attr[IPSET_ATTR_DATA] != NULL (attr[IPSET_ATTR_DATA] != NULL &&
&& !flag_nested(attr[IPSET_ATTR_DATA])))) !flag_nested(attr[IPSET_ATTR_DATA]))))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
name = nla_data(attr[IPSET_ATTR_SETNAME]); name = nla_data(attr[IPSET_ATTR_SETNAME]);
typename = nla_data(attr[IPSET_ATTR_TYPENAME]); typename = nla_data(attr[IPSET_ATTR_TYPENAME]);
family = nla_get_u8(attr[IPSET_ATTR_FAMILY]); family = nla_get_u8(attr[IPSET_ATTR_FAMILY]);
revision = nla_get_u8(attr[IPSET_ATTR_REVISION]); revision = nla_get_u8(attr[IPSET_ATTR_REVISION]);
pr_debug("setname: %s, typename: %s, family: %s, revision: %u", pr_debug("setname: %s, typename: %s, family: %s, revision: %u\n",
name, typename, family_name(family), revision); name, typename, family_name(family), revision);
/* /*
@@ -563,32 +652,15 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
* After referencing the type, we try to create the type * After referencing the type, we try to create the type
* specific part of the set without holding any locks. * specific part of the set without holding any locks.
*/ */
set->type = find_set_type_rcu(typename, family, revision); ret = find_set_type_get(typename, family, revision, &(set->type));
if (set->type == NULL) { if (ret)
/* Try loading the module */
load_type_module(typename);
set->type = find_set_type_rcu(typename, family, revision);
if (set->type == NULL) {
pr_warning("Can't find ip_set type %s, family %s, "
"revision %u: set '%s' not created",
typename, family_name(family), revision,
name);
ret = -IPSET_ERR_FIND_TYPE;
goto out;
}
}
if (!try_module_get(set->type->me)) {
rcu_read_unlock();
ret = -EFAULT;
goto out; goto out;
}
rcu_read_unlock();
/* /*
* Without holding any locks, create private part. * Without holding any locks, create private part.
*/ */
len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0; len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0;
pr_debug("data len: %u", len); pr_debug("data len: %u\n", len);
ret = set->type->create(set, attr[IPSET_ATTR_DATA] ? ret = set->type->create(set, attr[IPSET_ATTR_DATA] ?
nla_data(attr[IPSET_ATTR_DATA]) : NULL, len, nla_data(attr[IPSET_ATTR_DATA]) : NULL, len,
flags); flags);
@@ -604,12 +676,12 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
*/ */
if ((ret = find_free_id(set->name, &index, &clash)) != 0) { if ((ret = find_free_id(set->name, &index, &clash)) != 0) {
/* If this is the same set and requested, ignore error */ /* If this is the same set and requested, ignore error */
if (ret == -EEXIST if (ret == -EEXIST &&
&& (flags & IPSET_FLAG_EXIST) (flags & IPSET_FLAG_EXIST) &&
&& STREQ(set->type->name, clash->type->name) STREQ(set->type->name, clash->type->name) &&
&& set->type->family == clash->type->family set->type->family == clash->type->family &&
&& set->type->revision == clash->type->revision set->type->revision == clash->type->revision &&
&& set->variant->same_set(set, clash)) set->variant->same_set(set, clash))
ret = 0; ret = 0;
goto cleanup; goto cleanup;
} }
@@ -617,7 +689,7 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
/* /*
* Finally! Add our shiny new set to the list, and be done. * Finally! Add our shiny new set to the list, and be done.
*/ */
pr_debug("create: '%s' created with index %u!", set->name, index); pr_debug("create: '%s' created with index %u!\n", set->name, index);
ip_set_list[index] = set; ip_set_list[index] = set;
return ret; return ret;
@@ -640,12 +712,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
.len = IPSET_MAXNAMELEN - 1 }, .len = IPSET_MAXNAMELEN - 1 },
}; };
static inline void static void
ip_set_destroy_set(ip_set_id_t index) ip_set_destroy_set(ip_set_id_t index)
{ {
struct ip_set *set = ip_set_list[index]; struct ip_set *set = ip_set_list[index];
pr_debug("set: %s", set->name); pr_debug("set: %s\n", set->name);
ip_set_list[index] = NULL; ip_set_list[index] = NULL;
/* Must call it without holding any lock */ /* Must call it without holding any lock */
@@ -666,8 +738,8 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
/* References are protected by the nfnl mutex */ /* References are protected by the nfnl mutex */
if (!attr[IPSET_ATTR_SETNAME]) { if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL if (ip_set_list[i] != NULL &&
&& (atomic_read(&ip_set_list[i]->ref))) (atomic_read(&ip_set_list[i]->ref)))
return -IPSET_ERR_BUSY; return -IPSET_ERR_BUSY;
} }
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < ip_set_max; i++) {
@@ -688,10 +760,10 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
/* Flush sets */ /* Flush sets */
static inline void static void
ip_set_flush_set(struct ip_set *set) ip_set_flush_set(struct ip_set *set)
{ {
pr_debug("set: %s", set->name); pr_debug("set: %s\n", set->name);
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
set->variant->flush(set); set->variant->flush(set);
@@ -741,9 +813,9 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info)
const char *name2; const char *name2;
ip_set_id_t i; ip_set_id_t i;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL attr[IPSET_ATTR_SETNAME] == NULL ||
|| attr[IPSET_ATTR_SETNAME2] == NULL)) attr[IPSET_ATTR_SETNAME2] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
@@ -754,8 +826,8 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info)
name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
for (i = 0; i < ip_set_max; i++) { for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL if (ip_set_list[i] != NULL &&
&& STREQ(ip_set_list[i]->name, name2)) STREQ(ip_set_list[i]->name, name2))
return -IPSET_ERR_EXIST_SETNAME2; return -IPSET_ERR_EXIST_SETNAME2;
} }
strncpy(set->name, name2, IPSET_MAXNAMELEN); strncpy(set->name, name2, IPSET_MAXNAMELEN);
@@ -781,9 +853,9 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
char from_name[IPSET_MAXNAMELEN]; char from_name[IPSET_MAXNAMELEN];
u32 from_ref; u32 from_ref;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL attr[IPSET_ATTR_SETNAME] == NULL ||
|| attr[IPSET_ATTR_SETNAME2] == NULL)) attr[IPSET_ATTR_SETNAME2] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
@@ -800,8 +872,8 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
/* Features must not change. /* Features must not change.
* Not an artifical restriction anymore, as we must prevent * Not an artifical restriction anymore, as we must prevent
* possible loops created by swapping in setlist type of sets. */ * possible loops created by swapping in setlist type of sets. */
if (!(from->type->features == to->type->features if (!(from->type->features == to->type->features &&
&& from->type->family == to->type->family)) from->type->family == to->type->family))
return -IPSET_ERR_TYPE_MISMATCH; return -IPSET_ERR_TYPE_MISMATCH;
/* No magic here: ref munging protected by the nfnl_lock */ /* No magic here: ref munging protected by the nfnl_lock */
@@ -830,7 +902,7 @@ static int
ip_set_dump_done(struct netlink_callback *cb) ip_set_dump_done(struct netlink_callback *cb)
{ {
if (cb->args[2]) { if (cb->args[2]) {
pr_debug("release set %s", ip_set_list[cb->args[1]]->name); pr_debug("release set %s\n", ip_set_list[cb->args[1]]->name);
__ip_set_put((ip_set_id_t) cb->args[1]); __ip_set_put((ip_set_id_t) cb->args[1]);
} }
return 0; return 0;
@@ -843,14 +915,13 @@ dump_attrs(void *phdr)
const struct nlmsghdr *nlh = phdr - GENL_HDRLEN - NLMSG_HDRLEN; const struct nlmsghdr *nlh = phdr - GENL_HDRLEN - NLMSG_HDRLEN;
int rem; int rem;
pr_debug("nlmsg_len: %u", nlh->nlmsg_len); pr_debug("dump nlmsg\n");
pr_debug("dump nlmsg");
nlmsg_for_each_attr(attr, nlh, sizeof(struct genlmsghdr), rem) { nlmsg_for_each_attr(attr, nlh, sizeof(struct genlmsghdr), rem) {
pr_debug("type: %u, len %u", nla_type(attr), attr->nla_len); pr_debug("type: %u, len %u\n", nla_type(attr), attr->nla_len);
} }
} }
static inline int static int
dump_init(struct netlink_callback *cb) dump_init(struct netlink_callback *cb)
{ {
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb); struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
@@ -919,14 +990,14 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
/* When dumping all sets, we must dump "sorted" /* When dumping all sets, we must dump "sorted"
* so that lists (unions of sets) are dumped last. * so that lists (unions of sets) are dumped last.
*/ */
if (cb->args[0] != DUMP_ONE if (cb->args[0] != DUMP_ONE &&
&& !((cb->args[0] == DUMP_ALL) !((cb->args[0] == DUMP_ALL) ^
^ (set->type->features & IPSET_DUMP_LAST))) (set->type->features & IPSET_DUMP_LAST)))
continue; continue;
pr_debug("List set: %s", set->name); pr_debug("List set: %s\n", set->name);
if (!cb->args[2]) { if (!cb->args[2]) {
/* Start listing: make sure set won't be destroyed */ /* Start listing: make sure set won't be destroyed */
pr_debug("reference set"); pr_debug("reference set\n");
__ip_set_get(index); __ip_set_get(index);
} }
nlh = start_msg(skb, NETLINK_CB(cb->skb).pid, nlh = start_msg(skb, NETLINK_CB(cb->skb).pid,
@@ -972,7 +1043,7 @@ nla_put_failure:
release_refcount: release_refcount:
/* If there was an error or set is done, release set */ /* If there was an error or set is done, release set */
if (ret || !cb->args[2]) { if (ret || !cb->args[2]) {
pr_debug("release set %s", ip_set_list[index]->name); pr_debug("release set %s\n", ip_set_list[index]->name);
__ip_set_put(index); __ip_set_put(index);
} }
@@ -983,6 +1054,7 @@ release_refcount:
out: out:
if (nlh) { if (nlh) {
genlmsg_end(skb, nlh); genlmsg_end(skb, nlh);
pr_debug("nlmsg_len: %u\n", skb->len);
dump_attrs(nlh); dump_attrs(nlh);
} }
@@ -1034,9 +1106,9 @@ call_ad(struct sk_buff *skb, struct nlattr *const attr[],
ret = set->variant->uadt(set, head, len, adt, ret = set->variant->uadt(set, head, len, adt,
&lineno, flags); &lineno, flags);
write_unlock_bh(&set->lock); write_unlock_bh(&set->lock);
} while (ret == -EAGAIN } while (ret == -EAGAIN &&
&& set->variant->resize set->variant->resize &&
&& (ret = set->variant->resize(set, retried++)) == 0); (ret = set->variant->resize(set, retried++)) == 0);
if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0; return 0;
@@ -1060,15 +1132,15 @@ ip_set_uadd(struct sk_buff *skb, struct genl_info *info)
u32 flags = flag_exist(info->genlhdr); u32 flags = flag_exist(info->genlhdr);
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL attr[IPSET_ATTR_SETNAME] == NULL ||
|| !((attr[IPSET_ATTR_DATA] != NULL) !((attr[IPSET_ATTR_DATA] != NULL) ^
^ (attr[IPSET_ATTR_ADT] != NULL)) (attr[IPSET_ATTR_ADT] != NULL)) ||
|| (attr[IPSET_ATTR_DATA] != NULL (attr[IPSET_ATTR_DATA] != NULL &&
&& !flag_nested(attr[IPSET_ATTR_DATA])) !flag_nested(attr[IPSET_ATTR_DATA])) ||
|| (attr[IPSET_ATTR_ADT] != NULL (attr[IPSET_ATTR_ADT] != NULL &&
&& (!flag_nested(attr[IPSET_ATTR_ADT]) (!flag_nested(attr[IPSET_ATTR_ADT]) ||
|| attr[IPSET_ATTR_LINENO] == NULL)))) attr[IPSET_ATTR_LINENO] == NULL))))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
@@ -1082,8 +1154,8 @@ ip_set_uadd(struct sk_buff *skb, struct genl_info *info)
int nla_rem; int nla_rem;
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
if (nla_type(nla) != IPSET_ATTR_DATA if (nla_type(nla) != IPSET_ATTR_DATA ||
|| !flag_nested(nla)) !flag_nested(nla))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
ret = call_ad(skb, attr, ret = call_ad(skb, attr,
set, nla, IPSET_ADD, flags); set, nla, IPSET_ADD, flags);
@@ -1104,15 +1176,15 @@ ip_set_udel(struct sk_buff *skb, struct genl_info *info)
u32 flags = flag_exist(info->genlhdr); u32 flags = flag_exist(info->genlhdr);
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL attr[IPSET_ATTR_SETNAME] == NULL ||
|| !((attr[IPSET_ATTR_DATA] != NULL) !((attr[IPSET_ATTR_DATA] != NULL) ^
^ (attr[IPSET_ATTR_ADT] != NULL)) (attr[IPSET_ATTR_ADT] != NULL)) ||
|| (attr[IPSET_ATTR_DATA] != NULL (attr[IPSET_ATTR_DATA] != NULL &&
&& !flag_nested(attr[IPSET_ATTR_DATA])) !flag_nested(attr[IPSET_ATTR_DATA])) ||
|| (attr[IPSET_ATTR_ADT] != NULL (attr[IPSET_ATTR_ADT] != NULL &&
&& (!flag_nested(attr[IPSET_ATTR_ADT]) (!flag_nested(attr[IPSET_ATTR_ADT]) ||
|| attr[IPSET_ATTR_LINENO] == NULL)))) attr[IPSET_ATTR_LINENO] == NULL))))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
@@ -1126,8 +1198,8 @@ ip_set_udel(struct sk_buff *skb, struct genl_info *info)
int nla_rem; int nla_rem;
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
if (nla_type(nla) != IPSET_ATTR_DATA if (nla_type(nla) != IPSET_ATTR_DATA ||
|| !flag_nested(nla)) !flag_nested(nla))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
ret = call_ad(skb, attr, ret = call_ad(skb, attr,
set, nla, IPSET_DEL, flags); set, nla, IPSET_DEL, flags);
@@ -1146,10 +1218,10 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
struct ip_set *set; struct ip_set *set;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL attr[IPSET_ATTR_SETNAME] == NULL ||
|| attr[IPSET_ATTR_DATA] == NULL attr[IPSET_ATTR_DATA] == NULL ||
|| !flag_nested(attr[IPSET_ATTR_DATA]))) !flag_nested(attr[IPSET_ATTR_DATA])))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
@@ -1182,8 +1254,8 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
ip_set_id_t index; ip_set_id_t index;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_SETNAME] == NULL)) attr[IPSET_ATTR_SETNAME] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
@@ -1240,22 +1312,16 @@ ip_set_type(struct sk_buff *skb, struct genl_info *info)
const char *typename; const char *typename;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) if (unlikely(protocol_failed(attr) ||
|| attr[IPSET_ATTR_TYPENAME] == NULL attr[IPSET_ATTR_TYPENAME] == NULL ||
|| attr[IPSET_ATTR_FAMILY] == NULL)) attr[IPSET_ATTR_FAMILY] == NULL))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
family = nla_get_u8(attr[IPSET_ATTR_FAMILY]); family = nla_get_u8(attr[IPSET_ATTR_FAMILY]);
typename = nla_data(attr[IPSET_ATTR_TYPENAME]); typename = nla_data(attr[IPSET_ATTR_TYPENAME]);
if (!find_set_type_minmax(typename, family, &min, &max)) { ret = find_set_type_minmax(typename, family, &min, &max);
/* Try to load in the type module */ if (ret)
load_type_module(typename); return ret;
if (!find_set_type_minmax(typename, family, &min, &max)) {
pr_debug("can't find: %s, family: %u",
typename, family);
return -EEXIST;
}
}
skb2 = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); skb2 = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb2 == NULL) if (skb2 == NULL)
@@ -1272,6 +1338,7 @@ ip_set_type(struct sk_buff *skb, struct genl_info *info)
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION_MIN, min); NLA_PUT_U8(skb2, IPSET_ATTR_REVISION_MIN, min);
genlmsg_end(skb2, nlh2); genlmsg_end(skb2, nlh2);
pr_debug("Send TYPE, nlmsg_len: %u\n", skb2->len);
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
if (ret < 0) if (ret < 0)
return -EFAULT; return -EFAULT;
@@ -1421,7 +1488,7 @@ static struct genl_family ip_set_netlink_subsys __read_mostly = {
/* Interface to iptables/ip6tables */ /* Interface to iptables/ip6tables */
static int static int
ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
{ {
unsigned *op; unsigned *op;
void *data; void *data;
@@ -1482,8 +1549,8 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
case IP_SET_OP_GET_BYINDEX: { case IP_SET_OP_GET_BYINDEX: {
struct ip_set_req_get_set *req_get = data; struct ip_set_req_get_set *req_get = data;
if (*len != sizeof(struct ip_set_req_get_set) if (*len != sizeof(struct ip_set_req_get_set) ||
|| req_get->set.index >= ip_set_max) { req_get->set.index >= ip_set_max) {
ret = -EINVAL; ret = -EINVAL;
goto done; goto done;
} }
@@ -1531,12 +1598,10 @@ ip_set_init(void)
ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max,
GFP_KERNEL); GFP_KERNEL);
if (!ip_set_list) { if (!ip_set_list) {
pr_err("ip_set: Unable to create ip_set_list"); pr_err("ip_set: Unable to create ip_set_list\n");
return -ENOMEM; return -ENOMEM;
} }
INIT_LIST_HEAD(&ip_set_type_list);
ret = genl_register_family_with_ops(&ip_set_netlink_subsys, ret = genl_register_family_with_ops(&ip_set_netlink_subsys,
ip_set_netlink_subsys_cb, ARRAY_SIZE(ip_set_netlink_subsys_cb)); ip_set_netlink_subsys_cb, ARRAY_SIZE(ip_set_netlink_subsys_cb));
if (ret != 0) { if (ret != 0) {
@@ -1546,13 +1611,13 @@ ip_set_init(void)
} }
ret = nf_register_sockopt(&so_set); ret = nf_register_sockopt(&so_set);
if (ret != 0) { if (ret != 0) {
pr_err("SO_SET registry failed: %d", ret); pr_err("SO_SET registry failed: %d\n", ret);
genl_unregister_family(&ip_set_netlink_subsys); genl_unregister_family(&ip_set_netlink_subsys);
kfree(ip_set_list); kfree(ip_set_list);
return ret; return ret;
} }
pr_notice("ip_set: protocol %u", IPSET_PROTOCOL); pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
return 0; return 0;
} }
@@ -1563,7 +1628,7 @@ ip_set_fini(void)
nf_unregister_sockopt(&so_set); nf_unregister_sockopt(&so_set);
genl_unregister_family(&ip_set_netlink_subsys); genl_unregister_family(&ip_set_netlink_subsys);
kfree(ip_set_list); kfree(ip_set_list);
pr_debug("these are the famous last words"); pr_debug("these are the famous last words\n");
} }
module_init(ip_set_init); module_init(ip_set_init);

View File

@@ -0,0 +1,136 @@
/* Copyright (C) 2003-2011 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
* published by the Free Software Foundation.
*/
/* Get Layer-4 data from the packets */
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h>
#include "ip_set_getport.h"
/* We must handle non-linear skbs */
static bool
get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
bool src, __be16 *port, u8 *proto)
{
switch (protocol) {
case IPPROTO_TCP: {
struct tcphdr _tcph;
const struct tcphdr *th;
th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
if (th == NULL)
/* No choice either */
return false;
*port = src ? th->source : th->dest;
break;
}
case IPPROTO_UDP: {
struct udphdr _udph;
const struct udphdr *uh;
uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
if (uh == NULL)
/* No choice either */
return false;
*port = src ? uh->source : uh->dest;
break;
}
case IPPROTO_ICMP: {
struct icmphdr _ich;
const struct icmphdr *ic;
ic = skb_header_pointer(skb, protooff, sizeof(_ich), &_ich);
if (ic == NULL)
return false;
*port = (__force __be16)htons((ic->type << 8) | ic->code);
break;
}
case IPPROTO_ICMPV6: {
struct icmp6hdr _ich;
const struct icmp6hdr *ic;
ic = skb_header_pointer(skb, protooff, sizeof(_ich), &_ich);
if (ic == NULL)
return false;
*port = (__force __be16)
htons((ic->icmp6_type << 8) | ic->icmp6_code);
break;
}
default:
break;
}
*proto = protocol;
return true;
}
bool
ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
__be16 *port, u8 *proto)
{
const struct iphdr *iph = ip_hdr(skb);
unsigned int protooff = ip_hdrlen(skb);
int protocol = iph->protocol;
/* See comments at tcp_match in ip_tables.c */
if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET))
return false;
return get_port(skb, protocol, protooff, src, port, proto);
}
EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
bool
ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
__be16 *port, u8 *proto)
{
unsigned int protooff = 0;
int protocol;
unsigned short fragoff;
protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff);
if (protocol <= 0 || fragoff)
return false;
return get_port(skb, protocol, protooff, src, port, proto);
}
EXPORT_SYMBOL_GPL(ip_set_get_ip6_port);
bool
ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
{
bool ret;
u8 proto;
switch (pf) {
case AF_INET:
ret = ip_set_get_ip4_port(skb, src, port, &proto);
case AF_INET6:
ret = ip_set_get_ip6_port(skb, src, port, &proto);
default:
return false;
}
if (!ret)
return ret;
switch (proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
return true;
default:
return false;
}
}
EXPORT_SYMBOL_GPL(ip_set_get_ip_port);

View File

@@ -1,126 +1,11 @@
#ifndef _IP_SET_GETPORT_H #ifndef _IP_SET_GETPORT_H
#define _IP_SET_GETPORT_H #define _IP_SET_GETPORT_H
#ifdef __KERNEL__ extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
#include <linux/icmp.h> __be16 *port, u8 *proto);
#include <linux/icmpv6.h> extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
#include <linux/netfilter_ipv6/ip6_tables.h> __be16 *port, u8 *proto);
#include <net/ip.h> extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,
__be16 *port);
#define IPSET_INVALID_PORT 65536
/* We must handle non-linear skbs */
static inline bool
get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
bool src, u16 *port, u8 *proto)
{
switch (protocol) {
case IPPROTO_TCP: {
struct tcphdr _tcph;
const struct tcphdr *th;
th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
if (th == NULL)
/* No choice either */
return false;
*port = src ? th->source : th->dest;
break;
}
case IPPROTO_UDP: {
struct udphdr _udph;
const struct udphdr *uh;
uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
if (uh == NULL)
/* No choice either */
return false;
*port = src ? uh->source : uh->dest;
break;
}
case IPPROTO_ICMP: {
struct icmphdr _icmph;
const struct icmphdr *ic;
ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph);
if (ic == NULL)
return false;
*port = (ic->type << 8) & ic->code;
break;
}
case IPPROTO_ICMPV6: {
struct icmp6hdr _icmph;
const struct icmp6hdr *ic;
ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph);
if (ic == NULL)
return false;
*port = (ic->icmp6_type << 8) & ic->icmp6_code;
break;
}
default:
break;
}
*proto = protocol;
return true;
}
static inline bool
get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
{
const struct iphdr *iph = ip_hdr(skb);
unsigned int protooff = ip_hdrlen(skb);
int protocol = iph->protocol;
/* See comments at tcp_match in ip_tables.c */
if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET))
return false;
return get_port(skb, protocol, protooff, src, port, proto);
}
static inline bool
get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
{
unsigned int protooff = 0;
int protocol;
unsigned short fragoff;
protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff);
if (protocol <= 0 || fragoff)
return false;
return get_port(skb, protocol, protooff, src, port, proto);
}
static inline bool
get_ip_port(const struct sk_buff *skb, u8 pf, bool src, u16 *port)
{
bool ret;
u8 proto;
switch (pf) {
case AF_INET:
ret = get_ip4_port(skb, src, port, &proto);
case AF_INET6:
ret = get_ip6_port(skb, src, port, &proto);
default:
return false;
}
if (!ret)
return ret;
switch (proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
return true;
default:
return false;
}
}
#endif /* __KERNEL__ */
#endif /*_IP_SET_GETPORT_H*/ #endif /*_IP_SET_GETPORT_H*/

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the hash:ip type */ /* Kernel module implementing an IP set type: the hash:ip type */
#include "ip_set_kernel.h"
#include "jhash.h" #include "jhash.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
@@ -46,12 +45,12 @@ hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
/* Member elements without timeout */ /* Member elements without timeout */
struct hash_ip4_elem { struct hash_ip4_elem {
u32 ip; __be32 ip;
}; };
/* Member elements with timeout support */ /* Member elements with timeout support */
struct hash_ip4_telem { struct hash_ip4_telem {
u32 ip; __be32 ip;
unsigned long timeout; unsigned long timeout;
}; };
@@ -74,12 +73,6 @@ hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
dst->ip = src->ip; dst->ip = src->ip;
} }
static inline void
hash_ip4_data_swap(struct hash_ip4_elem *dst, struct hash_ip4_elem *src)
{
swap(dst->ip, src->ip);
}
/* Zero valued IP addresses cannot be stored */ /* Zero valued IP addresses cannot be stored */
static inline void static inline void
hash_ip4_data_zero_out(struct hash_ip4_elem *elem) hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
@@ -97,7 +90,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data) hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
{ {
const struct hash_ip4_telem *tdata = const struct hash_ip4_telem *tdata =
@@ -124,10 +117,10 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
u32 ip; __be32 ip;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip); ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
ip &= NETMASK(h->netmask); ip &= ip_set_netmask(h->netmask);
if (ip == 0) if (ip == 0)
return -EINVAL; return -EINVAL;
@@ -149,23 +142,26 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
u32 ip, nip, ip_to, hosts, timeout = h->timeout; u32 ip, ip_to, hosts, timeout = h->timeout;
__be32 nip;
int ret = 0; int ret = 0;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
hash_ip4_adt_policy)) hash_ip4_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret) if (ret)
return ret; return ret;
ip &= NETMASK(h->netmask); ip &= ip_set_hostmask(h->netmask);
if (ip == 0)
return -IPSET_ERR_HASH_ELEM;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
@@ -173,15 +169,17 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST) if (adt == IPSET_TEST) {
return adtfn(set, &ip, timeout); nip = htonl(ip);
if (nip == 0)
return -IPSET_ERR_HASH_ELEM;
return adtfn(set, &nip, timeout);
}
ip = ntohl(ip);
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
ip_to = ntohl(ip_to);
if (ip > ip_to) if (ip > ip_to)
swap(ip, ip_to); swap(ip, ip_to);
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
@@ -189,8 +187,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (cidr > 32) if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip &= HOSTMASK(cidr); ip &= ip_set_hostmask(cidr);
ip_to = ip | ~HOSTMASK(cidr); ip_to = ip | ~ip_set_hostmask(cidr);
} else } else
ip_to = ip; ip_to = ip;
@@ -198,6 +196,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
for (; !before(ip_to, ip); ip += hosts) { for (; !before(ip_to, ip); ip += hosts) {
nip = htonl(ip); nip = htonl(ip);
if (nip == 0)
return -IPSET_ERR_HASH_ELEM;
ret = adtfn(set, &nip, timeout); ret = adtfn(set, &nip, timeout);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
@@ -215,9 +215,9 @@ hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
const struct ip_set_hash *y = b->data; const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */ /* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem return x->maxelem == y->maxelem &&
&& x->timeout == y->timeout x->timeout == y->timeout &&
&& x->netmask == y->netmask; x->netmask == y->netmask;
} }
/* The type variant functions: IPv6 */ /* The type variant functions: IPv6 */
@@ -250,16 +250,6 @@ hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
ipv6_addr_copy(&dst->ip.in6, &src->ip.in6); ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
} }
static inline void
hash_ip6_data_swap(struct hash_ip6_elem *dst, struct hash_ip6_elem *src)
{
struct in6_addr tmp;
ipv6_addr_copy(&tmp, &dst->ip.in6);
ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
ipv6_addr_copy(&src->ip.in6, &tmp);
}
static inline void static inline void
hash_ip6_data_zero_out(struct hash_ip6_elem *elem) hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
{ {
@@ -269,13 +259,13 @@ hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
static inline void static inline void
ip6_netmask(union nf_inet_addr *ip, u8 prefix) ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{ {
ip->ip6[0] &= NETMASK6(prefix)[0]; ip->ip6[0] &= ip_set_netmask6(prefix)[0];
ip->ip6[1] &= NETMASK6(prefix)[1]; ip->ip6[1] &= ip_set_netmask6(prefix)[1];
ip->ip6[2] &= NETMASK6(prefix)[2]; ip->ip6[2] &= ip_set_netmask6(prefix)[2];
ip->ip6[3] &= NETMASK6(prefix)[3]; ip->ip6[3] &= ip_set_netmask6(prefix)[3];
} }
static inline bool 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 *data)
{ {
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
@@ -285,7 +275,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data) hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
{ {
const struct hash_ip6_telem *e = const struct hash_ip6_telem *e =
@@ -344,10 +334,14 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ip6_adt_policy)) hash_ip6_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(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], &ip);
if (ret) if (ret)
return ret; return ret;
@@ -389,13 +383,18 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
netmask = set->family == AF_INET ? 32 : 128; netmask = set->family == AF_INET ? 32 : 128;
pr_debug("Create set %s with family %s", pr_debug("Create set %s with family %s\n",
set->name, set->family == AF_INET ? "inet" : "inet6"); set->name, set->family == AF_INET ? "inet" : "inet6");
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
hash_ip_create_policy)) hash_ip_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
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]) { if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE) if (hashsize < IPSET_MIMINAL_HASHSIZE)
@@ -408,9 +407,9 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
if (tb[IPSET_ATTR_NETMASK]) { if (tb[IPSET_ATTR_NETMASK]) {
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
if ((set->family == AF_INET && netmask > 32) if ((set->family == AF_INET && netmask > 32) ||
|| (set->family == AF_INET6 && netmask > 128) (set->family == AF_INET6 && netmask > 128) ||
|| netmask == 0) netmask == 0)
return -IPSET_ERR_INVALID_NETMASK; return -IPSET_ERR_INVALID_NETMASK;
} }
@@ -451,7 +450,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
? &hash_ip4_variant : &hash_ip6_variant; ? &hash_ip4_variant : &hash_ip6_variant;
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); h->table->htable_bits, h->maxelem, set->data, h->table);

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the hash:ip,port type */ /* Kernel module implementing an IP set type: the hash:ip,port type */
#include "ip_set_kernel.h"
#include "jhash.h" #include "jhash.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
@@ -47,16 +46,16 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b);
/* Member elements without timeout */ /* Member elements without timeout */
struct hash_ipport4_elem { struct hash_ipport4_elem {
u32 ip; __be32 ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
}; };
/* Member elements with timeout support */ /* Member elements with timeout support */
struct hash_ipport4_telem { struct hash_ipport4_telem {
u32 ip; __be32 ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
unsigned long timeout; unsigned long timeout;
@@ -66,9 +65,9 @@ static inline bool
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1, hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
const struct hash_ipport4_elem *ip2) const struct hash_ipport4_elem *ip2)
{ {
return ip1->ip == ip2->ip return ip1->ip == ip2->ip &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto; ip1->proto == ip2->proto;
} }
static inline bool static inline bool
@@ -86,22 +85,13 @@ hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
dst->proto = src->proto; dst->proto = src->proto;
} }
static inline void
hash_ipport4_data_swap(struct hash_ipport4_elem *dst,
struct hash_ipport4_elem *src)
{
swap(dst->ip, src->ip);
swap(dst->port, src->port);
swap(dst->proto, src->proto);
}
static inline void static inline void
hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem) hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
{ {
elem->proto = 0; elem->proto = 0;
} }
static inline bool static bool
hash_ipport4_data_list(struct sk_buff *skb, hash_ipport4_data_list(struct sk_buff *skb,
const struct hash_ipport4_elem *data) const struct hash_ipport4_elem *data)
{ {
@@ -114,7 +104,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ipport4_data_tlist(struct sk_buff *skb, hash_ipport4_data_tlist(struct sk_buff *skb,
const struct hash_ipport4_elem *data) const struct hash_ipport4_elem *data)
{ {
@@ -145,8 +135,8 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem data = { }; struct hash_ipport4_elem data = { };
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
@@ -182,15 +172,21 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ipport_adt_policy)) hash_ipport_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -218,20 +214,19 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|| tb[IPSET_ATTR_PORT_TO])) { tb[IPSET_ATTR_PORT_TO])) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
ip = ntohl(data.ip); ip = ntohl(data.ip);
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
ip_to = ntohl(ip_to);
if (ip > ip_to) if (ip > ip_to)
swap(ip, ip_to); swap(ip, ip_to);
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
@@ -239,8 +234,8 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (cidr > 32) if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip &= HOSTMASK(cidr); ip &= ip_set_hostmask(cidr);
ip_to = ip | ~HOSTMASK(cidr); ip_to = ip | ~ip_set_hostmask(cidr);
} else } else
ip_to = ip; ip_to = ip;
@@ -273,22 +268,22 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
const struct ip_set_hash *y = b->data; const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */ /* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem return x->maxelem == y->maxelem &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
/* The type variant functions: IPv6 */ /* The type variant functions: IPv6 */
struct hash_ipport6_elem { struct hash_ipport6_elem {
union nf_inet_addr ip; union nf_inet_addr ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
}; };
struct hash_ipport6_telem { struct hash_ipport6_telem {
union nf_inet_addr ip; union nf_inet_addr ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
unsigned long timeout; unsigned long timeout;
@@ -298,9 +293,9 @@ static inline bool
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1, hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
const struct hash_ipport6_elem *ip2) const struct hash_ipport6_elem *ip2)
{ {
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto; ip1->proto == ip2->proto;
} }
static inline bool static inline bool
@@ -316,24 +311,13 @@ hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_ipport6_data_swap(struct hash_ipport6_elem *dst,
struct hash_ipport6_elem *src)
{
struct hash_ipport6_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem) hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
{ {
elem->proto = 0; elem->proto = 0;
} }
static inline bool static bool
hash_ipport6_data_list(struct sk_buff *skb, hash_ipport6_data_list(struct sk_buff *skb,
const struct hash_ipport6_elem *data) const struct hash_ipport6_elem *data)
{ {
@@ -346,7 +330,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ipport6_data_tlist(struct sk_buff *skb, hash_ipport6_data_tlist(struct sk_buff *skb,
const struct hash_ipport6_elem *data) const struct hash_ipport6_elem *data)
{ {
@@ -379,8 +363,8 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport6_elem data = { }; struct hash_ipport6_elem data = { };
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
@@ -404,15 +388,21 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ipport_adt_policy)) hash_ipport_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -440,9 +430,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !tb[IPSET_ATTR_PORT_TO]) { !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
@@ -491,6 +481,11 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hash_ipport_create_policy)) hash_ipport_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
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]) { if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE) if (hashsize < IPSET_MIMINAL_HASHSIZE)
@@ -536,7 +531,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
? &hash_ipport4_variant : &hash_ipport6_variant; ? &hash_ipport4_variant : &hash_ipport6_variant;
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); h->table->htable_bits, h->maxelem, set->data, h->table);

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the hash:ip,port,ip type */ /* Kernel module implementing an IP set type: the hash:ip,port,ip type */
#include "ip_set_kernel.h"
#include "jhash.h" #include "jhash.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
@@ -47,18 +46,18 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
/* Member elements without timeout */ /* Member elements without timeout */
struct hash_ipportip4_elem { struct hash_ipportip4_elem {
u32 ip; __be32 ip;
u32 ip2; __be32 ip2;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
}; };
/* Member elements with timeout support */ /* Member elements with timeout support */
struct hash_ipportip4_telem { struct hash_ipportip4_telem {
u32 ip; __be32 ip;
u32 ip2; __be32 ip2;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
unsigned long timeout; unsigned long timeout;
@@ -68,10 +67,10 @@ static inline bool
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
const struct hash_ipportip4_elem *ip2) const struct hash_ipportip4_elem *ip2)
{ {
return ip1->ip == ip2->ip return ip1->ip == ip2->ip &&
&& ip1->ip2 == ip2->ip2 ip1->ip2 == ip2->ip2 &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto; ip1->proto == ip2->proto;
} }
static inline bool static inline bool
@@ -87,24 +86,13 @@ hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_ipportip4_data_swap(struct hash_ipportip4_elem *dst,
struct hash_ipportip4_elem *src)
{
struct hash_ipportip4_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem) hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
{ {
elem->proto = 0; elem->proto = 0;
} }
static inline bool static bool
hash_ipportip4_data_list(struct sk_buff *skb, hash_ipportip4_data_list(struct sk_buff *skb,
const struct hash_ipportip4_elem *data) const struct hash_ipportip4_elem *data)
{ {
@@ -118,7 +106,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ipportip4_data_tlist(struct sk_buff *skb, hash_ipportip4_data_tlist(struct sk_buff *skb,
const struct hash_ipportip4_elem *data) const struct hash_ipportip4_elem *data)
{ {
@@ -150,8 +138,8 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem data = { }; struct hash_ipportip4_elem data = { };
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
@@ -189,19 +177,25 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ipportip_adt_policy)) hash_ipportip_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
if (ret) if (ret)
return ret; return ret;
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -229,20 +223,19 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|| tb[IPSET_ATTR_PORT_TO])) { tb[IPSET_ATTR_PORT_TO])) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
ip = ntohl(data.ip); ip = ntohl(data.ip);
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
ip_to = ntohl(ip_to);
if (ip > ip_to) if (ip > ip_to)
swap(ip, ip_to); swap(ip, ip_to);
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
@@ -250,8 +243,8 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (cidr > 32) if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip &= HOSTMASK(cidr); ip &= ip_set_hostmask(cidr);
ip_to = ip | ~HOSTMASK(cidr); ip_to = ip | ~ip_set_hostmask(cidr);
} else } else
ip_to = ip; ip_to = ip;
@@ -284,8 +277,8 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
const struct ip_set_hash *y = b->data; const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */ /* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem return x->maxelem == y->maxelem &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
/* The type variant functions: IPv6 */ /* The type variant functions: IPv6 */
@@ -293,7 +286,7 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
struct hash_ipportip6_elem { struct hash_ipportip6_elem {
union nf_inet_addr ip; union nf_inet_addr ip;
union nf_inet_addr ip2; union nf_inet_addr ip2;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
}; };
@@ -301,7 +294,7 @@ struct hash_ipportip6_elem {
struct hash_ipportip6_telem { struct hash_ipportip6_telem {
union nf_inet_addr ip; union nf_inet_addr ip;
union nf_inet_addr ip2; union nf_inet_addr ip2;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 padding; u8 padding;
unsigned long timeout; unsigned long timeout;
@@ -311,10 +304,10 @@ static inline bool
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
const struct hash_ipportip6_elem *ip2) const struct hash_ipportip6_elem *ip2)
{ {
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto; ip1->proto == ip2->proto;
} }
static inline bool static inline bool
@@ -330,24 +323,13 @@ hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_ipportip6_data_swap(struct hash_ipportip6_elem *dst,
struct hash_ipportip6_elem *src)
{
struct hash_ipportip6_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem) hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
{ {
elem->proto = 0; elem->proto = 0;
} }
static inline bool static bool
hash_ipportip6_data_list(struct sk_buff *skb, hash_ipportip6_data_list(struct sk_buff *skb,
const struct hash_ipportip6_elem *data) const struct hash_ipportip6_elem *data)
{ {
@@ -361,7 +343,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ipportip6_data_tlist(struct sk_buff *skb, hash_ipportip6_data_tlist(struct sk_buff *skb,
const struct hash_ipportip6_elem *data) const struct hash_ipportip6_elem *data)
{ {
@@ -395,8 +377,8 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip6_elem data = { }; struct hash_ipportip6_elem data = { };
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
@@ -421,19 +403,25 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ipportip_adt_policy)) hash_ipportip_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
if (ret) if (ret)
return ret; return ret;
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -461,9 +449,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !tb[IPSET_ATTR_PORT_TO]) { !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
@@ -512,6 +500,11 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
hash_ipportip_create_policy)) hash_ipportip_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
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]) { if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE) if (hashsize < IPSET_MIMINAL_HASHSIZE)
@@ -557,7 +550,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
? &hash_ipportip4_variant : &hash_ipportip6_variant; ? &hash_ipportip4_variant : &hash_ipportip6_variant;
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); h->table->htable_bits, h->maxelem, set->data, h->table);

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the hash:ip,port,net type */ /* Kernel module implementing an IP set type: the hash:ip,port,net type */
#include "ip_set_kernel.h"
#include "jhash.h" #include "jhash.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
@@ -47,18 +46,18 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
/* Member elements without timeout */ /* Member elements without timeout */
struct hash_ipportnet4_elem { struct hash_ipportnet4_elem {
u32 ip; __be32 ip;
u32 ip2; __be32 ip2;
u16 port; __be16 port;
u8 cidr; u8 cidr;
u8 proto; u8 proto;
}; };
/* Member elements with timeout support */ /* Member elements with timeout support */
struct hash_ipportnet4_telem { struct hash_ipportnet4_telem {
u32 ip; __be32 ip;
u32 ip2; __be32 ip2;
u16 port; __be16 port;
u8 cidr; u8 cidr;
u8 proto; u8 proto;
unsigned long timeout; unsigned long timeout;
@@ -68,11 +67,11 @@ static inline bool
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
const struct hash_ipportnet4_elem *ip2) const struct hash_ipportnet4_elem *ip2)
{ {
return ip1->ip == ip2->ip return ip1->ip == ip2->ip &&
&& ip1->ip2 == ip2->ip2 ip1->ip2 == ip2->ip2 &&
&& ip1->cidr == ip2->cidr ip1->cidr == ip2->cidr &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto; ip1->proto == ip2->proto;
} }
static inline bool static inline bool
@@ -88,21 +87,10 @@ hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_ipportnet4_data_swap(struct hash_ipportnet4_elem *dst,
struct hash_ipportnet4_elem *src)
{
struct hash_ipportnet4_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr) hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
{ {
elem->ip2 &= NETMASK(cidr); elem->ip2 &= ip_set_netmask(cidr);
elem->cidr = cidr; elem->cidr = cidr;
} }
@@ -112,7 +100,7 @@ hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
elem->proto = 0; elem->proto = 0;
} }
static inline bool static bool
hash_ipportnet4_data_list(struct sk_buff *skb, hash_ipportnet4_data_list(struct sk_buff *skb,
const struct hash_ipportnet4_elem *data) const struct hash_ipportnet4_elem *data)
{ {
@@ -127,7 +115,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ipportnet4_data_tlist(struct sk_buff *skb, hash_ipportnet4_data_tlist(struct sk_buff *skb,
const struct hash_ipportnet4_elem *data) const struct hash_ipportnet4_elem *data)
{ {
@@ -169,13 +157,13 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
if (adt == IPSET_TEST) if (adt == IPSET_TEST)
data.cidr = HOST_MASK; data.cidr = HOST_MASK;
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2); ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
data.ip2 &= NETMASK(data.cidr); data.ip2 &= ip_set_netmask(data.cidr);
return adtfn(set, &data, h->timeout); return adtfn(set, &data, h->timeout);
} }
@@ -210,14 +198,20 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ipportnet_adt_policy)) hash_ipportnet_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
if (ret) if (ret)
return ret; return ret;
@@ -227,16 +221,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (!data.cidr) if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
data.ip2 &= NETMASK(data.cidr); data.ip2 &= ip_set_netmask(data.cidr);
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) { if (tb[IPSET_ATTR_PROTO]) {
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
if (data.proto == 0) if (data.proto == 0)
return -IPSET_ERR_INVALID_PROTO; return -IPSET_ERR_INVALID_PROTO;
} else } else
@@ -258,20 +252,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|| tb[IPSET_ATTR_PORT_TO])) { tb[IPSET_ATTR_PORT_TO])) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
ip = ntohl(data.ip); ip = ntohl(data.ip);
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret) if (ret)
return ret; return ret;
ip_to = ntohl(ip_to);
if (ip > ip_to) if (ip > ip_to)
swap(ip, ip_to); swap(ip, ip_to);
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
@@ -279,8 +272,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (cidr > 32) if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip &= HOSTMASK(cidr); ip &= ip_set_hostmask(cidr);
ip_to = ip | ~HOSTMASK(cidr); ip_to = ip | ~ip_set_hostmask(cidr);
} else } else
ip_to = ip; ip_to = ip;
@@ -311,10 +304,10 @@ hash_ipportnet_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 *x = a->data;
const struct ip_set_hash *y = b->data; const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */ /* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem return x->maxelem == y->maxelem &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
/* The type variant functions: IPv6 */ /* The type variant functions: IPv6 */
@@ -322,7 +315,7 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
struct hash_ipportnet6_elem { struct hash_ipportnet6_elem {
union nf_inet_addr ip; union nf_inet_addr ip;
union nf_inet_addr ip2; union nf_inet_addr ip2;
u16 port; __be16 port;
u8 cidr; u8 cidr;
u8 proto; u8 proto;
}; };
@@ -330,7 +323,7 @@ struct hash_ipportnet6_elem {
struct hash_ipportnet6_telem { struct hash_ipportnet6_telem {
union nf_inet_addr ip; union nf_inet_addr ip;
union nf_inet_addr ip2; union nf_inet_addr ip2;
u16 port; __be16 port;
u8 cidr; u8 cidr;
u8 proto; u8 proto;
unsigned long timeout; unsigned long timeout;
@@ -340,11 +333,11 @@ static inline bool
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
const struct hash_ipportnet6_elem *ip2) const struct hash_ipportnet6_elem *ip2)
{ {
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
&& ip1->cidr == ip2->cidr ip1->cidr == ip2->cidr &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto; ip1->proto == ip2->proto;
} }
static inline bool static inline bool
@@ -360,17 +353,6 @@ hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_ipportnet6_data_swap(struct hash_ipportnet6_elem *dst,
struct hash_ipportnet6_elem *src)
{
struct hash_ipportnet6_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem) hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
{ {
@@ -380,10 +362,10 @@ hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
static inline void static inline void
ip6_netmask(union nf_inet_addr *ip, u8 prefix) ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{ {
ip->ip6[0] &= NETMASK6(prefix)[0]; ip->ip6[0] &= ip_set_netmask6(prefix)[0];
ip->ip6[1] &= NETMASK6(prefix)[1]; ip->ip6[1] &= ip_set_netmask6(prefix)[1];
ip->ip6[2] &= NETMASK6(prefix)[2]; ip->ip6[2] &= ip_set_netmask6(prefix)[2];
ip->ip6[3] &= NETMASK6(prefix)[3]; ip->ip6[3] &= ip_set_netmask6(prefix)[3];
} }
static inline void static inline void
@@ -393,7 +375,7 @@ hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
elem->cidr = cidr; elem->cidr = cidr;
} }
static inline bool static bool
hash_ipportnet6_data_list(struct sk_buff *skb, hash_ipportnet6_data_list(struct sk_buff *skb,
const struct hash_ipportnet6_elem *data) const struct hash_ipportnet6_elem *data)
{ {
@@ -408,13 +390,13 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_ipportnet6_data_tlist(struct sk_buff *skb, hash_ipportnet6_data_tlist(struct sk_buff *skb,
const struct hash_ipportnet6_elem *data) const struct hash_ipportnet6_elem *data)
{ {
const struct hash_ipportnet6_telem *e = const struct hash_ipportnet6_telem *e =
(const struct hash_ipportnet6_telem *)data; (const struct hash_ipportnet6_telem *)data;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
@@ -449,8 +431,8 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
if (adt == IPSET_TEST) if (adt == IPSET_TEST)
data.cidr = HOST_MASK; data.cidr = HOST_MASK;
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
@@ -476,14 +458,20 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_ipportnet_adt_policy)) hash_ipportnet_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
if (ret) if (ret)
return ret; return ret;
@@ -496,7 +484,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
ip6_netmask(&data.ip2, data.cidr); ip6_netmask(&data.ip2, data.cidr);
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -524,9 +512,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !tb[IPSET_ATTR_PORT_TO]) { !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
@@ -575,6 +563,11 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
hash_ipportnet_create_policy)) hash_ipportnet_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
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]) { if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE) if (hashsize < IPSET_MIMINAL_HASHSIZE)
@@ -609,7 +602,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET set->variant = set->family == AF_INET
? &hash_ipportnet4_tvariant ? &hash_ipportnet4_tvariant
: &hash_ipportnet6_tvariant; : &hash_ipportnet6_tvariant;
@@ -622,11 +615,11 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
set->variant = set->family == AF_INET set->variant = set->family == AF_INET
? &hash_ipportnet4_variant : &hash_ipportnet6_variant; ? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); h->table->htable_bits, h->maxelem, set->data, h->table);
return 0; return 0;
} }

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the hash:net type */ /* Kernel module implementing an IP set type: the hash:net type */
#include "ip_set_kernel.h"
#include "jhash.h" #include "jhash.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
@@ -45,7 +44,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
/* Member elements without timeout */ /* Member elements without timeout */
struct hash_net4_elem { struct hash_net4_elem {
u32 ip; __be32 ip;
u16 padding0; u16 padding0;
u8 padding1; u8 padding1;
u8 cidr; u8 cidr;
@@ -53,7 +52,7 @@ struct hash_net4_elem {
/* Member elements with timeout support */ /* Member elements with timeout support */
struct hash_net4_telem { struct hash_net4_telem {
u32 ip; __be32 ip;
u16 padding0; u16 padding0;
u8 padding1; u8 padding1;
u8 cidr; u8 cidr;
@@ -81,18 +80,10 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
dst->cidr = src->cidr; dst->cidr = src->cidr;
} }
static inline void
hash_net4_data_swap(struct hash_net4_elem *dst,
struct hash_net4_elem *src)
{
swap(dst->ip, src->ip);
swap(dst->cidr, src->cidr);
}
static inline void static inline void
hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr) hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
{ {
elem->ip &= NETMASK(cidr); elem->ip &= ip_set_netmask(cidr);
elem->cidr = cidr; elem->cidr = cidr;
} }
@@ -103,7 +94,7 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem)
elem->cidr = 0; elem->cidr = 0;
} }
static inline bool static bool
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
{ {
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
@@ -114,7 +105,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data) hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
{ {
const struct hash_net4_telem *tdata = const struct hash_net4_telem *tdata =
@@ -151,7 +142,7 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
data.cidr = HOST_MASK; data.cidr = HOST_MASK;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= NETMASK(data.cidr); data.ip &= ip_set_netmask(data.cidr);
return adtfn(set, &data, h->timeout); return adtfn(set, &data, h->timeout);
} }
@@ -177,10 +168,14 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_net_adt_policy)) hash_net_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
@@ -190,7 +185,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
if (!data.cidr) if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
data.ip &= NETMASK(data.cidr); data.ip &= ip_set_netmask(data.cidr);
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout)) if (!with_timeout(h->timeout))
@@ -210,8 +205,8 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b)
const struct ip_set_hash *y = b->data; const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */ /* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem return x->maxelem == y->maxelem &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
/* The type variant functions: IPv6 */ /* The type variant functions: IPv6 */
@@ -235,8 +230,8 @@ static inline bool
hash_net6_data_equal(const struct hash_net6_elem *ip1, hash_net6_data_equal(const struct hash_net6_elem *ip1,
const struct hash_net6_elem *ip2) const struct hash_net6_elem *ip2)
{ {
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
&& ip1->cidr == ip2->cidr; ip1->cidr == ip2->cidr;
} }
static inline bool static inline bool
@@ -253,16 +248,6 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
dst->cidr = src->cidr; dst->cidr = src->cidr;
} }
static inline void
hash_net6_data_swap(struct hash_net6_elem *dst, struct hash_net6_elem *src)
{
struct hash_net6_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_net6_data_zero_out(struct hash_net6_elem *elem) hash_net6_data_zero_out(struct hash_net6_elem *elem)
{ {
@@ -272,10 +257,10 @@ hash_net6_data_zero_out(struct hash_net6_elem *elem)
static inline void static inline void
ip6_netmask(union nf_inet_addr *ip, u8 prefix) ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{ {
ip->ip6[0] &= NETMASK6(prefix)[0]; ip->ip6[0] &= ip_set_netmask6(prefix)[0];
ip->ip6[1] &= NETMASK6(prefix)[1]; ip->ip6[1] &= ip_set_netmask6(prefix)[1];
ip->ip6[2] &= NETMASK6(prefix)[2]; ip->ip6[2] &= ip_set_netmask6(prefix)[2];
ip->ip6[3] &= NETMASK6(prefix)[3]; ip->ip6[3] &= ip_set_netmask6(prefix)[3];
} }
static inline void static inline void
@@ -285,7 +270,7 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
elem->cidr = cidr; elem->cidr = cidr;
} }
static inline bool static bool
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
{ {
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
@@ -296,7 +281,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data) hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
{ {
const struct hash_net6_telem *e = const struct hash_net6_telem *e =
@@ -353,10 +338,14 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_net_adt_policy)) hash_net_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
@@ -405,6 +394,11 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hash_net_create_policy)) hash_net_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
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]) { if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE) if (hashsize < IPSET_MIMINAL_HASHSIZE)
@@ -452,7 +446,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
? &hash_net4_variant : &hash_net6_variant; ? &hash_net4_variant : &hash_net6_variant;
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); h->table->htable_bits, h->maxelem, set->data, h->table);

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the hash:net,port type */ /* Kernel module implementing an IP set type: the hash:net,port type */
#include "ip_set_kernel.h"
#include "jhash.h" #include "jhash.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
@@ -46,16 +45,16 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
/* Member elements without timeout */ /* Member elements without timeout */
struct hash_netport4_elem { struct hash_netport4_elem {
u32 ip; __be32 ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 cidr; u8 cidr;
}; };
/* Member elements with timeout support */ /* Member elements with timeout support */
struct hash_netport4_telem { struct hash_netport4_telem {
u32 ip; __be32 ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 cidr; u8 cidr;
unsigned long timeout; unsigned long timeout;
@@ -65,10 +64,10 @@ static inline bool
hash_netport4_data_equal(const struct hash_netport4_elem *ip1, hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
const struct hash_netport4_elem *ip2) const struct hash_netport4_elem *ip2)
{ {
return ip1->ip == ip2->ip return ip1->ip == ip2->ip &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto ip1->proto == ip2->proto &&
&& ip1->cidr == ip2->cidr; ip1->cidr == ip2->cidr;
} }
static inline bool static inline bool
@@ -87,20 +86,10 @@ hash_netport4_data_copy(struct hash_netport4_elem *dst,
dst->cidr = src->cidr; dst->cidr = src->cidr;
} }
static inline void
hash_netport4_data_swap(struct hash_netport4_elem *dst,
struct hash_netport4_elem *src)
{
swap(dst->ip, src->ip);
swap(dst->port, src->port);
swap(dst->proto, src->proto);
swap(dst->cidr, src->cidr);
}
static inline void static inline void
hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr) hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
{ {
elem->ip &= NETMASK(cidr); elem->ip &= ip_set_netmask(cidr);
elem->cidr = cidr; elem->cidr = cidr;
} }
@@ -110,7 +99,7 @@ hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
elem->proto = 0; elem->proto = 0;
} }
static inline bool static bool
hash_netport4_data_list(struct sk_buff *skb, hash_netport4_data_list(struct sk_buff *skb,
const struct hash_netport4_elem *data) const struct hash_netport4_elem *data)
{ {
@@ -124,7 +113,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_netport4_data_tlist(struct sk_buff *skb, hash_netport4_data_tlist(struct sk_buff *skb,
const struct hash_netport4_elem *data) const struct hash_netport4_elem *data)
{ {
@@ -165,12 +154,12 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
if (adt == IPSET_TEST) if (adt == IPSET_TEST)
data.cidr = HOST_MASK; data.cidr = HOST_MASK;
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= NETMASK(data.cidr); data.ip &= ip_set_netmask(data.cidr);
return adtfn(set, &data, h->timeout); return adtfn(set, &data, h->timeout);
} }
@@ -202,10 +191,16 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_netport_adt_policy)) hash_netport_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
@@ -213,10 +208,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr) if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
data.ip &= NETMASK(data.cidr); data.ip &= ip_set_netmask(data.cidr);
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -244,9 +239,9 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !tb[IPSET_ATTR_PORT_TO]) { !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
@@ -275,22 +270,22 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b)
const struct ip_set_hash *y = b->data; const struct ip_set_hash *y = b->data;
/* Resizing changes htable_bits, so we ignore it */ /* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem return x->maxelem == y->maxelem &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
/* The type variant functions: IPv6 */ /* The type variant functions: IPv6 */
struct hash_netport6_elem { struct hash_netport6_elem {
union nf_inet_addr ip; union nf_inet_addr ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 cidr; u8 cidr;
}; };
struct hash_netport6_telem { struct hash_netport6_telem {
union nf_inet_addr ip; union nf_inet_addr ip;
u16 port; __be16 port;
u8 proto; u8 proto;
u8 cidr; u8 cidr;
unsigned long timeout; unsigned long timeout;
@@ -300,10 +295,10 @@ static inline bool
hash_netport6_data_equal(const struct hash_netport6_elem *ip1, hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
const struct hash_netport6_elem *ip2) const struct hash_netport6_elem *ip2)
{ {
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
&& ip1->port == ip2->port ip1->port == ip2->port &&
&& ip1->proto == ip2->proto ip1->proto == ip2->proto &&
&& ip1->cidr == ip2->cidr; ip1->cidr == ip2->cidr;
} }
static inline bool static inline bool
@@ -319,17 +314,6 @@ hash_netport6_data_copy(struct hash_netport6_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_netport6_data_swap(struct hash_netport6_elem *dst,
struct hash_netport6_elem *src)
{
struct hash_netport6_elem tmp;
memcpy(&tmp, dst, sizeof(tmp));
memcpy(dst, src, sizeof(tmp));
memcpy(src, &tmp, sizeof(tmp));
}
static inline void static inline void
hash_netport6_data_zero_out(struct hash_netport6_elem *elem) hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
{ {
@@ -339,10 +323,10 @@ hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
static inline void static inline void
ip6_netmask(union nf_inet_addr *ip, u8 prefix) ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{ {
ip->ip6[0] &= NETMASK6(prefix)[0]; ip->ip6[0] &= ip_set_netmask6(prefix)[0];
ip->ip6[1] &= NETMASK6(prefix)[1]; ip->ip6[1] &= ip_set_netmask6(prefix)[1];
ip->ip6[2] &= NETMASK6(prefix)[2]; ip->ip6[2] &= ip_set_netmask6(prefix)[2];
ip->ip6[3] &= NETMASK6(prefix)[3]; ip->ip6[3] &= ip_set_netmask6(prefix)[3];
} }
static inline void static inline void
@@ -352,7 +336,7 @@ hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
elem->cidr = cidr; elem->cidr = cidr;
} }
static inline bool static bool
hash_netport6_data_list(struct sk_buff *skb, hash_netport6_data_list(struct sk_buff *skb,
const struct hash_netport6_elem *data) const struct hash_netport6_elem *data)
{ {
@@ -366,7 +350,7 @@ nla_put_failure:
return 1; return 1;
} }
static inline bool static bool
hash_netport6_data_tlist(struct sk_buff *skb, hash_netport6_data_tlist(struct sk_buff *skb,
const struct hash_netport6_elem *data) const struct hash_netport6_elem *data)
{ {
@@ -406,8 +390,8 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
if (adt == IPSET_TEST) if (adt == IPSET_TEST)
data.cidr = HOST_MASK; data.cidr = HOST_MASK;
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC, if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto)) &data.port, &data.proto))
return -EINVAL; return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
@@ -432,10 +416,16 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
hash_netport_adt_policy)) hash_netport_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
if (ret) if (ret)
return ret; return ret;
@@ -446,7 +436,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
ip6_netmask(&data.ip, data.cidr); ip6_netmask(&data.ip, data.cidr);
if (tb[IPSET_ATTR_PORT]) if (tb[IPSET_ATTR_PORT])
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]); data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -474,9 +464,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (adt == IPSET_TEST if (adt == IPSET_TEST ||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP) ||
|| !tb[IPSET_ATTR_PORT_TO]) { !tb[IPSET_ATTR_PORT_TO]) {
ret = adtfn(set, &data, timeout); ret = adtfn(set, &data, timeout);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
} }
@@ -525,6 +515,11 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hash_netport_create_policy)) hash_netport_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
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]) { if (tb[IPSET_ATTR_HASHSIZE]) {
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]); hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
if (hashsize < IPSET_MIMINAL_HASHSIZE) if (hashsize < IPSET_MIMINAL_HASHSIZE)
@@ -572,7 +567,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
? &hash_netport4_variant : &hash_netport6_variant; ? &hash_netport4_variant : &hash_netport6_variant;
} }
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)", pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
set->name, jhash_size(h->table->htable_bits), set->name, jhash_size(h->table->htable_bits),
h->table->htable_bits, h->maxelem, set->data, h->table); h->table->htable_bits, h->maxelem, set->data, h->table);

View File

@@ -1,15 +0,0 @@
#ifndef _IP_SET_KERNEL_H
#define _IP_SET_KERNEL_H
#ifdef __KERNEL__
#ifdef CONFIG_DEBUG_KERNEL
/* Complete debug messages */
#define pr_fmt(fmt) "%s %s[%i]: " fmt "\n", __FILE__, __func__, __LINE__
#endif
#include <linux/kernel.h>
#endif /* __KERNEL__ */
#endif /*_IP_SET_H */

View File

@@ -7,7 +7,6 @@
/* Kernel module implementing an IP set type: the list:set type */ /* Kernel module implementing an IP set type: the list:set type */
#include "ip_set_kernel.h"
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
@@ -68,8 +67,8 @@ list_set_expired(const struct list_set *map, u32 id)
static inline int static inline int
list_set_exist(const struct set_telem *elem) list_set_exist(const struct set_telem *elem)
{ {
return elem->id != IPSET_INVALID_ID return elem->id != IPSET_INVALID_ID &&
&& !ip_set_timeout_expired(elem->timeout); !ip_set_timeout_expired(elem->timeout);
} }
/* Set list without and with timeout */ /* Set list without and with timeout */
@@ -122,22 +121,22 @@ static const struct nla_policy list_set_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
}; };
static inline bool static bool
next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id) next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
{ {
const struct set_elem *elem; const struct set_elem *elem;
if (i + 1 < map->size) { if (i + 1 < map->size) {
elem = list_set_elem(map, i + 1); elem = list_set_elem(map, i + 1);
return !!(elem->id == id return !!(elem->id == id &&
&& !(with_timeout(map->timeout) !(with_timeout(map->timeout) &&
&& list_set_expired(map, i + 1))); list_set_expired(map, i + 1)));
} }
return 0; return 0;
} }
static inline void static void
list_elem_add(struct list_set *map, u32 i, ip_set_id_t id) list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
{ {
struct set_elem *e; struct set_elem *e;
@@ -150,7 +149,7 @@ list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
} }
} }
static inline void static void
list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id, list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
unsigned long timeout) unsigned long timeout)
{ {
@@ -223,20 +222,22 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
list_set_adt_policy)) list_set_adt_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_NAME] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
if (tb[IPSET_ATTR_NAME]) { id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); if (id == IPSET_INVALID_ID)
if (id == IPSET_INVALID_ID) return -IPSET_ERR_NAME;
return -IPSET_ERR_NAME; /* "Loop detection" */
/* "Loop detection" */ if (s->type->features & IPSET_TYPE_NAME) {
if (s->type->features & IPSET_TYPE_NAME) { ret = -IPSET_ERR_LOOP;
ret = -IPSET_ERR_LOOP; goto finish;
goto finish; }
}
} else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_CADT_FLAGS]) { if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
@@ -270,8 +271,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
case IPSET_TEST: case IPSET_TEST:
for (i = 0; i < map->size && !ret; i++) { for (i = 0; i < map->size && !ret; i++) {
elem = list_set_elem(map, i); elem = list_set_elem(map, i);
if (elem->id == IPSET_INVALID_ID if (elem->id == IPSET_INVALID_ID ||
|| (before != 0 && i + 1 >= map->size)) (before != 0 && i + 1 >= map->size))
break; break;
else if (with_timeout && list_set_expired(map, i)) else if (with_timeout && list_set_expired(map, i))
continue; continue;
@@ -286,8 +287,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
case IPSET_ADD: case IPSET_ADD:
for (i = 0; i < map->size && !ret; i++) { for (i = 0; i < map->size && !ret; i++) {
elem = list_set_elem(map, i); elem = list_set_elem(map, i);
if (elem->id == id if (elem->id == id &&
&& !(with_timeout && list_set_expired(map, i))) !(with_timeout && list_set_expired(map, i)))
ret = -IPSET_ERR_EXIST; ret = -IPSET_ERR_EXIST;
} }
if (ret == -IPSET_ERR_EXIST) if (ret == -IPSET_ERR_EXIST)
@@ -318,14 +319,14 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
break; break;
} else if (with_timeout && list_set_expired(map, i)) } else if (with_timeout && list_set_expired(map, i))
continue; continue;
else if (elem->id == id else if (elem->id == id &&
&& (before == 0 (before == 0 ||
|| (before > 0 (before > 0 &&
&& next_id_eq(map, i, refid)))) next_id_eq(map, i, refid))))
ret = list_set_del(map, id, i); ret = list_set_del(map, id, i);
else if (before < 0 else if (before < 0 &&
&& elem->id == refid elem->id == refid &&
&& next_id_eq(map, i, id)) next_id_eq(map, i, id))
ret = list_set_del(map, id, i + 1); ret = list_set_del(map, id, i + 1);
} }
break; break;
@@ -449,8 +450,8 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
const struct list_set *x = a->data; const struct list_set *x = a->data;
const struct list_set *y = b->data; const struct list_set *y = b->data;
return x->size == y->size return x->size == y->size &&
&& x->timeout == y->timeout; x->timeout == y->timeout;
} }
static const struct ip_set_type_variant list_set = { static const struct ip_set_type_variant list_set = {
@@ -476,8 +477,8 @@ list_set_gc(unsigned long ul_set)
read_lock_bh(&set->lock); read_lock_bh(&set->lock);
for (i = map->size - 1; i >= 0; i--) { for (i = map->size - 1; i >= 0; i--) {
e = (struct set_telem *) list_set_elem(map, i); e = (struct set_telem *) list_set_elem(map, i);
if (e->id != IPSET_INVALID_ID if (e->id != IPSET_INVALID_ID &&
&& list_set_expired(map, i)) list_set_expired(map, i))
list_set_del(map, e->id, i); list_set_del(map, e->id, i);
} }
read_unlock_bh(&set->lock); read_unlock_bh(&set->lock);
@@ -486,7 +487,7 @@ list_set_gc(unsigned long ul_set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static inline void static void
list_set_gc_init(struct ip_set *set) list_set_gc_init(struct ip_set *set)
{ {
struct list_set *map = set->data; struct list_set *map = set->data;
@@ -506,7 +507,7 @@ list_set_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
}; };
static inline bool static bool
init_list_set(struct ip_set *set, u32 size, size_t dsize, init_list_set(struct ip_set *set, u32 size, size_t dsize,
unsigned long timeout) unsigned long timeout)
{ {
@@ -542,6 +543,10 @@ list_set_create(struct ip_set *set, struct nlattr *head, int len,
list_set_create_policy)) list_set_create_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_SIZE]) if (tb[IPSET_ATTR_SIZE])
size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]); size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
if (size < IP_SET_LIST_MIN_SIZE) if (size < IP_SET_LIST_MIN_SIZE)

View File

@@ -43,17 +43,17 @@ ip_set_timeout_uget(struct nlattr *tb)
static inline bool static inline bool
ip_set_timeout_test(unsigned long timeout) ip_set_timeout_test(unsigned long timeout)
{ {
return timeout != IPSET_ELEM_UNSET return timeout != IPSET_ELEM_UNSET &&
&& (timeout == IPSET_ELEM_PERMANENT (timeout == IPSET_ELEM_PERMANENT ||
|| time_after(timeout, jiffies)); time_after(timeout, jiffies));
} }
static inline bool static inline bool
ip_set_timeout_expired(unsigned long timeout) ip_set_timeout_expired(unsigned long timeout)
{ {
return timeout != IPSET_ELEM_UNSET return timeout != IPSET_ELEM_UNSET &&
&& timeout != IPSET_ELEM_PERMANENT timeout != IPSET_ELEM_PERMANENT &&
&& time_before(timeout, jiffies); time_before(timeout, jiffies);
} }
static inline unsigned long static inline unsigned long
@@ -88,15 +88,15 @@ ip_set_timeout_get(unsigned long timeout)
static inline bool static inline bool
ip_set_timeout_test(unsigned long timeout) ip_set_timeout_test(unsigned long timeout)
{ {
return timeout == IPSET_ELEM_PERMANENT return timeout == IPSET_ELEM_PERMANENT ||
|| time_after(timeout, jiffies); time_after(timeout, jiffies);
} }
static inline bool static inline bool
ip_set_timeout_expired(unsigned long timeout) ip_set_timeout_expired(unsigned long timeout)
{ {
return timeout != IPSET_ELEM_PERMANENT return timeout != IPSET_ELEM_PERMANENT &&
&& time_before(timeout, jiffies); time_before(timeout, jiffies);
} }
static inline unsigned long static inline unsigned long

View File

@@ -14,7 +14,7 @@
* This table works for both IPv4 and IPv6; * This table works for both IPv4 and IPv6;
* just use prefixlen_netmask_map[prefixlength].ip. * just use prefixlen_netmask_map[prefixlength].ip.
*/ */
const union nf_inet_addr prefixlen_netmask_map[] = { const union nf_inet_addr ip_set_netmask_map[] = {
E(0x00000000, 0x00000000, 0x00000000, 0x00000000), E(0x00000000, 0x00000000, 0x00000000, 0x00000000),
E(0x80000000, 0x00000000, 0x00000000, 0x00000000), E(0x80000000, 0x00000000, 0x00000000, 0x00000000),
E(0xC0000000, 0x00000000, 0x00000000, 0x00000000), E(0xC0000000, 0x00000000, 0x00000000, 0x00000000),
@@ -145,17 +145,19 @@ const union nf_inet_addr prefixlen_netmask_map[] = {
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE), E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE),
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF), E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
}; };
EXPORT_SYMBOL_GPL(prefixlen_netmask_map); EXPORT_SYMBOL_GPL(ip_set_netmask_map);
#undef E #undef E
#define E(a, b, c, d) \ #define E(a, b, c, d) \
{.ip6 = { a, b, c, d } } {.ip6 = { (__force __be32) a, (__force __be32) b, \
(__force __be32) c, (__force __be32) d, \
} }
/* /*
* This table works for both IPv4 and IPv6; * This table works for both IPv4 and IPv6;
* just use prefixlen_hostmask_map[prefixlength].ip. * just use prefixlen_hostmask_map[prefixlength].ip.
*/ */
const union nf_inet_addr prefixlen_hostmask_map[] = { const union nf_inet_addr ip_set_hostmask_map[] = {
E(0x00000000, 0x00000000, 0x00000000, 0x00000000), E(0x00000000, 0x00000000, 0x00000000, 0x00000000),
E(0x80000000, 0x00000000, 0x00000000, 0x00000000), E(0x80000000, 0x00000000, 0x00000000, 0x00000000),
E(0xC0000000, 0x00000000, 0x00000000, 0x00000000), E(0xC0000000, 0x00000000, 0x00000000, 0x00000000),
@@ -286,4 +288,4 @@ const union nf_inet_addr prefixlen_hostmask_map[] = {
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE), E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE),
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF), E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
}; };
EXPORT_SYMBOL_GPL(prefixlen_hostmask_map); EXPORT_SYMBOL_GPL(ip_set_hostmask_map);

View File

@@ -5,12 +5,31 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
/* Prefixlen maps, by Jan Engelhardt */ /* Prefixlen maps, by Jan Engelhardt */
extern const union nf_inet_addr prefixlen_netmask_map[]; extern const union nf_inet_addr ip_set_netmask_map[];
extern const union nf_inet_addr prefixlen_hostmask_map[]; extern const union nf_inet_addr ip_set_hostmask_map[];
#define NETMASK(n) prefixlen_netmask_map[n].ip static inline __be32
#define NETMASK6(n) prefixlen_netmask_map[n].ip6 ip_set_netmask(u8 pfxlen)
#define HOSTMASK(n) prefixlen_hostmask_map[n].ip {
#define HOSTMASK6(n) prefixlen_hostmask_map[n].ip6 return ip_set_netmask_map[pfxlen].ip;
}
static inline const __be32 *
ip_set_netmask6(u8 pfxlen)
{
return &ip_set_netmask_map[pfxlen].ip6[0];
}
static inline u32
ip_set_hostmask(u8 pfxlen)
{
return (__force u32) ip_set_hostmask_map[pfxlen].ip;
}
static inline const __be32 *
ip_set_hostmask6(u8 pfxlen)
{
return &ip_set_hostmask_map[pfxlen].ip6[0];
}
#endif /*_PFXLEN_H */ #endif /*_PFXLEN_H */

View File

@@ -108,12 +108,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
index = ip_set_nfnl_get_byindex(info->match_set.index); index = ip_set_nfnl_get_byindex(info->match_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match", pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index); info->match_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("That's nasty!"); pr_warning("That's nasty!\n");
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
@@ -167,7 +167,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
if (info->add_set.index != IPSET_INVALID_ID) { if (info->add_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->add_set.index); index = ip_set_nfnl_get_byindex(info->add_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("cannot find add_set index %u as target", pr_warning("cannot find add_set index %u as target\n",
info->add_set.index); info->add_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
@@ -176,14 +176,14 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
if (info->del_set.index != IPSET_INVALID_ID) { if (info->del_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->del_set.index); index = ip_set_nfnl_get_byindex(info->del_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("cannot find del_set index %u as target", pr_warning("cannot find del_set index %u as target\n",
info->del_set.index); info->del_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
} }
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|| info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("That's nasty!"); pr_warning("That's nasty!\n");
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
@@ -237,12 +237,12 @@ set_match_checkentry(const struct xt_mtchk_param *par)
index = ip_set_nfnl_get_byindex(info->match_set.index); index = ip_set_nfnl_get_byindex(info->match_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match", pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index); info->match_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
if (info->match_set.dim > IPSET_DIM_MAX) { if (info->match_set.dim > IPSET_DIM_MAX) {
pr_warning("That's nasty!"); pr_warning("That's nasty!\n");
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
@@ -295,7 +295,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
if (info->add_set.index != IPSET_INVALID_ID) { if (info->add_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->add_set.index); index = ip_set_nfnl_get_byindex(info->add_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("cannot find add_set index %u as target", pr_warning("cannot find add_set index %u as target\n",
info->add_set.index); info->add_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
@@ -304,14 +304,14 @@ set_target_checkentry(const struct xt_tgchk_param *par)
if (info->del_set.index != IPSET_INVALID_ID) { if (info->del_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->del_set.index); index = ip_set_nfnl_get_byindex(info->del_set.index);
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("cannot find del_set index %u as target", pr_warning("cannot find del_set index %u as target\n",
info->del_set.index); info->del_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }
} }
if (info->add_set.dim > IPSET_DIM_MAX if (info->add_set.dim > IPSET_DIM_MAX ||
|| info->del_set.flags > IPSET_DIM_MAX) { info->del_set.flags > IPSET_DIM_MAX) {
pr_warning("That's nasty!"); pr_warning("That's nasty!\n");
return CHECK_FAIL; /* error */ return CHECK_FAIL; /* error */
} }