Commit c1e2e04388b2539960453689b8e721709f71dc9c
Committed by
Patrick McHardy
1 parent
ac8cc925d3
Exists in
master
and in
6 other branches
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: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Showing 2 changed files with 50 additions and 27 deletions Side-by-side Diff
include/linux/netfilter/ipset/ip_set.h
... | ... | @@ -142,6 +142,10 @@ |
142 | 142 | enum ipset_cmd_flags { |
143 | 143 | IPSET_FLAG_BIT_EXIST = 0, |
144 | 144 | IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST), |
145 | + IPSET_FLAG_BIT_LIST_SETNAME = 1, | |
146 | + IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME), | |
147 | + IPSET_FLAG_BIT_LIST_HEADER = 2, | |
148 | + IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER), | |
145 | 149 | }; |
146 | 150 | |
147 | 151 | /* Flags at CADT attribute level */ |
net/netfilter/ipset/ip_set_core.c
... | ... | @@ -939,11 +939,14 @@ |
939 | 939 | |
940 | 940 | /* List/save set data */ |
941 | 941 | |
942 | -#define DUMP_INIT 0L | |
943 | -#define DUMP_ALL 1L | |
944 | -#define DUMP_ONE 2L | |
945 | -#define DUMP_LAST 3L | |
942 | +#define DUMP_INIT 0 | |
943 | +#define DUMP_ALL 1 | |
944 | +#define DUMP_ONE 2 | |
945 | +#define DUMP_LAST 3 | |
946 | 946 | |
947 | +#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF) | |
948 | +#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16) | |
949 | + | |
947 | 950 | static int |
948 | 951 | ip_set_dump_done(struct netlink_callback *cb) |
949 | 952 | { |
... | ... | @@ -973,6 +976,7 @@ |
973 | 976 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); |
974 | 977 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; |
975 | 978 | struct nlattr *attr = (void *)nlh + min_len; |
979 | + u32 dump_type; | |
976 | 980 | ip_set_id_t index; |
977 | 981 | |
978 | 982 | /* Second pass, so parser can't fail */ |
979 | 983 | |
980 | 984 | |
... | ... | @@ -984,17 +988,22 @@ |
984 | 988 | * [..]: type specific |
985 | 989 | */ |
986 | 990 | |
987 | - if (!cda[IPSET_ATTR_SETNAME]) { | |
988 | - cb->args[0] = DUMP_ALL; | |
989 | - return 0; | |
990 | - } | |
991 | + if (cda[IPSET_ATTR_SETNAME]) { | |
992 | + index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); | |
993 | + if (index == IPSET_INVALID_ID) | |
994 | + return -ENOENT; | |
991 | 995 | |
992 | - index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); | |
993 | - if (index == IPSET_INVALID_ID) | |
994 | - return -ENOENT; | |
996 | + dump_type = DUMP_ONE; | |
997 | + cb->args[1] = index; | |
998 | + } else | |
999 | + dump_type = DUMP_ALL; | |
995 | 1000 | |
996 | - cb->args[0] = DUMP_ONE; | |
997 | - cb->args[1] = index; | |
1001 | + if (cda[IPSET_ATTR_FLAGS]) { | |
1002 | + u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]); | |
1003 | + dump_type |= (f << 16); | |
1004 | + } | |
1005 | + cb->args[0] = dump_type; | |
1006 | + | |
998 | 1007 | return 0; |
999 | 1008 | } |
1000 | 1009 | |
1001 | 1010 | |
... | ... | @@ -1005,9 +1014,10 @@ |
1005 | 1014 | struct ip_set *set = NULL; |
1006 | 1015 | struct nlmsghdr *nlh = NULL; |
1007 | 1016 | unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; |
1017 | + u32 dump_type, dump_flags; | |
1008 | 1018 | int ret = 0; |
1009 | 1019 | |
1010 | - if (cb->args[0] == DUMP_INIT) { | |
1020 | + if (!cb->args[0]) { | |
1011 | 1021 | ret = dump_init(cb); |
1012 | 1022 | if (ret < 0) { |
1013 | 1023 | nlh = nlmsg_hdr(cb->skb); |
1014 | 1024 | |
1015 | 1025 | |
... | ... | @@ -1022,14 +1032,17 @@ |
1022 | 1032 | if (cb->args[1] >= ip_set_max) |
1023 | 1033 | goto out; |
1024 | 1034 | |
1025 | - max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; | |
1035 | + dump_type = DUMP_TYPE(cb->args[0]); | |
1036 | + dump_flags = DUMP_FLAGS(cb->args[0]); | |
1037 | + max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; | |
1026 | 1038 | dump_last: |
1027 | - pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]); | |
1039 | + pr_debug("args[0]: %u %u args[1]: %ld\n", | |
1040 | + dump_type, dump_flags, cb->args[1]); | |
1028 | 1041 | for (; cb->args[1] < max; cb->args[1]++) { |
1029 | 1042 | index = (ip_set_id_t) cb->args[1]; |
1030 | 1043 | set = ip_set_list[index]; |
1031 | 1044 | if (set == NULL) { |
1032 | - if (cb->args[0] == DUMP_ONE) { | |
1045 | + if (dump_type == DUMP_ONE) { | |
1033 | 1046 | ret = -ENOENT; |
1034 | 1047 | goto out; |
1035 | 1048 | } |
... | ... | @@ -1038,8 +1051,8 @@ |
1038 | 1051 | /* When dumping all sets, we must dump "sorted" |
1039 | 1052 | * so that lists (unions of sets) are dumped last. |
1040 | 1053 | */ |
1041 | - if (cb->args[0] != DUMP_ONE && | |
1042 | - ((cb->args[0] == DUMP_ALL) == | |
1054 | + if (dump_type != DUMP_ONE && | |
1055 | + ((dump_type == DUMP_ALL) == | |
1043 | 1056 | !!(set->type->features & IPSET_DUMP_LAST))) |
1044 | 1057 | continue; |
1045 | 1058 | pr_debug("List set: %s\n", set->name); |
... | ... | @@ -1057,6 +1070,8 @@ |
1057 | 1070 | } |
1058 | 1071 | NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); |
1059 | 1072 | NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name); |
1073 | + if (dump_flags & IPSET_FLAG_LIST_SETNAME) | |
1074 | + goto next_set; | |
1060 | 1075 | switch (cb->args[2]) { |
1061 | 1076 | case 0: |
1062 | 1077 | /* Core header data */ |
1063 | 1078 | |
1064 | 1079 | |
1065 | 1080 | |
... | ... | @@ -1069,24 +1084,23 @@ |
1069 | 1084 | ret = set->variant->head(set, skb); |
1070 | 1085 | if (ret < 0) |
1071 | 1086 | goto release_refcount; |
1087 | + if (dump_flags & IPSET_FLAG_LIST_HEADER) | |
1088 | + goto next_set; | |
1072 | 1089 | /* Fall through and add elements */ |
1073 | 1090 | default: |
1074 | 1091 | read_lock_bh(&set->lock); |
1075 | 1092 | ret = set->variant->list(set, skb, cb); |
1076 | 1093 | read_unlock_bh(&set->lock); |
1077 | - if (!cb->args[2]) { | |
1094 | + if (!cb->args[2]) | |
1078 | 1095 | /* Set is done, proceed with next one */ |
1079 | - if (cb->args[0] == DUMP_ONE) | |
1080 | - cb->args[1] = IPSET_INVALID_ID; | |
1081 | - else | |
1082 | - cb->args[1]++; | |
1083 | - } | |
1096 | + goto next_set; | |
1084 | 1097 | goto release_refcount; |
1085 | 1098 | } |
1086 | 1099 | } |
1087 | 1100 | /* If we dump all sets, continue with dumping last ones */ |
1088 | - if (cb->args[0] == DUMP_ALL) { | |
1089 | - cb->args[0] = DUMP_LAST; | |
1101 | + if (dump_type == DUMP_ALL) { | |
1102 | + dump_type = DUMP_LAST; | |
1103 | + cb->args[0] = dump_type | (dump_flags << 16); | |
1090 | 1104 | cb->args[1] = 0; |
1091 | 1105 | goto dump_last; |
1092 | 1106 | } |
... | ... | @@ -1094,6 +1108,11 @@ |
1094 | 1108 | |
1095 | 1109 | nla_put_failure: |
1096 | 1110 | ret = -EFAULT; |
1111 | +next_set: | |
1112 | + if (dump_type == DUMP_ONE) | |
1113 | + cb->args[1] = IPSET_INVALID_ID; | |
1114 | + else | |
1115 | + cb->args[1]++; | |
1097 | 1116 | release_refcount: |
1098 | 1117 | /* If there was an error or set is done, release set */ |
1099 | 1118 | if (ret || !cb->args[2]) { |