mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-12-25 01:13:52 +01:00
ipset: update to 6.6a-genl
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user