diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2013-09-04 17:43:49 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-11-18 18:47:32 +0100 |
commit | cf1f03f8f3cf2db577a9ddee254cc7f886129d18 (patch) | |
tree | 6c9c40726b8a428b217af6c7e89fc18d4040a8fc | |
parent | 9e6928f037823773a37630dec5a764455dcea6fb (diff) |
extensions: libxt_set, libxt_SET: check the set family too
Do not accept silently sets with wrong protocol family but reject
them with an error message. It makes straightforward to catch user
errors.
[ Use afinfo instead to avoid a binary interface update --pablo ]
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | extensions/libxt_set.h | 52 | ||||
-rw-r--r-- | include/linux/netfilter/ipset/ip_set.h | 9 |
2 files changed, 57 insertions, 4 deletions
diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index 47c3f5b6..5a1bdcf7 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -6,6 +6,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <errno.h> +#include "../iptables/xshared.h" #ifdef DEBUG #define DEBUGP(x, args...) fprintf(stderr, x , ## args) @@ -71,13 +72,13 @@ get_set_byid(char *setname, ip_set_id_t idx) } static void -get_set_byname(const char *setname, struct xt_set_info *info) +get_set_byname_only(const char *setname, struct xt_set_info *info, + int sockfd, unsigned int version) { - struct ip_set_req_get_set req; + struct ip_set_req_get_set req = { .version = version }; socklen_t size = sizeof(struct ip_set_req_get_set); - int res, sockfd; + int res; - sockfd = get_version(&req.version); req.op = IP_SET_OP_GET_BYNAME; strncpy(req.set.name, setname, IPSET_MAXNAMELEN); req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; @@ -101,6 +102,49 @@ get_set_byname(const char *setname, struct xt_set_info *info) } static void +get_set_byname(const char *setname, struct xt_set_info *info) +{ + struct ip_set_req_get_set_family req; + socklen_t size = sizeof(struct ip_set_req_get_set_family); + int res, sockfd, version; + + sockfd = get_version(&req.version); + version = req.version; + req.op = IP_SET_OP_GET_FNAME; + strncpy(req.set.name, setname, IPSET_MAXNAMELEN); + req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size); + + if (res != 0 && errno == EBADMSG) + /* Backward compatibility */ + return get_set_byname_only(setname, info, sockfd, version); + + close(sockfd); + if (res != 0) + xtables_error(OTHER_PROBLEM, + "Problem when communicating with ipset, errno=%d.\n", + errno); + if (size != sizeof(struct ip_set_req_get_set_family)) + xtables_error(OTHER_PROBLEM, + "Incorrect return size from kernel during ipset lookup, " + "(want %zu, got %zu)\n", + sizeof(struct ip_set_req_get_set_family), + (size_t)size); + if (req.set.index == IPSET_INVALID_ID) + xtables_error(PARAMETER_PROBLEM, + "Set %s doesn't exist.\n", setname); + if (!(req.family == afinfo->family || + req.family == NFPROTO_UNSPEC)) + xtables_error(PARAMETER_PROBLEM, + "The protocol family of set %s is %s, " + "which is not applicable.\n", + setname, + req.family == NFPROTO_IPV4 ? "IPv4" : "IPv6"); + + info->index = req.set.index; +} + +static void parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info) { char *saved = strdup(opt_arg); diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index eb9123e6..0dcf5ddf 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -250,6 +250,15 @@ struct ip_set_req_get_set { #define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ /* Uses ip_set_req_get_set */ +#define IP_SET_OP_GET_FNAME 0x00000008 /* Get set index and family */ +struct ip_set_req_get_set_family { + unsigned int op; + unsigned int version; + unsigned int family; + union ip_set_name_index set; +}; + + #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ struct ip_set_req_version { unsigned int op; |