diff options
Diffstat (limited to 'extensions/libxt_set.h')
-rw-r--r-- | extensions/libxt_set.h | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index 6b93691..5a1bdcf 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -2,9 +2,11 @@ #define _LIBXT_SET_H #include <unistd.h> +#include <fcntl.h> #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) @@ -23,6 +25,12 @@ get_version(unsigned *version) xtables_error(OTHER_PROBLEM, "Can't open socket to ipset.\n"); + if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { + xtables_error(OTHER_PROBLEM, + "Could not set close on exec: %s\n", + strerror(errno)); + } + req_version.op = IP_SET_OP_VERSION; res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size); if (res != 0) @@ -64,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'; @@ -94,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); @@ -114,7 +165,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info) if (tmp) xtables_error(PARAMETER_PROBLEM, "Can't be more src/dst options than %i.", - IPSET_DIM_MAX - 1); + IPSET_DIM_MAX); free(saved); } @@ -124,9 +175,8 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info) { char *saved = strdup(opt_arg); char *ptr, *tmp = saved; - int i = 0; - while (i < (IPSET_DIM_MAX - 1) && tmp != NULL) { + while (info->dim < IPSET_DIM_MAX && tmp != NULL) { info->dim++; ptr = strsep(&tmp, ","); if (strncmp(ptr, "src", 3) == 0) @@ -139,7 +189,7 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info) if (tmp) xtables_error(PARAMETER_PROBLEM, "Can't be more src/dst options than %i.", - IPSET_DIM_MAX - 1); + IPSET_DIM_MAX); free(saved); } |