Commit c1e2e043 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Patrick McHardy

netfilter: ipset: support listing setnames and headers too

Current listing makes possible to list sets with full content only.
The patch adds support partial listings, i.e. listing just
the existing setnames or listing set headers, without set members.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent ac8cc925
...@@ -142,6 +142,10 @@ enum ipset_errno { ...@@ -142,6 +142,10 @@ enum ipset_errno {
enum ipset_cmd_flags { enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0, IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), 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 */ /* Flags at CADT attribute level */
......
...@@ -939,10 +939,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, ...@@ -939,10 +939,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
/* List/save set data */ /* List/save set data */
#define DUMP_INIT 0L #define DUMP_INIT 0
#define DUMP_ALL 1L #define DUMP_ALL 1
#define DUMP_ONE 2L #define DUMP_ONE 2
#define DUMP_LAST 3L #define DUMP_LAST 3
#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF)
#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16)
static int static int
ip_set_dump_done(struct netlink_callback *cb) ip_set_dump_done(struct netlink_callback *cb)
...@@ -973,6 +976,7 @@ dump_init(struct netlink_callback *cb) ...@@ -973,6 +976,7 @@ dump_init(struct netlink_callback *cb)
int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
struct nlattr *attr = (void *)nlh + min_len; struct nlattr *attr = (void *)nlh + min_len;
u32 dump_type;
ip_set_id_t index; ip_set_id_t index;
/* Second pass, so parser can't fail */ /* Second pass, so parser can't fail */
...@@ -984,17 +988,22 @@ dump_init(struct netlink_callback *cb) ...@@ -984,17 +988,22 @@ dump_init(struct netlink_callback *cb)
* [..]: type specific * [..]: type specific
*/ */
if (!cda[IPSET_ATTR_SETNAME]) { if (cda[IPSET_ATTR_SETNAME]) {
cb->args[0] = DUMP_ALL; index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
return 0; if (index == IPSET_INVALID_ID)
} return -ENOENT;
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); dump_type = DUMP_ONE;
if (index == IPSET_INVALID_ID) cb->args[1] = index;
return -ENOENT; } 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;
cb->args[0] = DUMP_ONE;
cb->args[1] = index;
return 0; return 0;
} }
...@@ -1005,9 +1014,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1005,9 +1014,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
struct ip_set *set = NULL; struct ip_set *set = NULL;
struct nlmsghdr *nlh = NULL; struct nlmsghdr *nlh = NULL;
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
u32 dump_type, dump_flags;
int ret = 0; int ret = 0;
if (cb->args[0] == DUMP_INIT) { if (!cb->args[0]) {
ret = dump_init(cb); ret = dump_init(cb);
if (ret < 0) { if (ret < 0) {
nlh = nlmsg_hdr(cb->skb); nlh = nlmsg_hdr(cb->skb);
...@@ -1022,14 +1032,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1022,14 +1032,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->args[1] >= ip_set_max) if (cb->args[1] >= ip_set_max)
goto out; goto out;
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: dump_last:
pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); 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]++) { for (; cb->args[1] < max; cb->args[1]++) {
index = (ip_set_id_t) cb->args[1]; index = (ip_set_id_t) cb->args[1];
set = ip_set_list[index]; set = ip_set_list[index];
if (set == NULL) { if (set == NULL) {
if (cb->args[0] == DUMP_ONE) { if (dump_type == DUMP_ONE) {
ret = -ENOENT; ret = -ENOENT;
goto out; goto out;
} }
...@@ -1038,8 +1051,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1038,8 +1051,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
/* When dumping all sets, we must dump "sorted" /* When dumping all sets, we must dump "sorted"
* so that lists (unions of sets) are dumped last. * so that lists (unions of sets) are dumped last.
*/ */
if (cb->args[0] != DUMP_ONE && if (dump_type != DUMP_ONE &&
((cb->args[0] == DUMP_ALL) == ((dump_type == DUMP_ALL) ==
!!(set->type->features & IPSET_DUMP_LAST))) !!(set->type->features & IPSET_DUMP_LAST)))
continue; continue;
pr_debug("List set: %s\n", set->name); pr_debug("List set: %s\n", set->name);
...@@ -1057,6 +1070,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1057,6 +1070,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
} }
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name); NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
goto next_set;
switch (cb->args[2]) { switch (cb->args[2]) {
case 0: case 0:
/* Core header data */ /* Core header data */
...@@ -1069,24 +1084,23 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1069,24 +1084,23 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
ret = set->variant->head(set, skb); ret = set->variant->head(set, skb);
if (ret < 0) if (ret < 0)
goto release_refcount; goto release_refcount;
if (dump_flags & IPSET_FLAG_LIST_HEADER)
goto next_set;
/* Fall through and add elements */ /* Fall through and add elements */
default: default:
read_lock_bh(&set->lock); read_lock_bh(&set->lock);
ret = set->variant->list(set, skb, cb); ret = set->variant->list(set, skb, cb);
read_unlock_bh(&set->lock); read_unlock_bh(&set->lock);
if (!cb->args[2]) { if (!cb->args[2])
/* Set is done, proceed with next one */ /* Set is done, proceed with next one */
if (cb->args[0] == DUMP_ONE) goto next_set;
cb->args[1] = IPSET_INVALID_ID;
else
cb->args[1]++;
}
goto release_refcount; goto release_refcount;
} }
} }
/* If we dump all sets, continue with dumping last ones */ /* If we dump all sets, continue with dumping last ones */
if (cb->args[0] == DUMP_ALL) { if (dump_type == DUMP_ALL) {
cb->args[0] = DUMP_LAST; dump_type = DUMP_LAST;
cb->args[0] = dump_type | (dump_flags << 16);
cb->args[1] = 0; cb->args[1] = 0;
goto dump_last; goto dump_last;
} }
...@@ -1094,6 +1108,11 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1094,6 +1108,11 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
nla_put_failure: nla_put_failure:
ret = -EFAULT; ret = -EFAULT;
next_set:
if (dump_type == DUMP_ONE)
cb->args[1] = IPSET_INVALID_ID;
else
cb->args[1]++;
release_refcount: release_refcount:
/* If there was an error or set is done, release set */ /* If there was an error or set is done, release set */
if (ret || !cb->args[2]) { if (ret || !cb->args[2]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment