]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
extensions: libxt_set, libxt_SET: check the set family too
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Wed, 4 Sep 2013 15:43:49 +0000 (17:43 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 18 Nov 2013 17:47:32 +0000 (18:47 +0100)
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>
extensions/libxt_set.h
include/linux/netfilter/ipset/ip_set.h

index 47c3f5b6f5d49865c028edc259265c334b66beb9..5a1bdcf730cf218078e82f6b0a27d97c08cfeb77 100644 (file)
@@ -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';
@@ -100,6 +101,49 @@ get_set_byname(const char *setname, struct xt_set_info *info)
        info->index = req.set.index;
 }
 
+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)
 {
index eb9123e641de793c6ad3c4c7552a49e4e81ef73e..0dcf5ddfdf91784e666b692d79e691633d03fb1d 100644 (file)
@@ -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;