diff options
-rw-r--r-- | include/libipset/linux_ip_set.h | 4 | ||||
-rw-r--r-- | include/libipset/session.h | 4 | ||||
-rw-r--r-- | kernel/include/linux/netfilter/ipset/ip_set.h | 4 | ||||
-rw-r--r-- | kernel/net/netfilter/ipset/ip_set_core.c | 73 | ||||
-rw-r--r-- | lib/session.c | 33 | ||||
-rw-r--r-- | src/ipset.8 | 20 | ||||
-rw-r--r-- | src/ui.c | 13 |
7 files changed, 118 insertions, 33 deletions
diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h index d81a811..00cf0c6 100644 --- a/include/libipset/linux_ip_set.h +++ b/include/libipset/linux_ip_set.h @@ -142,6 +142,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 */ diff --git a/include/libipset/session.h b/include/libipset/session.h index a06c79f..5ccdd6c 100644 --- a/include/libipset/session.h +++ b/include/libipset/session.h @@ -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, diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h index 68b21f5..e677c4d 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set.h +++ b/kernel/include/linux/netfilter/ipset/ip_set.h @@ -142,6 +142,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 */ diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c index 126d555..ea1f561 100644 --- a/kernel/net/netfilter/ipset/ip_set_core.c +++ b/kernel/net/netfilter/ipset/ip_set_core.c @@ -944,10 +944,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, /* 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) @@ -978,6 +981,7 @@ dump_init(struct netlink_callback *cb) int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); 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 */ @@ -989,17 +993,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; - 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; - cb->args[0] = DUMP_ONE; - cb->args[1] = index; return 0; } @@ -1010,9 +1019,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) struct ip_set *set = NULL; struct nlmsghdr *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) { nlh = nlmsg_hdr(cb->skb); @@ -1027,14 +1037,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) if (cb->args[1] >= ip_set_max) 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: - 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]++) { 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; } @@ -1043,8 +1056,8 @@ dump_last: /* 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) == + if (dump_type != DUMP_ONE && + ((dump_type == DUMP_ALL) == !!(set->type->features & IPSET_DUMP_LAST))) continue; pr_debug("List set: %s\n", set->name); @@ -1062,6 +1075,8 @@ dump_last: } 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,24 +1089,23 @@ dump_last: 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 (cb->args[0] == DUMP_ALL) { - cb->args[0] = DUMP_LAST; + if (dump_type == DUMP_ALL) { + dump_type = DUMP_LAST; + cb->args[0] = dump_type | (dump_flags << 16); cb->args[1] = 0; goto dump_last; } @@ -1099,6 +1113,11 @@ dump_last: 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]) { diff --git a/lib/session.c b/lib/session.c index a193143..9a7f45b 100644 --- a/lib/session.c +++ b/lib/session.c @@ -136,6 +136,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: @@ -885,7 +887,9 @@ 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>"); @@ -938,6 +942,16 @@ 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) { + 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) @@ -1602,11 +1616,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) { + 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)) diff --git a/src/ipset.8 b/src/ipset.8 index d9e5ff8..21750fa 100644 --- a/src/ipset.8 +++ b/src/ipset.8 @@ -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 @@ -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.", + }, { }, }; |