mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-06 04:35:12 +02:00
Merge branch 'ipset-6'
This commit is contained in:
2
README
2
README
@@ -19,7 +19,7 @@ simplified, and sped up.
|
||||
Included in this package
|
||||
========================
|
||||
- ipset 4.5
|
||||
- ipset 5.4.1
|
||||
- ipset 6.6a-genl
|
||||
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
|
||||
|
||||
|
||||
|
@@ -21,4 +21,4 @@ ipset_SOURCES = src/ipset.c src/errcode.c src/ui.c src/ipset_bitmap_ip.c \
|
||||
src/ipset_list_set.c
|
||||
ipset_LDADD = libipset.la
|
||||
|
||||
man_MANS = ipset.8
|
||||
man_MANS = src/ipset.8
|
||||
|
@@ -44,6 +44,7 @@ enum ipset_opt {
|
||||
IPSET_OPT_NAMEREF,
|
||||
IPSET_OPT_IP2,
|
||||
IPSET_OPT_CIDR2,
|
||||
IPSET_OPT_IP2_TO,
|
||||
IPSET_OPT_PROTO,
|
||||
/* Swap/rename to */
|
||||
IPSET_OPT_SETNAME2,
|
||||
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 6
|
||||
#define IPSET_PROTOCOL 0x60
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -104,6 +104,7 @@ enum {
|
||||
IPSET_ATTR_NAMEREF,
|
||||
IPSET_ATTR_IP2,
|
||||
IPSET_ATTR_CIDR2,
|
||||
IPSET_ATTR_IP2_TO,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
@@ -142,6 +143,10 @@ enum ipset_errno {
|
||||
enum ipset_cmd_flags {
|
||||
IPSET_FLAG_BIT_EXIST = 0,
|
||||
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
|
||||
IPSET_FLAG_BIT_LIST_SETNAME = 1,
|
||||
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
|
||||
IPSET_FLAG_BIT_LIST_HEADER = 2,
|
||||
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
|
||||
};
|
||||
|
||||
/* Flags at CADT attribute level */
|
||||
|
@@ -11,6 +11,10 @@ enum {
|
||||
IPSET_ERR_INVALID_PROTO,
|
||||
/* Protocol missing but must be specified */
|
||||
IPSET_ERR_MISSING_PROTO,
|
||||
/* Range not supported */
|
||||
IPSET_ERR_HASH_RANGE_UNSUPPORTED,
|
||||
/* Invalid range */
|
||||
IPSET_ERR_HASH_RANGE,
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_HASH_H */
|
||||
|
@@ -60,6 +60,8 @@ extern int ipset_parse_ipnet(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ip4_single6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ip4_net6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_name(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_before(struct ipset_session *session,
|
||||
|
@@ -65,6 +65,10 @@ enum ipset_envopt {
|
||||
IPSET_ENV_RESOLVE = (1 << IPSET_ENV_BIT_RESOLVE),
|
||||
IPSET_ENV_BIT_EXIST = 3,
|
||||
IPSET_ENV_EXIST = (1 << IPSET_ENV_BIT_EXIST),
|
||||
IPSET_ENV_BIT_LIST_SETNAME = 4,
|
||||
IPSET_ENV_LIST_SETNAME = (1 << IPSET_ENV_BIT_LIST_SETNAME),
|
||||
IPSET_ENV_BIT_LIST_HEADER = 5,
|
||||
IPSET_ENV_LIST_HEADER = (1 << IPSET_ENV_BIT_LIST_HEADER),
|
||||
};
|
||||
|
||||
extern int ipset_envopt_parse(struct ipset_session *session,
|
||||
@@ -92,4 +96,6 @@ typedef int (*ipset_outfn)(const char *fmt, ...)
|
||||
extern struct ipset_session * ipset_session_init(ipset_outfn outfn);
|
||||
extern int ipset_session_fini(struct ipset_session *session);
|
||||
|
||||
extern void ipset_debug_msg(const char *dir, void *buffer, int len);
|
||||
|
||||
#endif /* LIBIPSET_SESSION_H */
|
||||
|
@@ -14,7 +14,7 @@
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 6
|
||||
#define IPSET_PROTOCOL 0x60
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -106,6 +106,7 @@ enum {
|
||||
IPSET_ATTR_NAMEREF,
|
||||
IPSET_ATTR_IP2,
|
||||
IPSET_ATTR_CIDR2,
|
||||
IPSET_ATTR_IP2_TO,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
@@ -144,6 +145,10 @@ enum ipset_errno {
|
||||
enum ipset_cmd_flags {
|
||||
IPSET_FLAG_BIT_EXIST = 0,
|
||||
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
|
||||
IPSET_FLAG_BIT_LIST_SETNAME = 1,
|
||||
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
|
||||
IPSET_FLAG_BIT_LIST_HEADER = 2,
|
||||
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
|
||||
};
|
||||
|
||||
/* Flags at CADT attribute level */
|
||||
@@ -167,6 +172,7 @@ enum ipset_adt {
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
@@ -219,6 +225,15 @@ struct ip_set;
|
||||
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
|
||||
u32 timeout, u32 flags);
|
||||
|
||||
/* Kernel API function options */
|
||||
struct ip_set_adt_opt {
|
||||
u8 family; /* Actual protocol family */
|
||||
u8 dim; /* Dimension of match/target */
|
||||
u8 flags; /* Direction and negation flags */
|
||||
u32 cmdflags; /* Command-like flags */
|
||||
u32 timeout; /* Timeout value */
|
||||
};
|
||||
|
||||
/* Set type, variant-specific part */
|
||||
struct ip_set_type_variant {
|
||||
/* Kernelspace: test/add/del entries
|
||||
@@ -226,14 +241,15 @@ struct ip_set_type_variant {
|
||||
* zero for no match/success to add/delete
|
||||
* positive for matching element */
|
||||
int (*kadt)(struct ip_set *set, const struct sk_buff * skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
|
||||
|
||||
/* Userspace: test/add/del entries
|
||||
* returns negative error code,
|
||||
* zero for no match/success to add/delete
|
||||
* positive for matching element */
|
||||
int (*uadt)(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
|
||||
|
||||
/* Low level add/del/test functions */
|
||||
ipset_adtfn adt[IPSET_ADT_MAX];
|
||||
@@ -271,8 +287,8 @@ struct ip_set_type {
|
||||
u8 dimension;
|
||||
/* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
|
||||
u8 family;
|
||||
/* Type revision */
|
||||
u8 revision;
|
||||
/* Type revisions */
|
||||
u8 revision_min, revision_max;
|
||||
|
||||
/* Create set */
|
||||
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
|
||||
@@ -303,6 +319,8 @@ struct ip_set {
|
||||
const struct ip_set_type_variant *variant;
|
||||
/* The actual INET family of the set */
|
||||
u8 family;
|
||||
/* The type revision */
|
||||
u8 revision;
|
||||
/* The type specific data */
|
||||
void *data;
|
||||
};
|
||||
@@ -316,12 +334,16 @@ extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
|
||||
extern void ip_set_nfnl_put(ip_set_id_t index);
|
||||
|
||||
/* API for iptables set match, and SET target */
|
||||
|
||||
extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
|
||||
/* Utility functions */
|
||||
extern void * ip_set_alloc(size_t size);
|
||||
|
@@ -5,6 +5,11 @@
|
||||
#include "jhash.h"
|
||||
#include "ip_set_timeout.h"
|
||||
|
||||
#define CONCAT(a, b, c) a##b##c
|
||||
#define TOKEN(a, b, c) CONCAT(a, b, c)
|
||||
|
||||
#define type_pf_next TOKEN(TYPE, PF, _elem)
|
||||
|
||||
/* Hashing which uses arrays to resolve clashing. The hash table is resized
|
||||
* (doubled) when searching becomes too long.
|
||||
* Internally jhash is used with the assumption that the size of the
|
||||
@@ -54,6 +59,7 @@ struct ip_set_hash {
|
||||
u32 initval; /* random jhash init value */
|
||||
u32 timeout; /* timeout value, if enabled */
|
||||
struct timer_list gc; /* garbage collection when timeout enabled */
|
||||
struct type_pf_next next; /* temporary storage for uadd */
|
||||
#ifdef IP_SET_HASH_WITH_NETMASK
|
||||
u8 netmask; /* netmask value for subnets to store */
|
||||
#endif
|
||||
@@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set)
|
||||
#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask)
|
||||
#define type_pf_data_list TOKEN(TYPE, PF, _data_list)
|
||||
#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist)
|
||||
#define type_pf_data_next TOKEN(TYPE, PF, _data_next)
|
||||
|
||||
#define type_pf_elem TOKEN(TYPE, PF, _elem)
|
||||
#define type_pf_telem TOKEN(TYPE, PF, _telem)
|
||||
@@ -346,6 +353,9 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);
|
||||
|
||||
/* Add an element to a hash and update the internal counters when succeeded,
|
||||
* otherwise report the proper error code. */
|
||||
static int
|
||||
@@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
}
|
||||
|
||||
ret = type_pf_elem_add(n, value);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
if (ret == -EAGAIN)
|
||||
type_pf_data_next(h, d);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
add_cidr(h, d->cidr, HOST_MASK);
|
||||
@@ -586,10 +599,11 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
|
||||
static int
|
||||
type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
|
||||
|
||||
static const struct ip_set_type_variant type_pf_variant = {
|
||||
.kadt = type_pf_kadt,
|
||||
@@ -821,8 +835,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
goto out;
|
||||
}
|
||||
ret = type_pf_elem_tadd(n, d, timeout);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
if (ret == -EAGAIN)
|
||||
type_pf_data_next(h, d);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
add_cidr(h, d->cidr, HOST_MASK);
|
||||
@@ -840,7 +857,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
struct htable *t = h->table;
|
||||
const struct type_pf_elem *d = value;
|
||||
struct hbucket *n;
|
||||
int i, ret = 0;
|
||||
int i;
|
||||
struct type_pf_elem *data;
|
||||
u32 key;
|
||||
|
||||
@@ -851,7 +868,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
if (!type_pf_data_equal(data, d))
|
||||
continue;
|
||||
if (type_pf_data_expired(data))
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
return -IPSET_ERR_EXIST;
|
||||
if (i != n->pos - 1)
|
||||
/* Not last one */
|
||||
type_pf_data_copy(data, ahash_tdata(n, n->pos - 1));
|
||||
|
@@ -219,24 +219,25 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip;
|
||||
|
||||
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
ip = ip_to_id(map, ip);
|
||||
|
||||
return adtfn(set, &ip, map->timeout, flags);
|
||||
return adtfn(set, &ip, opt_timeout(opt, map), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -283,8 +284,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -478,7 +478,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
@@ -551,7 +551,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_INET,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
|
@@ -338,17 +338,18 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct ipmac data;
|
||||
|
||||
/* MAC can be src only */
|
||||
if (!(flags & IPSET_DIM_TWO_SRC))
|
||||
if (!(opt->flags & IPSET_DIM_TWO_SRC))
|
||||
return 0;
|
||||
|
||||
data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||
data.id = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
|
||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
@@ -360,12 +361,12 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
data.id -= map->first_ip;
|
||||
data.ether = eth_hdr(skb)->h_source;
|
||||
|
||||
return adtfn(set, &data, map->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, map), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -578,7 +579,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
@@ -623,7 +624,8 @@ static struct ip_set_type bitmap_ipmac_type = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_INET,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_ipmac_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
|
@@ -208,14 +208,16 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
__be16 __port;
|
||||
u16 port = 0;
|
||||
|
||||
if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
|
||||
if (!ip_set_get_ip_port(skb, opt->family,
|
||||
opt->flags & IPSET_DIM_ONE_SRC, &__port))
|
||||
return -EINVAL;
|
||||
|
||||
port = ntohs(__port);
|
||||
@@ -225,12 +227,12 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
|
||||
port -= map->first_port;
|
||||
|
||||
return adtfn(set, &port, map->timeout, flags);
|
||||
return adtfn(set, &port, opt_timeout(opt, map), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -482,7 +484,8 @@ static struct ip_set_type bitmap_port_type = {
|
||||
.features = IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_port_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include "ip_set.h"
|
||||
#include <net/genetlink.h>
|
||||
@@ -75,7 +76,8 @@ find_set_type(const char *name, u8 family, u8 revision)
|
||||
list_for_each_entry_rcu(type, &ip_set_type_list, list)
|
||||
if (STREQ(type->name, name) &&
|
||||
(type->family == family || type->family == AF_UNSPEC) &&
|
||||
type->revision == revision)
|
||||
revision >= type->revision_min &&
|
||||
revision <= type->revision_max)
|
||||
return type;
|
||||
return NULL;
|
||||
}
|
||||
@@ -148,10 +150,10 @@ retry:
|
||||
if (STREQ(type->name, name) &&
|
||||
(type->family == family || type->family == AF_UNSPEC)) {
|
||||
found = true;
|
||||
if (type->revision < *min)
|
||||
*min = type->revision;
|
||||
if (type->revision > *max)
|
||||
*max = type->revision;
|
||||
if (type->revision_min < *min)
|
||||
*min = type->revision_min;
|
||||
if (type->revision_max > *max)
|
||||
*max = type->revision_max;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (found)
|
||||
@@ -175,25 +177,27 @@ ip_set_type_register(struct ip_set_type *type)
|
||||
int ret = 0;
|
||||
|
||||
if (type->protocol != IPSET_PROTOCOL) {
|
||||
pr_warning("ip_set type %s, family %s, revision %u uses "
|
||||
pr_warning("ip_set type %s, family %s, revision %u:%u uses "
|
||||
"wrong protocol version %u (want %u)\n",
|
||||
type->name, family_name(type->family),
|
||||
type->revision, type->protocol, IPSET_PROTOCOL);
|
||||
type->revision_min, type->revision_max,
|
||||
type->protocol, IPSET_PROTOCOL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ip_set_type_lock();
|
||||
if (find_set_type(type->name, type->family, type->revision)) {
|
||||
if (find_set_type(type->name, type->family, type->revision_min)) {
|
||||
/* Duplicate! */
|
||||
pr_warning("ip_set type %s, family %s, revision %u "
|
||||
pr_warning("ip_set type %s, family %s with revision min %u "
|
||||
"already registered!\n", type->name,
|
||||
family_name(type->family), type->revision);
|
||||
family_name(type->family), type->revision_min);
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
list_add_rcu(&type->list, &ip_set_type_list);
|
||||
pr_debug("type %s, family %s, revision %u registered.\n",
|
||||
type->name, family_name(type->family), type->revision);
|
||||
pr_debug("type %s, family %s, revision %u:%u registered.\n",
|
||||
type->name, family_name(type->family),
|
||||
type->revision_min, type->revision_max);
|
||||
unlock:
|
||||
ip_set_type_unlock();
|
||||
return ret;
|
||||
@@ -205,15 +209,15 @@ void
|
||||
ip_set_type_unregister(struct ip_set_type *type)
|
||||
{
|
||||
ip_set_type_lock();
|
||||
if (!find_set_type(type->name, type->family, type->revision)) {
|
||||
pr_warning("ip_set type %s, family %s, revision %u "
|
||||
if (!find_set_type(type->name, type->family, type->revision_min)) {
|
||||
pr_warning("ip_set type %s, family %s with revision min %u "
|
||||
"not registered\n", type->name,
|
||||
family_name(type->family), type->revision);
|
||||
family_name(type->family), type->revision_min);
|
||||
goto unlock;
|
||||
}
|
||||
list_del_rcu(&type->list);
|
||||
pr_debug("type %s, family %s, revision %u unregistered.\n",
|
||||
type->name, family_name(type->family), type->revision);
|
||||
pr_debug("type %s, family %s with revision min %u unregistered.\n",
|
||||
type->name, family_name(type->family), type->revision_min);
|
||||
unlock:
|
||||
ip_set_type_unlock();
|
||||
|
||||
@@ -346,7 +350,8 @@ __ip_set_put(ip_set_id_t index)
|
||||
|
||||
int
|
||||
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret = 0;
|
||||
@@ -354,19 +359,19 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
!(family == set->family || set->family == AF_UNSPEC))
|
||||
if (opt->dim < set->type->dimension ||
|
||||
!(opt->family == set->family || set->family == AF_UNSPEC))
|
||||
return 0;
|
||||
|
||||
read_lock_bh(&set->lock);
|
||||
ret = set->variant->kadt(set, skb, IPSET_TEST, family, dim, flags);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);
|
||||
read_unlock_bh(&set->lock);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
/* Type requests element to be completed */
|
||||
pr_debug("element must be competed, ADD is triggered\n");
|
||||
write_lock_bh(&set->lock);
|
||||
set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
|
||||
set->variant->kadt(set, skb, par, IPSET_ADD, opt);
|
||||
write_unlock_bh(&set->lock);
|
||||
ret = 1;
|
||||
}
|
||||
@@ -378,7 +383,8 @@ EXPORT_SYMBOL_GPL(ip_set_test);
|
||||
|
||||
int
|
||||
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret;
|
||||
@@ -386,12 +392,12 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
!(family == set->family || set->family == AF_UNSPEC))
|
||||
if (opt->dim < set->type->dimension ||
|
||||
!(opt->family == set->family || set->family == AF_UNSPEC))
|
||||
return 0;
|
||||
|
||||
write_lock_bh(&set->lock);
|
||||
ret = set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
return ret;
|
||||
@@ -400,7 +406,8 @@ EXPORT_SYMBOL_GPL(ip_set_add);
|
||||
|
||||
int
|
||||
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret = 0;
|
||||
@@ -408,12 +415,12 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
!(family == set->family || set->family == AF_UNSPEC))
|
||||
if (opt->dim < set->type->dimension ||
|
||||
!(opt->family == set->family || set->family == AF_UNSPEC))
|
||||
return 0;
|
||||
|
||||
write_lock_bh(&set->lock);
|
||||
ret = set->variant->kadt(set, skb, IPSET_DEL, family, dim, flags);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
return ret;
|
||||
@@ -668,6 +675,7 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
rwlock_init(&set->lock);
|
||||
strlcpy(set->name, name, IPSET_MAXNAMELEN);
|
||||
set->family = family;
|
||||
set->revision = revision;
|
||||
|
||||
/*
|
||||
* Next, check that we know the type, and take
|
||||
@@ -708,7 +716,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
(flags & IPSET_FLAG_EXIST) &&
|
||||
STREQ(set->type->name, clash->type->name) &&
|
||||
set->type->family == clash->type->family &&
|
||||
set->type->revision == clash->type->revision &&
|
||||
set->type->revision_min == clash->type->revision_min &&
|
||||
set->type->revision_max == clash->type->revision_max &&
|
||||
set->variant->same_set(set, clash))
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
@@ -778,7 +787,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
|
||||
ret = IPSET_ERR_BUSY;
|
||||
ret = -IPSET_ERR_BUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -825,7 +834,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
|
||||
ip_set_id_t i;
|
||||
|
||||
if (unlikely(protocol_failed(attr)))
|
||||
return -EPROTO;
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++)
|
||||
@@ -947,10 +956,13 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
/* List/save set data */
|
||||
|
||||
#define DUMP_INIT 0L
|
||||
#define DUMP_ALL 1L
|
||||
#define DUMP_ONE 2L
|
||||
#define DUMP_LAST 3L
|
||||
#define DUMP_INIT 0
|
||||
#define DUMP_ALL 1
|
||||
#define DUMP_ONE 2
|
||||
#define DUMP_LAST 3
|
||||
|
||||
#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF)
|
||||
#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16)
|
||||
|
||||
static int
|
||||
ip_set_dump_done(struct netlink_callback *cb)
|
||||
@@ -983,6 +995,7 @@ dump_init(struct netlink_callback *cb)
|
||||
int min_len = NLMSG_SPACE(sizeof(struct genlmsghdr));
|
||||
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
|
||||
struct nlattr *attr = (void *)nlh + min_len;
|
||||
u32 dump_type;
|
||||
ip_set_id_t index;
|
||||
|
||||
/* Second pass, so parser can't fail */
|
||||
@@ -994,17 +1007,22 @@ dump_init(struct netlink_callback *cb)
|
||||
* [..]: type specific
|
||||
*/
|
||||
|
||||
if (!cda[IPSET_ATTR_SETNAME]) {
|
||||
cb->args[0] = DUMP_ALL;
|
||||
return 0;
|
||||
if (cda[IPSET_ATTR_SETNAME]) {
|
||||
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
|
||||
if (index == IPSET_INVALID_ID)
|
||||
return -ENOENT;
|
||||
|
||||
dump_type = DUMP_ONE;
|
||||
cb->args[1] = index;
|
||||
} else
|
||||
dump_type = DUMP_ALL;
|
||||
|
||||
if (cda[IPSET_ATTR_FLAGS]) {
|
||||
u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
|
||||
dump_type |= (f << 16);
|
||||
}
|
||||
cb->args[0] = dump_type;
|
||||
|
||||
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
|
||||
if (index == IPSET_INVALID_ID)
|
||||
return -ENOENT;
|
||||
|
||||
cb->args[0] = DUMP_ONE;
|
||||
cb->args[1] = index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1015,9 +1033,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
struct ip_set *set = NULL;
|
||||
struct genlmsg_buf *nlh = NULL;
|
||||
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
|
||||
u32 dump_type, dump_flags;
|
||||
int ret = 0;
|
||||
|
||||
if (cb->args[0] == DUMP_INIT) {
|
||||
if (!cb->args[0]) {
|
||||
ret = dump_init(cb);
|
||||
if (ret < 0) {
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
|
||||
@@ -1032,13 +1051,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (cb->args[1] >= ip_set_max)
|
||||
goto out;
|
||||
|
||||
pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
|
||||
max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
|
||||
dump_type = DUMP_TYPE(cb->args[0]);
|
||||
dump_flags = DUMP_FLAGS(cb->args[0]);
|
||||
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
|
||||
dump_last:
|
||||
pr_debug("args[0]: %u %u args[1]: %ld\n",
|
||||
dump_type, dump_flags, cb->args[1]);
|
||||
for (; cb->args[1] < max; cb->args[1]++) {
|
||||
index = (ip_set_id_t) cb->args[1];
|
||||
set = ip_set_list[index];
|
||||
if (set == NULL) {
|
||||
if (cb->args[0] == DUMP_ONE) {
|
||||
if (dump_type == DUMP_ONE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
@@ -1047,9 +1070,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
/* When dumping all sets, we must dump "sorted"
|
||||
* so that lists (unions of sets) are dumped last.
|
||||
*/
|
||||
if (cb->args[0] != DUMP_ONE &&
|
||||
!((cb->args[0] == DUMP_ALL) ^
|
||||
(set->type->features & IPSET_DUMP_LAST)))
|
||||
if (dump_type != DUMP_ONE &&
|
||||
((dump_type == DUMP_ALL) ==
|
||||
!!(set->type->features & IPSET_DUMP_LAST)))
|
||||
continue;
|
||||
pr_debug("List set: %s\n", set->name);
|
||||
if (!cb->args[2]) {
|
||||
@@ -1066,6 +1089,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
}
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
|
||||
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
|
||||
goto next_set;
|
||||
switch (cb->args[2]) {
|
||||
case 0:
|
||||
/* Core header data */
|
||||
@@ -1074,40 +1099,45 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
|
||||
set->family);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
|
||||
set->type->revision);
|
||||
set->revision);
|
||||
ret = set->variant->head(set, skb);
|
||||
if (ret < 0)
|
||||
goto release_refcount;
|
||||
if (dump_flags & IPSET_FLAG_LIST_HEADER)
|
||||
goto next_set;
|
||||
/* Fall through and add elements */
|
||||
default:
|
||||
read_lock_bh(&set->lock);
|
||||
ret = set->variant->list(set, skb, cb);
|
||||
read_unlock_bh(&set->lock);
|
||||
if (!cb->args[2]) {
|
||||
if (!cb->args[2])
|
||||
/* Set is done, proceed with next one */
|
||||
if (cb->args[0] == DUMP_ONE)
|
||||
cb->args[1] = IPSET_INVALID_ID;
|
||||
else
|
||||
cb->args[1]++;
|
||||
}
|
||||
goto next_set;
|
||||
goto release_refcount;
|
||||
}
|
||||
}
|
||||
/* If we dump all sets, continue with dumping last ones */
|
||||
if (dump_type == DUMP_ALL) {
|
||||
dump_type = DUMP_LAST;
|
||||
cb->args[0] = dump_type | (dump_flags << 16);
|
||||
cb->args[1] = 0;
|
||||
goto dump_last;
|
||||
}
|
||||
goto out;
|
||||
|
||||
nla_put_failure:
|
||||
ret = -EFAULT;
|
||||
next_set:
|
||||
if (dump_type == DUMP_ONE)
|
||||
cb->args[1] = IPSET_INVALID_ID;
|
||||
else
|
||||
cb->args[1]++;
|
||||
release_refcount:
|
||||
/* If there was an error or set is done, release set */
|
||||
if (ret || !cb->args[2]) {
|
||||
pr_debug("release set %s\n", ip_set_list[index]->name);
|
||||
ip_set_put_byindex(index);
|
||||
}
|
||||
|
||||
/* If we dump all sets, continue with dumping last ones */
|
||||
if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
|
||||
cb->args[0] = DUMP_LAST;
|
||||
|
||||
out:
|
||||
if (nlh) {
|
||||
genlmsg_end(skb, nlh);
|
||||
@@ -1153,17 +1183,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
|
||||
struct nlattr *tb[], enum ipset_adt adt,
|
||||
u32 flags, bool use_lineno)
|
||||
{
|
||||
int ret, retried = 0;
|
||||
int ret;
|
||||
u32 lineno = 0;
|
||||
bool eexist = flags & IPSET_FLAG_EXIST;
|
||||
bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
|
||||
|
||||
do {
|
||||
write_lock_bh(&set->lock);
|
||||
ret = set->variant->uadt(set, tb, adt, &lineno, flags);
|
||||
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
|
||||
write_unlock_bh(&set->lock);
|
||||
retried = true;
|
||||
} while (ret == -EAGAIN &&
|
||||
set->variant->resize &&
|
||||
(ret = set->variant->resize(set, retried++)) == 0);
|
||||
(ret = set->variant->resize(set, retried)) == 0);
|
||||
|
||||
if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
|
||||
return 0;
|
||||
@@ -1338,7 +1369,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
read_lock_bh(&set->lock);
|
||||
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
|
||||
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0);
|
||||
read_unlock_bh(&set->lock);
|
||||
/* Userspace can't trigger element to be re-added */
|
||||
if (ret == -EAGAIN)
|
||||
@@ -1381,7 +1412,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
|
||||
NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
|
||||
NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
|
||||
NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
|
||||
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision);
|
||||
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
|
||||
genlmsg_end(skb2, nlh2);
|
||||
|
||||
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
|
||||
|
@@ -11,6 +11,10 @@ enum {
|
||||
IPSET_ERR_INVALID_PROTO,
|
||||
/* Protocol missing but must be specified */
|
||||
IPSET_ERR_MISSING_PROTO,
|
||||
/* Range not supported */
|
||||
IPSET_ERR_HASH_RANGE_UNSUPPORTED,
|
||||
/* Invalid range */
|
||||
IPSET_ERR_HASH_RANGE,
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
@@ -108,25 +108,32 @@ nla_put_failure:
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
__be32 ip;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
|
||||
ip &= ip_set_netmask(h->netmask);
|
||||
if (ip == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return adtfn(set, &ip, h->timeout, flags);
|
||||
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -171,13 +178,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip += hosts) {
|
||||
nip = htonl(ip);
|
||||
if (nip == 0)
|
||||
@@ -281,20 +289,26 @@ nla_put_failure:
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
union nf_inet_addr ip;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
|
||||
ip6_netmask(&ip, h->netmask);
|
||||
if (ipv6_addr_any(&ip.in6))
|
||||
return -EINVAL;
|
||||
|
||||
return adtfn(set, &ip, h->timeout, flags);
|
||||
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
@@ -305,7 +319,7 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
|
||||
static int
|
||||
hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -428,7 +442,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = hash_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@@ -124,31 +124,40 @@ nla_put_failure:
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipport4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipport4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem data = { };
|
||||
u32 ip, ip_to, p, port, port_to;
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -208,8 +217,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -220,8 +228,11 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
swap(port, port_to);
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip++) {
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
@@ -231,6 +242,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -328,26 +340,34 @@ nla_put_failure:
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipport6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipport6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -405,6 +425,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
@@ -491,7 +513,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* SCTP and UDPLITE support added */
|
||||
.create = hash_ipport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@@ -127,32 +127,41 @@ nla_put_failure:
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportip4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportip4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem data = { };
|
||||
u32 ip, ip_to, p, port, port_to;
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -216,8 +225,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -228,8 +236,11 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
swap(port, port_to);
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip++) {
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
@@ -239,6 +250,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -341,27 +353,35 @@ nla_put_failure:
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportip6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportip6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -423,6 +443,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
@@ -509,7 +531,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* SCTP and UDPLITE support added */
|
||||
.create = hash_ipportip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@@ -140,39 +140,51 @@ nla_put_failure:
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportnet4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
h->next.ip2 = ntohl(d->ip2);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem data =
|
||||
{ .cidr = h->nets[0].cidr || HOST_MASK };
|
||||
struct hash_ipportnet4_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
data.ip2 &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
|
||||
u32 ip, ip_to, p, port, port_to;
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 ip2_from = 0, ip2_to, ip2_last, ip2;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -186,21 +198,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2])
|
||||
if (tb[IPSET_ATTR_CIDR2]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
data.ip2 &= ip_set_netmask(data.cidr);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
@@ -225,14 +235,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
!(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
|
||||
tb[IPSET_ATTR_IP2_TO])) {
|
||||
data.ip = htonl(ip);
|
||||
data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
@@ -244,29 +256,50 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
}
|
||||
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
}
|
||||
if (tb[IPSET_ATTR_IP2_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip2_from > ip2_to)
|
||||
swap(ip2_from, ip2_to);
|
||||
if (ip2_from + UINT_MAX == ip2_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
} else {
|
||||
ip_set_mask_from_to(ip2_from, ip2_to, data.cidr);
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip++) {
|
||||
data.ip = htonl(ip);
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
ip2 = retried && ip == h->next.ip && p == h->next.port
|
||||
? h->next.ip2 : ip2_from;
|
||||
while (!after(ip2, ip2_to)) {
|
||||
data.ip2 = htonl(ip2);
|
||||
ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
|
||||
&data.cidr);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip2 = ip2_last + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -388,34 +421,43 @@ nla_put_failure:
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportnet6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet6_elem data =
|
||||
{ .cidr = h->nets[0].cidr || HOST_MASK };
|
||||
struct hash_ipportnet6_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
ip6_netmask(&data.ip2, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -432,6 +474,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
@@ -485,6 +529,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
@@ -574,7 +620,9 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.revision_min = 0,
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
.revision_max = 2, /* Range as input support for IPv4 added */
|
||||
.create = hash_ipportnet_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
@@ -587,6 +635,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
|
@@ -125,33 +125,44 @@ nla_put_failure:
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_net4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_net4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
|
||||
struct hash_net4_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem data = { .cidr = HOST_MASK };
|
||||
u32 timeout = h->timeout;
|
||||
u32 ip = 0, ip_to, last;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
@@ -161,27 +172,51 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
|
||||
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
ip_to = ip;
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip_to < ip)
|
||||
swap(ip, ip_to);
|
||||
if (ip + UINT_MAX == ip_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
}
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
while (!after(ip, ip_to)) {
|
||||
data.ip = htonl(ip);
|
||||
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip = last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -290,28 +325,37 @@ nla_put_failure:
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_net6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_net6_elem *d)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net6_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
|
||||
struct hash_net6_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -322,6 +366,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
@@ -425,7 +471,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* Range as input support for IPv4 added */
|
||||
.create = hash_net_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
@@ -436,6 +483,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
|
@@ -137,38 +137,48 @@ nla_put_failure:
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_netport4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem data = {
|
||||
.cidr = h->nets[0].cidr || HOST_MASK };
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to;
|
||||
u32 port, port_to, p = 0, ip = 0, ip_to, last;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -182,15 +192,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
@@ -215,24 +225,47 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
|
||||
if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
|
||||
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = ntohs(data.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
port = port_to = ntohs(data.port);
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port_to < port)
|
||||
swap(port, port_to);
|
||||
}
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
if (ip_to < ip)
|
||||
swap(ip, ip_to);
|
||||
if (ip + UINT_MAX == ip_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
} else {
|
||||
ip_set_mask_from_to(ip, ip_to, data.cidr);
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
while (!after(ip, ip_to)) {
|
||||
data.ip = htonl(ip);
|
||||
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
ip = last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -350,33 +383,42 @@ nla_put_failure:
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_netport6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport6_elem data = {
|
||||
.cidr = h->nets[0].cidr || HOST_MASK };
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -391,6 +433,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
@@ -438,6 +482,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
@@ -526,7 +572,9 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.revision_min = 0,
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
.revision_max = 2, /* Range as input support for IPv4 added */
|
||||
.create = hash_netport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
@@ -538,6 +586,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
|
@@ -72,7 +72,8 @@ list_set_expired(const struct list_set *map, u32 id)
|
||||
|
||||
static int
|
||||
list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct set_elem *elem;
|
||||
@@ -87,17 +88,17 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
continue;
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
ret = ip_set_test(elem->id, skb, pf, dim, flags);
|
||||
ret = ip_set_test(elem->id, skb, par, opt);
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
break;
|
||||
case IPSET_ADD:
|
||||
ret = ip_set_add(elem->id, skb, pf, dim, flags);
|
||||
ret = ip_set_add(elem->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
break;
|
||||
case IPSET_DEL:
|
||||
ret = ip_set_del(elem->id, skb, pf, dim, flags);
|
||||
ret = ip_set_del(elem->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
break;
|
||||
@@ -218,7 +219,7 @@ cleanup_entries(struct list_set *map)
|
||||
|
||||
static int
|
||||
list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
bool with_timeout = with_timeout(map->timeout);
|
||||
@@ -575,7 +576,8 @@ static struct ip_set_type list_set_type __read_mostly = {
|
||||
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = list_set_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
||||
|
@@ -22,6 +22,9 @@
|
||||
|
||||
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
|
||||
|
||||
#define opt_timeout(opt, map) \
|
||||
(with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout)
|
||||
|
||||
static inline unsigned int
|
||||
ip_set_timeout_uget(struct nlattr *tb)
|
||||
{
|
||||
@@ -45,7 +48,7 @@ ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
(timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_after(timeout, jiffies));
|
||||
time_is_after_jiffies(timeout));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -53,7 +56,7 @@ ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_before(timeout, jiffies);
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
@@ -64,7 +67,7 @@ ip_set_timeout_set(u32 timeout)
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = timeout * HZ + jiffies;
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! */
|
||||
t++;
|
||||
@@ -75,7 +78,8 @@ ip_set_timeout_set(u32 timeout)
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -89,14 +93,14 @@ static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_after(timeout, jiffies);
|
||||
time_is_after_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_before(timeout, jiffies);
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
@@ -107,7 +111,7 @@ ip_set_timeout_set(u32 timeout)
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = timeout * HZ + jiffies;
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! :-) */
|
||||
t++;
|
||||
@@ -118,7 +122,8 @@ ip_set_timeout_set(u32 timeout)
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
#endif /* ! IP_SET_BITMAP_TIMEOUT */
|
||||
|
||||
|
@@ -66,6 +66,7 @@ struct ipset_data {
|
||||
/* ADT/LIST/SAVE */
|
||||
struct {
|
||||
union nf_inet_addr ip2;
|
||||
union nf_inet_addr ip2_to;
|
||||
uint8_t cidr2;
|
||||
uint8_t proto;
|
||||
char ether[ETH_ALEN];
|
||||
@@ -289,6 +290,11 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
return -1;
|
||||
copy_addr(data->family, &data->adt.ip2, value);
|
||||
break;
|
||||
case IPSET_OPT_IP2_TO:
|
||||
if (!(data->family == AF_INET || data->family == AF_INET6))
|
||||
return -1;
|
||||
copy_addr(data->family, &data->adt.ip2_to, value);
|
||||
break;
|
||||
case IPSET_OPT_CIDR2:
|
||||
data->adt.cidr2 = *(const uint8_t *) value;
|
||||
break;
|
||||
@@ -401,6 +407,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
return data->adt.nameref;
|
||||
case IPSET_OPT_IP2:
|
||||
return &data->adt.ip2;
|
||||
case IPSET_OPT_IP2_TO:
|
||||
return &data->adt.ip2_to;
|
||||
case IPSET_OPT_CIDR2:
|
||||
return &data->adt.cidr2;
|
||||
case IPSET_OPT_PROTO:
|
||||
@@ -436,6 +444,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
|
||||
case IPSET_OPT_IP:
|
||||
case IPSET_OPT_IP_TO:
|
||||
case IPSET_OPT_IP2:
|
||||
case IPSET_OPT_IP2_TO:
|
||||
return family == AF_INET ? sizeof(uint32_t)
|
||||
: sizeof(struct in6_addr);
|
||||
case IPSET_OPT_PORT:
|
||||
|
268
extensions/ipset-6/libipset/debug.c
Normal file
268
extensions/ipset-6/libipset/debug.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/* Copyright 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.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h> /* inet_ntop */
|
||||
#include <libmnl/libmnl.h> /* libmnl backend */
|
||||
|
||||
struct ipset_attrname {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static const struct ipset_attrname cmdattr2name[] = {
|
||||
[IPSET_ATTR_PROTOCOL] = { .name = "PROTOCOL" },
|
||||
[IPSET_ATTR_SETNAME] = { .name = "SETNAME" },
|
||||
[IPSET_ATTR_TYPENAME] = { .name = "TYPENAME" },
|
||||
[IPSET_ATTR_REVISION] = { .name = "REVISION" },
|
||||
[IPSET_ATTR_FAMILY] = { .name = "FAMILY" },
|
||||
[IPSET_ATTR_FLAGS] = { .name = "FLAGS" },
|
||||
[IPSET_ATTR_DATA] = { .name = "DATA" },
|
||||
[IPSET_ATTR_ADT] = { .name = "ADT" },
|
||||
[IPSET_ATTR_LINENO] = { .name = "LINENO" },
|
||||
[IPSET_ATTR_PROTOCOL_MIN] = { .name = "PROTO_MIN" },
|
||||
};
|
||||
|
||||
static const struct ipset_attrname createattr2name[] = {
|
||||
[IPSET_ATTR_IP] = { .name = "IP" },
|
||||
[IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
|
||||
[IPSET_ATTR_CIDR] = { .name = "CIDR" },
|
||||
[IPSET_ATTR_PORT] = { .name = "PORT" },
|
||||
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
|
||||
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
|
||||
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
|
||||
[IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
|
||||
[IPSET_ATTR_GC] = { .name = "GC" },
|
||||
[IPSET_ATTR_HASHSIZE] = { .name = "HASHSIZE" },
|
||||
[IPSET_ATTR_MAXELEM] = { .name = "MAXELEM" },
|
||||
[IPSET_ATTR_NETMASK] = { .name = "NETMASK" },
|
||||
[IPSET_ATTR_PROBES] = { .name = "PROBES" },
|
||||
[IPSET_ATTR_RESIZE] = { .name = "RESIZE" },
|
||||
[IPSET_ATTR_SIZE] = { .name = "SIZE" },
|
||||
[IPSET_ATTR_ELEMENTS] = { .name = "ELEMENTS" },
|
||||
[IPSET_ATTR_REFERENCES] = { .name = "REFERENCES" },
|
||||
[IPSET_ATTR_MEMSIZE] = { .name = "MEMSIZE" },
|
||||
};
|
||||
|
||||
static const struct ipset_attrname adtattr2name[] = {
|
||||
[IPSET_ATTR_IP] = { .name = "IP" },
|
||||
[IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
|
||||
[IPSET_ATTR_CIDR] = { .name = "CIDR" },
|
||||
[IPSET_ATTR_PORT] = { .name = "PORT" },
|
||||
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
|
||||
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
|
||||
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
|
||||
[IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
|
||||
[IPSET_ATTR_ETHER] = { .name = "ETHER" },
|
||||
[IPSET_ATTR_NAME] = { .name = "NAME" },
|
||||
[IPSET_ATTR_NAMEREF] = { .name = "NAMEREF" },
|
||||
[IPSET_ATTR_IP2] = { .name = "IP2" },
|
||||
[IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
|
||||
[IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
|
||||
};
|
||||
|
||||
static void
|
||||
debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
|
||||
const struct ipset_attrname attr2name[],
|
||||
struct nlattr *nla[])
|
||||
{
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr,"\t\t%s attributes:\n", policy == create_attrs ? "CREATE" : "ADT");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (policy[i].type) {
|
||||
case MNL_TYPE_U8:
|
||||
v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, v);
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, ntohs(v));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, ntohl(v));
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name,
|
||||
(const char *) mnl_attr_get_payload(nla[i]));
|
||||
break;
|
||||
case MNL_TYPE_NESTED: {
|
||||
struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
void *d;
|
||||
|
||||
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) {
|
||||
fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
|
||||
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV4]);
|
||||
|
||||
inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name, addr);
|
||||
} else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
|
||||
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV6]);
|
||||
|
||||
inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name, addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "\t\t%s: unresolved!\n",
|
||||
attr2name[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
{
|
||||
struct nlattr *adt[IPSET_ATTR_ADT_MAX+1] = {};
|
||||
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr,"\tCommand attributes:\n");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (cmd_attrs[i].type) {
|
||||
case MNL_TYPE_U8:
|
||||
v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, v);
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, ntohs(v));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, ntohl(v));
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
fprintf(stderr, "\t%s: %s\n",
|
||||
cmdattr2name[i].name,
|
||||
(const char *) mnl_attr_get_payload(nla[i]));
|
||||
break;
|
||||
case MNL_TYPE_NESTED:
|
||||
if (i == IPSET_ATTR_DATA) {
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_ADD:
|
||||
case IPSET_CMD_DEL:
|
||||
case IPSET_CMD_TEST:
|
||||
if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
adt_attrs,
|
||||
adtattr2name,
|
||||
adt);
|
||||
break;
|
||||
default:
|
||||
if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) {
|
||||
fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
|
||||
create_attrs,
|
||||
createattr2name,
|
||||
cattr);
|
||||
}
|
||||
} else {
|
||||
struct nlattr *tb;
|
||||
mnl_attr_for_each_nested(tb, nla[i]) {
|
||||
memset(adt, 0, sizeof(adt));
|
||||
if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
adt_attrs,
|
||||
adtattr2name,
|
||||
adt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "\t%s: unresolved!\n",
|
||||
cmdattr2name[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ipset_debug_msg(const char *dir, void *buffer, int len)
|
||||
{
|
||||
const struct nlmsghdr *nlh = buffer;
|
||||
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
|
||||
int cmd, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
|
||||
|
||||
debug = 0;
|
||||
while (mnl_nlmsg_ok(nlh, len)) {
|
||||
switch (nlh->nlmsg_type) {
|
||||
case NLMSG_NOOP:
|
||||
case NLMSG_DONE:
|
||||
case NLMSG_OVERRUN:
|
||||
fprintf(stderr, "Message header: %s msg %s\n"
|
||||
"\tlen %d\n"
|
||||
"\tseq %u\n",
|
||||
dir,
|
||||
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
|
||||
nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN",
|
||||
len, nlh->nlmsg_seq);
|
||||
goto next_msg;
|
||||
case NLMSG_ERROR: {
|
||||
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
|
||||
fprintf(stderr, "Message header: %s msg ERROR\n"
|
||||
"\tlen %d\n"
|
||||
"\terrcode %d\n"
|
||||
"\tseq %u\n",
|
||||
dir, len, err->error, nlh->nlmsg_seq);
|
||||
goto next_msg;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
cmd = ipset_get_nlmsg_type(nlh);
|
||||
fprintf(stderr, "Message header: %s cmd %s (%d)\n"
|
||||
"\tlen %d\n"
|
||||
"\tflag %s\n"
|
||||
"\tseq %u\n",
|
||||
dir,
|
||||
cmd <= IPSET_CMD_NONE ? "NONE!" :
|
||||
cmd >= IPSET_CMD_MAX ? "MAX!" : cmd2name[cmd], cmd,
|
||||
len,
|
||||
!(nlh->nlmsg_flags & NLM_F_EXCL) ? "EXIST" : "none",
|
||||
nlh->nlmsg_seq);
|
||||
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
|
||||
goto next_msg;
|
||||
memset(nla, 0, sizeof(nla));
|
||||
if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) {
|
||||
fprintf(stderr, "\tcannot validate and parse attributes\n");
|
||||
goto next_msg;
|
||||
}
|
||||
debug_cmd_attrs(cmd, nla);
|
||||
next_msg:
|
||||
nlh = mnl_nlmsg_next(nlh, &len);
|
||||
}
|
||||
debug = 1;
|
||||
}
|
@@ -83,7 +83,6 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
if (cmdflags[cmd-1] & NLM_F_ACK)
|
||||
nlh->nlmsg_flags |= NLM_F_ACK;
|
||||
nlh->nlmsg_seq = ++handle->seq;
|
||||
|
||||
ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
ghdr->cmd = cmd;
|
||||
@@ -102,19 +101,24 @@ ipset_mnl_query(struct ipset_handle *handle, void *buffer, size_t len)
|
||||
assert(handle);
|
||||
assert(buffer);
|
||||
|
||||
nlh->nlmsg_seq = ++handle->seq;
|
||||
#ifdef IPSET_DEBUG
|
||||
ipset_debug_msg("sent", nlh, nlh->nlmsg_len);
|
||||
#endif
|
||||
if (mnl_socket_sendto(handle->h, nlh, nlh->nlmsg_len) < 0)
|
||||
return -ECOMM;
|
||||
|
||||
D("message sent");
|
||||
ret = mnl_socket_recvfrom(handle->h, buffer, len);
|
||||
D("message received, ret: %d", ret);
|
||||
#ifdef IPSET_DEBUG
|
||||
ipset_debug_msg("received", buffer, ret);
|
||||
#endif
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run2(buffer, ret,
|
||||
handle->seq, handle->portid,
|
||||
handle->cb_ctl[NLMSG_MIN_TYPE],
|
||||
handle->data,
|
||||
handle->cb_ctl, NLMSG_MIN_TYPE);
|
||||
D("nfln_cb_run2, ret: %d", ret);
|
||||
D("nfln_cb_run2, ret: %d, errno %d", ret, errno);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(handle->h, buffer, len);
|
||||
|
@@ -667,8 +667,15 @@ parse_ipaddr(struct ipset_session *session,
|
||||
char *saved = strdup(str);
|
||||
char *a, *tmp = saved;
|
||||
struct addrinfo *info;
|
||||
enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR
|
||||
: IPSET_OPT_CIDR2;
|
||||
enum ipset_opt copt, opt2;
|
||||
|
||||
if (opt == IPSET_OPT_IP) {
|
||||
copt = IPSET_OPT_CIDR;
|
||||
opt2 = IPSET_OPT_IP_TO;
|
||||
} else {
|
||||
copt = IPSET_OPT_CIDR2;
|
||||
opt2 = IPSET_OPT_IP2_TO;
|
||||
}
|
||||
|
||||
if (tmp == NULL)
|
||||
return ipset_err(session,
|
||||
@@ -691,7 +698,7 @@ parse_ipaddr(struct ipset_session *session,
|
||||
|| !range)
|
||||
goto out;
|
||||
freeaddrinfo(info);
|
||||
aerr = get_addrinfo(session, IPSET_OPT_IP_TO, a, &info, family);
|
||||
aerr = get_addrinfo(session, opt2, a, &info, family);
|
||||
|
||||
out:
|
||||
if (aerr != EINVAL)
|
||||
@@ -973,6 +980,46 @@ ipset_parse_ip4_single6(struct ipset_session *session,
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_parse_ip4_net6 - parse IPv4|IPv6 address or address/cidr pattern
|
||||
* @session: session structure
|
||||
* @opt: option kind of the data
|
||||
* @str: string to parse
|
||||
*
|
||||
* Parse string as an IPv4|IPv6 address or address/cidr pattern. For IPv4,
|
||||
* address range is valid too.
|
||||
* If family is not set yet in the data blob, INET is assumed.
|
||||
* The values are stored in the data blob of the session.
|
||||
*
|
||||
* FIXME: if the hostname resolves to multiple addresses,
|
||||
* the first one is used only.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_parse_ip4_net6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
{
|
||||
struct ipset_data *data;
|
||||
uint8_t family;
|
||||
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
||||
assert(str);
|
||||
|
||||
data = ipset_session_data(session);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
if (family == AF_UNSPEC) {
|
||||
family = AF_INET;
|
||||
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
|
||||
}
|
||||
|
||||
return family == AF_INET ? parse_ip(session, opt, str, IPADDR_ANY)
|
||||
: ipset_parse_ipnet(session, opt, str);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
|
||||
* @session: session structure
|
||||
|
@@ -37,6 +37,7 @@ struct ipset_session {
|
||||
/* Command state */
|
||||
enum ipset_cmd cmd; /* Current command */
|
||||
uint32_t lineno; /* Current lineno in restore mode */
|
||||
uint32_t printed_set; /* Printed sets so far */
|
||||
char saved_setname[IPSET_MAXNAMELEN]; /* Saved setname */
|
||||
const struct ipset_type *saved_type; /* Saved type */
|
||||
struct nlattr *nested[IPSET_NEST_MAX]; /* Pointer to nest levels */
|
||||
@@ -138,6 +139,8 @@ ipset_envopt_parse(struct ipset_session *session, int opt,
|
||||
case IPSET_ENV_QUIET:
|
||||
case IPSET_ENV_RESOLVE:
|
||||
case IPSET_ENV_EXIST:
|
||||
case IPSET_ENV_LIST_SETNAME:
|
||||
case IPSET_ENV_LIST_HEADER:
|
||||
session->envopts |= opt;
|
||||
return 0;
|
||||
default:
|
||||
@@ -468,6 +471,10 @@ static const struct ipset_attr_policy adt_attrs[] = {
|
||||
.type = MNL_TYPE_U8,
|
||||
.opt = IPSET_OPT_CIDR2,
|
||||
},
|
||||
[IPSET_ATTR_IP2_TO] = {
|
||||
.type = MNL_TYPE_NESTED,
|
||||
.opt = IPSET_OPT_IP2_TO,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ipset_attr_policy ipaddr_attrs[] = {
|
||||
@@ -480,6 +487,10 @@ static const struct ipset_attr_policy ipaddr_attrs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
static int debug = 1;
|
||||
#endif
|
||||
|
||||
static int
|
||||
generic_data_attr_cb(const struct nlattr *attr, void *data,
|
||||
int attr_max, const struct ipset_attr_policy *policy)
|
||||
@@ -487,14 +498,14 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
|
||||
const struct nlattr **tb = data;
|
||||
int type = mnl_attr_get_type(attr);
|
||||
|
||||
D("attr type: %u, len %u", type, attr->nla_len);
|
||||
IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
|
||||
if (mnl_attr_type_valid(attr, attr_max) < 0) {
|
||||
D("attr type: %u INVALID", type);
|
||||
IF_D(debug, "attr type: %u INVALID", type);
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
if (mnl_attr_validate(attr, policy[type].type) < 0) {
|
||||
D("attr type: %u POLICY, attrlen %u", type,
|
||||
mnl_attr_get_payload_len(attr));
|
||||
IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
|
||||
mnl_attr_get_payload_len(attr));
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING
|
||||
@@ -829,8 +840,9 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
|
||||
type->name);
|
||||
break;
|
||||
case IPSET_LIST_PLAIN:
|
||||
safe_snprintf(session, "Name: %s\n"
|
||||
safe_snprintf(session, "%sName: %s\n"
|
||||
"Type: %s\nHeader: ",
|
||||
session->printed_set ? "\n" : "",
|
||||
ipset_data_setname(data),
|
||||
type->name);
|
||||
break;
|
||||
@@ -887,18 +899,24 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
|
||||
safe_snprintf(session, "\nReferences: ");
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
|
||||
safe_snprintf(session, "\nMembers:\n");
|
||||
safe_snprintf(session,
|
||||
session->envopts & IPSET_ENV_LIST_HEADER ?
|
||||
"\n" : "\nMembers:\n");
|
||||
break;
|
||||
case IPSET_LIST_XML:
|
||||
safe_snprintf(session, "</elements>\n <memsize>");
|
||||
safe_snprintf(session, " <memsize>");
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
|
||||
safe_snprintf(session, "</memsize>\n <references>");
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
|
||||
safe_snprintf(session, "</references>\n </header>\n <members>\n");
|
||||
safe_snprintf(session,
|
||||
session->envopts & IPSET_ENV_LIST_HEADER ?
|
||||
"</references>\n </header>\n" :
|
||||
"</references>\n </header>\n <members>\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
session->printed_set++;
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
@@ -910,16 +928,17 @@ print_set_done(struct ipset_session *session)
|
||||
? "NONE" : session->saved_setname);
|
||||
switch (session->mode) {
|
||||
case IPSET_LIST_XML:
|
||||
if (session->saved_setname[0] == '\0')
|
||||
safe_snprintf(session, "\n");
|
||||
else
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME)
|
||||
break;
|
||||
if (session->envopts & IPSET_ENV_LIST_HEADER) {
|
||||
if (session->saved_setname[0] != '\0')
|
||||
safe_snprintf(session, "</ipset>\n");
|
||||
break;
|
||||
}
|
||||
if (session->saved_setname[0] != '\0')
|
||||
safe_snprintf(session, " </members>\n</ipset>\n");
|
||||
break;
|
||||
case IPSET_LIST_SAVE:
|
||||
/* No empty lines between the sets */
|
||||
break;
|
||||
default:
|
||||
safe_snprintf(session, "\n");
|
||||
break;
|
||||
}
|
||||
return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_STOP;
|
||||
@@ -931,8 +950,11 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
{
|
||||
struct ipset_data *data = session->data;
|
||||
|
||||
if (setjmp(printf_failure))
|
||||
if (setjmp(printf_failure)) {
|
||||
session->saved_setname[0] = '\0';
|
||||
session->printed_set = 0;
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
if (!nla[IPSET_ATTR_SETNAME])
|
||||
FAILURE("Broken %s kernel message: missing setname!",
|
||||
@@ -940,6 +962,17 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
|
||||
D("setname %s", ipset_data_setname(data));
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME &&
|
||||
session->mode != IPSET_LIST_SAVE) {
|
||||
if (session->mode == IPSET_LIST_XML)
|
||||
safe_snprintf(session, "<ipset name=\"%s\"/>\n",
|
||||
ipset_data_setname(data));
|
||||
else
|
||||
safe_snprintf(session, "%s\n",
|
||||
ipset_data_setname(data));
|
||||
return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
|
||||
}
|
||||
|
||||
if (STREQ(ipset_data_setname(data), session->saved_setname)) {
|
||||
/* Header part already seen */
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE)
|
||||
@@ -1422,6 +1455,9 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
return 1;
|
||||
|
||||
switch (attr->type) {
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
alen = strlen((const char *)d) + 1;
|
||||
break;
|
||||
case MNL_TYPE_U32: {
|
||||
uint32_t value = htonl(*(const uint32_t *)d);
|
||||
|
||||
@@ -1497,7 +1533,7 @@ addattr_adt(struct ipset_session *session,
|
||||
static int
|
||||
build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
{
|
||||
char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned));
|
||||
char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned)) = {};
|
||||
struct nlmsghdr *nlh = (void *)buffer;
|
||||
struct ipset_data *data = session->data;
|
||||
int len = PRIVATE_MSG_BUFLEN, ret;
|
||||
@@ -1592,7 +1628,12 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
IPSET_ATTR_REVISION, cmd_attrs);
|
||||
D("family: %u, type family %u",
|
||||
ipset_data_family(data), type->family);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
|
||||
if (ipset_data_test(data, IPSET_OPT_FAMILY))
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
|
||||
AF_INET, cmd_attrs);
|
||||
else
|
||||
/* bitmap:port and list:set types */
|
||||
mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
|
||||
|
||||
/* Type-specific create attributes */
|
||||
D("call open_nested");
|
||||
@@ -1604,11 +1645,26 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
}
|
||||
case IPSET_CMD_DESTROY:
|
||||
case IPSET_CMD_FLUSH:
|
||||
case IPSET_CMD_LIST:
|
||||
case IPSET_CMD_SAVE:
|
||||
if (ipset_data_test(data, IPSET_SETNAME))
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
break;
|
||||
case IPSET_CMD_LIST: {
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME)
|
||||
flags |= IPSET_FLAG_LIST_SETNAME;
|
||||
if (session->envopts & IPSET_ENV_LIST_HEADER)
|
||||
flags |= IPSET_FLAG_LIST_HEADER;
|
||||
if (ipset_data_test(data, IPSET_SETNAME))
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
if (flags && session->mode != IPSET_LIST_SAVE) {
|
||||
ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS, AF_INET,
|
||||
cmd_attrs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPSET_CMD_RENAME:
|
||||
case IPSET_CMD_SWAP:
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
@@ -1729,6 +1785,7 @@ ipset_commit(struct ipset_session *session)
|
||||
|
||||
/* Reset saved data and nested state */
|
||||
session->saved_setname[0] = '\0';
|
||||
session->printed_set = 0;
|
||||
for (i = session->nestid - 1; i >= 0; i--)
|
||||
session->nested[i] = NULL;
|
||||
session->nestid = 0;
|
||||
@@ -1926,3 +1983,7 @@ ipset_session_fini(struct ipset_session *session)
|
||||
free(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
#include "debug.c"
|
||||
#endif
|
||||
|
@@ -267,6 +267,19 @@ create_type_get(struct ipset_session *session)
|
||||
kmax, tmin);
|
||||
}
|
||||
|
||||
/* Disable unsupported revisions */
|
||||
for (match = NULL, t = typelist; t != NULL; t = t->next) {
|
||||
/* Skip revisions which are unsupported by the kernel */
|
||||
if (t->kernel_check == IPSET_KERNEL_MISMATCH)
|
||||
continue;
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (t->revision < kmin || t->revision > kmax)
|
||||
t->kernel_check = IPSET_KERNEL_MISMATCH;
|
||||
else if (match == NULL)
|
||||
match = t;
|
||||
}
|
||||
}
|
||||
match->kernel_check = IPSET_KERNEL_OK;
|
||||
found:
|
||||
ipset_data_set(data, IPSET_OPT_TYPE, match);
|
||||
|
@@ -289,3 +289,24 @@ const union nf_inet_addr ip_set_hostmask_map[] = {
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ip_set_hostmask_map);
|
||||
|
||||
/* Find the largest network which matches the range from left, in host order. */
|
||||
u32
|
||||
ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr)
|
||||
{
|
||||
u32 last;
|
||||
u8 i;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
if ((from & ip_set_hostmask(i)) != from)
|
||||
continue;
|
||||
last = from | ~ip_set_hostmask(i);
|
||||
if (!after(last, to)) {
|
||||
*cidr = i;
|
||||
return last;
|
||||
}
|
||||
}
|
||||
*cidr = 32;
|
||||
return from;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_range_to_cidr);
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
/* Prefixlen maps, by Jan Engelhardt */
|
||||
extern const union nf_inet_addr ip_set_netmask_map[];
|
||||
@@ -32,4 +33,12 @@ ip_set_hostmask6(u8 pfxlen)
|
||||
return &ip_set_hostmask_map[pfxlen].ip6[0];
|
||||
}
|
||||
|
||||
extern u32 ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr);
|
||||
|
||||
#define ip_set_mask_from_to(from, to, cidr) \
|
||||
do { \
|
||||
from &= ip_set_hostmask(cidr); \
|
||||
to = from | ~ip_set_hostmask(cidr); \
|
||||
} while (0)
|
||||
|
||||
#endif /*_PFXLEN_H */
|
||||
|
@@ -1,89 +0,0 @@
|
||||
#ifndef _IP_SET_SLIST_H
|
||||
#define _IP_SET_SLIST_H
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* Single linked lists with a single pointer.
|
||||
* Mostly useful for hash tables where the two pointer list head
|
||||
* and list node is too wasteful.
|
||||
*/
|
||||
|
||||
struct slist {
|
||||
struct slist *next;
|
||||
};
|
||||
|
||||
#define SLIST(name) struct slist name = { .next = NULL }
|
||||
#define INIT_SLIST(ptr) ((ptr)->next = NULL)
|
||||
|
||||
#define slist_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
#define slist_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
|
||||
pos = pos->next)
|
||||
|
||||
#define slist_for_each_prev(prev, pos, head) \
|
||||
for (prev = head, pos = (head)->next; \
|
||||
pos && ({ prefetch(pos->next); 1; }); \
|
||||
prev = pos, pos = pos->next)
|
||||
|
||||
#define slist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry - iterate over list of given type
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry(tpos, pos, head, member) \
|
||||
for (pos = (head)->next; \
|
||||
pos && ({ prefetch(pos->next); 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry_continue - iterate over a hlist continuing
|
||||
* after current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry_continue(tpos, pos, member) \
|
||||
for (pos = (pos)->next; \
|
||||
pos && ({ prefetch(pos->next); 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry_from - iterate over a hlist continuing
|
||||
* from current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry_from(tpos, pos, member) \
|
||||
for (; pos && ({ prefetch(pos->next); 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry_safe - iterate over list of given type safe against
|
||||
* removal of list entry
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @n: another &struct slist to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->next; \
|
||||
pos && ({ n = pos->next; 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = n)
|
||||
|
||||
#endif /* _IP_SET_SLIST_H */
|
@@ -113,6 +113,10 @@ static const struct ipset_errcode_table hash_errcode_table[] = {
|
||||
"Invalid protocol specified" },
|
||||
{ IPSET_ERR_MISSING_PROTO, 0,
|
||||
"Protocol missing, but must be specified" },
|
||||
{ IPSET_ERR_HASH_RANGE_UNSUPPORTED, 0,
|
||||
"Range is not supported in the \"net\" component of the element" },
|
||||
{ IPSET_ERR_HASH_RANGE, 0,
|
||||
"Invalid range, covers the whole address space" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@@ -21,7 +21,7 @@ ipset \(em administration tool for IP sets
|
||||
.PP
|
||||
COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
|
||||
.PP
|
||||
\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR }
|
||||
\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR }
|
||||
.PP
|
||||
\fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
|
||||
.PP
|
||||
@@ -109,7 +109,7 @@ Destroy the specified set or all the sets if none is given.
|
||||
|
||||
If the set has got reference(s), nothing is done and no set destroyed.
|
||||
.TP
|
||||
\fBlist\fP [ \fISETNAME\fP ]
|
||||
\fBlist\fP [ \fISETNAME\fP ] [ \fIOPTIONS\fP ]
|
||||
List the header data and the entries for the specified set, or for
|
||||
all sets if none is given. The
|
||||
\fB\-resolve\fP
|
||||
@@ -120,8 +120,13 @@ type supports the operation). The option
|
||||
\fB\-output\fR
|
||||
can be used to control the format of the listing:
|
||||
\fBplain\fR, \fBsave\fR or \fBxml\fR.
|
||||
The default is
|
||||
\fBplain\fR.
|
||||
(The default is
|
||||
\fBplain\fR.)
|
||||
If the option
|
||||
\fB\-name\fR
|
||||
is specified, just the names of the existing sets are listed. If the option
|
||||
\fB\-terse\fR
|
||||
is specified, just the set names and headers are listed.
|
||||
.TP
|
||||
\fBsave\fP [ \fISETNAME\fP ]
|
||||
Save the given set, or all sets if none is given
|
||||
@@ -190,6 +195,13 @@ DNS lookups.
|
||||
.TP
|
||||
\fB\-s\fP, \fB\-sorted\fP
|
||||
Sorted output. When listing sets entries are listed sorted. Not supported yet.
|
||||
.TP
|
||||
\fB\-n\fP, \fB\-name\fP
|
||||
List just the names of the existing sets, i.e. suppress listing of set headers and members.
|
||||
.TP
|
||||
\fB\-t\fP, \fB\-terse\fP
|
||||
List the set names and headers, i.e. suppress listing of set members.
|
||||
|
||||
.SH "SET TYPES"
|
||||
A set type comprises of the storage method by which the data is stored and
|
||||
the data type(s) which are stored in the set. Therefore the
|
||||
@@ -202,7 +214,7 @@ command follows the syntax
|
||||
|
||||
where the current list of the methods are
|
||||
\fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types
|
||||
are \fBip\fR, \fBmac\fR and \fBport\fR. The dimension of a set
|
||||
are \fBip\fR, \fBnet\fR, \fBmac\fR and \fBport\fR. The dimension of a set
|
||||
is equal to the number of data types in its type name.
|
||||
|
||||
When adding, deleting or testing entries in a set, the same comma separated
|
||||
@@ -397,13 +409,16 @@ Network address with zero prefix size cannot be stored in this type of sets.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
@@ -419,6 +434,11 @@ correct value.
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the \fBinet\fR family one can add or delete multiple entries by specifying
|
||||
a range, which is converted internally to network(s) equal to the range:
|
||||
.PP
|
||||
\fInetaddr\fR := { \fIip\fR[/\fIcidr\fR] | \fIfromaddr\fR\-\fItoaddr\fR }
|
||||
.PP
|
||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
||||
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||
element is added/deleted and overlapping elements are not checked by the kernel.
|
||||
@@ -527,13 +547,16 @@ address with zero prefix size is not accepted either.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
@@ -549,7 +572,8 @@ correct value.
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the
|
||||
For the \fInetaddr\fR part of the elements
|
||||
see the description at the \fBhash:net\fR set type. For the
|
||||
[\fIproto\fR:]\fIport\fR
|
||||
part of the elements see the description at the
|
||||
\fBhash:ip,port\fR set type.
|
||||
@@ -633,18 +657,22 @@ address with zero prefix size cannot be stored either.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
For the first \fIipaddr\fR and
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
For the \fIipaddr\fR and
|
||||
[\fIproto\fR:]\fIport\fR
|
||||
parts of the elements see the descriptions at the
|
||||
\fBhash:ip,port\fR set type.
|
||||
\fBhash:ip,port\fR set type. For the \fInetaddr\fR part of the elements
|
||||
see the description at the \fBhash:net\fR set type.
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
@@ -39,10 +39,13 @@ extern struct ipset_type ipset_bitmap_ipmac0;
|
||||
extern struct ipset_type ipset_bitmap_port0;
|
||||
extern struct ipset_type ipset_hash_ip0;
|
||||
extern struct ipset_type ipset_hash_net0;
|
||||
extern struct ipset_type ipset_hash_netport0;
|
||||
extern struct ipset_type ipset_hash_ipport0;
|
||||
extern struct ipset_type ipset_hash_ipportip0;
|
||||
extern struct ipset_type ipset_hash_ipportnet0;
|
||||
extern struct ipset_type ipset_hash_net1;
|
||||
extern struct ipset_type ipset_hash_netport1;
|
||||
extern struct ipset_type ipset_hash_netport2;
|
||||
extern struct ipset_type ipset_hash_ipport1;
|
||||
extern struct ipset_type ipset_hash_ipportip1;
|
||||
extern struct ipset_type ipset_hash_ipportnet1;
|
||||
extern struct ipset_type ipset_hash_ipportnet2;
|
||||
extern struct ipset_type ipset_list_set0;
|
||||
|
||||
enum exittype {
|
||||
@@ -145,9 +148,9 @@ build_argv(char *buffer)
|
||||
newargv[i] = NULL;
|
||||
newargc = 1;
|
||||
|
||||
ptr = strtok(buffer, " \t\n");
|
||||
ptr = strtok(buffer, " \t\r\n");
|
||||
newargv[newargc++] = ptr;
|
||||
while ((ptr = strtok(NULL, " \t\n")) != NULL) {
|
||||
while ((ptr = strtok(NULL, " \t\r\n")) != NULL) {
|
||||
if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
|
||||
newargv[newargc++] = ptr;
|
||||
else {
|
||||
@@ -181,7 +184,7 @@ restore(char *argv0)
|
||||
c++;
|
||||
if (c[0] == '\0' || c[0] == '#')
|
||||
continue;
|
||||
else if (strcmp(c, "COMMIT\n") == 0) {
|
||||
else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n")) {
|
||||
ret = ipset_commit(session);
|
||||
if (ret < 0)
|
||||
handle_error();
|
||||
@@ -715,16 +718,21 @@ parse_commandline(int argc, char *argv[])
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Register types */
|
||||
ipset_type_add(&ipset_bitmap_ip0);
|
||||
ipset_type_add(&ipset_bitmap_ipmac0);
|
||||
ipset_type_add(&ipset_bitmap_port0);
|
||||
ipset_type_add(&ipset_hash_ip0);
|
||||
ipset_type_add(&ipset_hash_net0);
|
||||
ipset_type_add(&ipset_hash_netport0);
|
||||
ipset_type_add(&ipset_hash_ipport0);
|
||||
ipset_type_add(&ipset_hash_ipportip0);
|
||||
ipset_type_add(&ipset_hash_ipportnet0);
|
||||
ipset_type_add(&ipset_hash_net1);
|
||||
ipset_type_add(&ipset_hash_netport1);
|
||||
ipset_type_add(&ipset_hash_netport2);
|
||||
ipset_type_add(&ipset_hash_ipport1);
|
||||
ipset_type_add(&ipset_hash_ipportip1);
|
||||
ipset_type_add(&ipset_hash_ipportnet1);
|
||||
ipset_type_add(&ipset_hash_ipportnet2);
|
||||
ipset_type_add(&ipset_list_set0);
|
||||
|
||||
/* Initialize session */
|
||||
@@ -733,5 +741,9 @@ main(int argc, char *argv[])
|
||||
return exit_error(OTHER_PROBLEM,
|
||||
"Cannot initialize ipset session, aborting.");
|
||||
|
||||
return parse_commandline(argc, argv);
|
||||
ret = parse_commandline(argc, argv);
|
||||
|
||||
ipset_session_fini(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ static const char hash_ip_usage[] =
|
||||
|
||||
struct ipset_type ipset_hash_ip0 = {
|
||||
.name = "hash:ip",
|
||||
.alias = { "iphash", "iptree", "iptreemap", NULL },
|
||||
.alias = { "iphash", NULL },
|
||||
.revision = 0,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
@@ -92,7 +92,6 @@ struct ipset_type ipset_hash_ip0 = {
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.compat_parse_elem = ipset_parse_iptimeout,
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ip_create_args,
|
||||
[IPSET_ADD] = hash_ip_add_args,
|
||||
|
@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipport_add_args[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ipport_usage[] =
|
||||
static const char hash_ipport1_usage[] =
|
||||
"create SETNAME hash:ip,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -85,7 +85,7 @@ static const char hash_ipport_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipport0 = {
|
||||
struct ipset_type ipset_hash_ipport1 = {
|
||||
.name = "hash:ip,port",
|
||||
.alias = { "ipporthash", NULL },
|
||||
.revision = 1,
|
||||
@@ -139,6 +139,6 @@ struct ipset_type ipset_hash_ipport0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
},
|
||||
|
||||
.usage = hash_ipport_usage,
|
||||
.usage = hash_ipport1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipportip_add_args[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ipportip_usage[] =
|
||||
static const char hash_ipportip1_usage[] =
|
||||
"create SETNAME hash:ip,port,ip\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -85,7 +85,7 @@ static const char hash_ipportip_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportip0 = {
|
||||
struct ipset_type ipset_hash_ipportip1 = {
|
||||
.name = "hash:ip,port,ip",
|
||||
.alias = { "ipportiphash", NULL },
|
||||
.revision = 1,
|
||||
@@ -150,6 +150,6 @@ struct ipset_type ipset_hash_ipportip0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportip_usage,
|
||||
.usage = hash_ipportip1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipportnet_add_args[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ipportnet_usage[] =
|
||||
static const char hash_ipportnet1_usage[] =
|
||||
"create SETNAME hash:ip,port,net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -86,7 +86,7 @@ static const char hash_ipportnet_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportnet0 = {
|
||||
struct ipset_type ipset_hash_ipportnet1 = {
|
||||
.name = "hash:ip,port,net",
|
||||
.alias = { "ipportnethash", NULL },
|
||||
.revision = 1,
|
||||
@@ -133,6 +133,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
@@ -141,6 +142,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
@@ -154,6 +156,99 @@ struct ipset_type ipset_hash_ipportnet0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportnet_usage,
|
||||
.usage = hash_ipportnet1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
||||
static const char hash_ipportnet2_usage[] =
|
||||
"create SETNAME hash:ip,port,net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
|
||||
"del SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
|
||||
"test SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" in both IP components are supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportnet2 = {
|
||||
.name = "hash:ip,port,net",
|
||||
.alias = { "ipportnethash", NULL },
|
||||
.revision = 2,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP2
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ipportnet_create_args,
|
||||
[IPSET_ADD] = hash_ipportnet_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportnet2_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
||||
|
@@ -57,7 +57,7 @@ static const struct ipset_arg hash_net_add_args[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_net_usage[] =
|
||||
static const char hash_net0_usage[] =
|
||||
"create SETNAME hash:net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -105,5 +105,60 @@ struct ipset_type ipset_hash_net0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_net_usage,
|
||||
.usage = hash_net0_usage,
|
||||
};
|
||||
|
||||
static const char hash_net1_usage[] =
|
||||
"create SETNAME hash:net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR]|FROM-TO [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR]|FROM-TO\n"
|
||||
"test SETNAME IP[/CIDR]\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is an IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" IP range is not supported with IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_net1 = {
|
||||
.name = "hash:net",
|
||||
.alias = { "nethash", NULL },
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_net_create_args,
|
||||
[IPSET_ADD] = hash_net_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_net1_usage,
|
||||
};
|
||||
|
||||
|
@@ -49,7 +49,7 @@ static const struct ipset_arg hash_netport_add_args[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_netport_usage[] =
|
||||
static const char hash_netport1_usage[] =
|
||||
"create SETNAME hash:net,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -63,7 +63,7 @@ static const char hash_netport_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_netport0 = {
|
||||
struct ipset_type ipset_hash_netport1 = {
|
||||
.name = "hash:net,port",
|
||||
.alias = { "netporthash", NULL },
|
||||
.revision = 1,
|
||||
@@ -118,6 +118,82 @@ struct ipset_type ipset_hash_netport0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_netport_usage,
|
||||
.usage = hash_netport1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
||||
static const char hash_netport2_usage[] =
|
||||
"create SETNAME hash:net,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
|
||||
"test SETNAME IP[/CIDR],PROTO:PORT\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements with IPv4 is supported.\n"
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_netport2 = {
|
||||
.name = "hash:net,port",
|
||||
.alias = { "netporthash", NULL },
|
||||
.revision = 2,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_netport_create_args,
|
||||
[IPSET_ADD] = hash_netport_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
},
|
||||
|
||||
.usage = hash_netport2_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
@@ -188,6 +188,19 @@ const struct ipset_envopts ipset_envopts[] = {
|
||||
" when adding already existing elements\n"
|
||||
" or when deleting non-existing elements.",
|
||||
},
|
||||
{ .name = { "-n", "-name" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_SETNAME,
|
||||
.help = "\n"
|
||||
" When listing, list just setnames from kernel.\n",
|
||||
},
|
||||
{ .name = { "-t", "-terse" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_HEADER,
|
||||
.help = "\n"
|
||||
" When listing, list setnames and set headers\n"
|
||||
" from kernel only.",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -256,9 +269,9 @@ ipset_port_usage(void)
|
||||
const char *name;
|
||||
|
||||
printf(" [PROTO:]PORT is a valid pattern of the following:\n"
|
||||
" PORTNAME port name from /etc/services\n"
|
||||
" PORTNUMBER port number identifier\n"
|
||||
" tcp|udp:PORTNAME|PORTNUMBER\n"
|
||||
" PORTNAME TCP port name from /etc/services\n"
|
||||
" PORTNUMBER TCP port number identifier\n"
|
||||
" tcp|sctp|udp|udplite:PORTNAME|PORTNUMBER\n"
|
||||
" icmp:CODENAME supported ICMP codename\n"
|
||||
" icmp:TYPE/CODE ICMP type/code value\n"
|
||||
" icmpv6:CODENAME supported ICMPv6 codename\n"
|
||||
|
@@ -29,52 +29,33 @@ MODULE_ALIAS("ip6t_SET");
|
||||
|
||||
static inline int
|
||||
match_set(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 pf, u8 dim, u8 flags, int inv)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt, int inv)
|
||||
{
|
||||
if (ip_set_test(index, skb, pf, dim, flags))
|
||||
if (ip_set_test(index, skb, par, opt))
|
||||
inv = !inv;
|
||||
return inv;
|
||||
}
|
||||
|
||||
#define ADT_OPT(n, f, d, fs, cfs, t) \
|
||||
const struct ip_set_adt_opt n = { \
|
||||
.family = f, \
|
||||
.dim = d, \
|
||||
.flags = fs, \
|
||||
.cmdflags = cfs, \
|
||||
.timeout = t, \
|
||||
}
|
||||
|
||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
||||
|
||||
/* Backward compatibility constrains (incomplete):
|
||||
* 2.6.24: [NETLINK]: Introduce nested and byteorder flag to netlink attribute
|
||||
* 2.6.25: is_vmalloc_addr(): Check if an address is within the vmalloc
|
||||
* boundaries
|
||||
* 2.6.27: rcu: split list.h and move rcu-protected lists into rculist.h
|
||||
* 2.6.28: netfilter: ctnetlink: remove bogus module dependency between
|
||||
* ctnetlink and nf_nat (nfnl_lock/nfnl_unlock)
|
||||
* 2.6.29: generic swap(): introduce global macro swap(a, b)
|
||||
* 2.6.31: netfilter: passive OS fingerprint xtables match
|
||||
* 2.6.34: rcu: Add lockdep-enabled variants of rcu_dereference()
|
||||
*/
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
|
||||
#error "Linux kernel version too old: must be >= 2.6.34"
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
#define CHECK_OK 1
|
||||
#define CHECK_FAIL(err) 0
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
#define CHECK_OK 0
|
||||
#define CHECK_FAIL(err) (err)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match_v0(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static bool
|
||||
set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
#endif
|
||||
{
|
||||
const struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
|
||||
info->match_set.u.compat.flags, 0, UINT_MAX);
|
||||
|
||||
return match_set(info->match_set.index, skb, par->family,
|
||||
info->match_set.u.compat.dim,
|
||||
info->match_set.u.compat.flags,
|
||||
return match_set(info->match_set.index, skb, par, &opt,
|
||||
info->match_set.u.compat.flags & IPSET_INV_MATCH);
|
||||
}
|
||||
|
||||
@@ -94,13 +75,8 @@ compat_flags(struct xt_set_info_v0 *info)
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
#endif
|
||||
{
|
||||
struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
@@ -110,19 +86,19 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->match_set);
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -133,35 +109,25 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
#endif
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
|
||||
info->add_set.u.compat.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
|
||||
info->del_set.u.compat.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par->family,
|
||||
info->add_set.u.compat.dim,
|
||||
info->add_set.u.compat.flags);
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par->family,
|
||||
info->del_set.u.compat.dim,
|
||||
info->del_set.u.compat.flags);
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
#endif
|
||||
{
|
||||
struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
@@ -171,7 +137,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +148,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||
@@ -193,14 +159,14 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->add_set);
|
||||
compat_flags(&info->del_set);
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -214,33 +180,23 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 1: current interface to netfilter/iptables */
|
||||
/* Revision 1 match and target */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static bool
|
||||
set_match(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
#endif
|
||||
set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_match *info = par->matchinfo;
|
||||
const struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
ADT_OPT(opt, par->family, info->match_set.dim,
|
||||
info->match_set.flags, 0, UINT_MAX);
|
||||
|
||||
return match_set(info->match_set.index, skb, par->family,
|
||||
info->match_set.dim,
|
||||
info->match_set.flags,
|
||||
return match_set(info->match_set.index, skb, par, &opt,
|
||||
info->match_set.flags & IPSET_INV_MATCH);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
#endif
|
||||
set_match_v1_checkentry(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_set_info_match *info = par->matchinfo;
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
@@ -248,59 +204,47 @@ set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
if (info->match_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_match_destroy(const struct xt_mtdtor_param *par)
|
||||
set_match_v1_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
struct xt_set_info_match *info = par->matchinfo;
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static unsigned int
|
||||
set_target(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static unsigned int
|
||||
set_target(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
#endif
|
||||
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target *info = par->targinfo;
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index,
|
||||
skb, par->family,
|
||||
info->add_set.dim,
|
||||
info->add_set.flags);
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index,
|
||||
skb, par->family,
|
||||
info->del_set.dim,
|
||||
info->del_set.flags);
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
#endif
|
||||
set_target_v1_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct xt_set_info_target *info = par->targinfo;
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
@@ -308,7 +252,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +263,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||
@@ -330,16 +274,16 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_destroy(const struct xt_tgdtor_param *par)
|
||||
set_target_v1_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target *info = par->targinfo;
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
@@ -347,6 +291,28 @@ set_target_destroy(const struct xt_tgdtor_param *par)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 2 target */
|
||||
|
||||
static unsigned int
|
||||
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v2 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, info->flags, info->timeout);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#define set_target_v2_checkentry set_target_v1_checkentry
|
||||
#define set_target_v2_destroy set_target_v1_destroy
|
||||
|
||||
static struct xt_match set_matches[] __read_mostly = {
|
||||
{
|
||||
.name = "set",
|
||||
@@ -362,20 +328,20 @@ static struct xt_match set_matches[] __read_mostly = {
|
||||
.name = "set",
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision = 1,
|
||||
.match = set_match,
|
||||
.matchsize = sizeof(struct xt_set_info_match),
|
||||
.checkentry = set_match_checkentry,
|
||||
.destroy = set_match_destroy,
|
||||
.match = set_match_v1,
|
||||
.matchsize = sizeof(struct xt_set_info_match_v1),
|
||||
.checkentry = set_match_v1_checkentry,
|
||||
.destroy = set_match_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "set",
|
||||
.family = NFPROTO_IPV6,
|
||||
.revision = 1,
|
||||
.match = set_match,
|
||||
.matchsize = sizeof(struct xt_set_info_match),
|
||||
.checkentry = set_match_checkentry,
|
||||
.destroy = set_match_destroy,
|
||||
.match = set_match_v1,
|
||||
.matchsize = sizeof(struct xt_set_info_match_v1),
|
||||
.checkentry = set_match_v1_checkentry,
|
||||
.destroy = set_match_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
};
|
||||
@@ -395,20 +361,40 @@ static struct xt_target set_targets[] __read_mostly = {
|
||||
.name = "SET",
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = set_target,
|
||||
.targetsize = sizeof(struct xt_set_info_target),
|
||||
.checkentry = set_target_checkentry,
|
||||
.destroy = set_target_destroy,
|
||||
.target = set_target_v1,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v1),
|
||||
.checkentry = set_target_v1_checkentry,
|
||||
.destroy = set_target_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = set_target,
|
||||
.targetsize = sizeof(struct xt_set_info_target),
|
||||
.checkentry = set_target_checkentry,
|
||||
.destroy = set_target_destroy,
|
||||
.target = set_target_v1,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v1),
|
||||
.checkentry = set_target_v1_checkentry,
|
||||
.destroy = set_target_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 2,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = set_target_v2,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v2),
|
||||
.checkentry = set_target_v2_checkentry,
|
||||
.destroy = set_target_v2_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 2,
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = set_target_v2,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v2),
|
||||
.checkentry = set_target_v2_checkentry,
|
||||
.destroy = set_target_v2_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
};
|
||||
|
@@ -35,7 +35,7 @@ struct xt_set_info_target_v0 {
|
||||
struct xt_set_info_v0 del_set;
|
||||
};
|
||||
|
||||
/* Revision 1: current interface to netfilter/iptables */
|
||||
/* Revision 1 match and target */
|
||||
|
||||
struct xt_set_info {
|
||||
ip_set_id_t index;
|
||||
@@ -44,13 +44,22 @@ struct xt_set_info {
|
||||
};
|
||||
|
||||
/* match and target infos */
|
||||
struct xt_set_info_match {
|
||||
struct xt_set_info_match_v1 {
|
||||
struct xt_set_info match_set;
|
||||
};
|
||||
|
||||
struct xt_set_info_target {
|
||||
struct xt_set_info_target_v1 {
|
||||
struct xt_set_info add_set;
|
||||
struct xt_set_info del_set;
|
||||
};
|
||||
|
||||
/* Revision 2 target */
|
||||
|
||||
struct xt_set_info_target_v2 {
|
||||
struct xt_set_info add_set;
|
||||
struct xt_set_info del_set;
|
||||
u32 flags;
|
||||
u32 timeout;
|
||||
};
|
||||
|
||||
#endif /*_XT_SET_H*/
|
||||
|
Reference in New Issue
Block a user