]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
ipset 2 related updates (JK)
authorJoszef Kadlecsik <kadlec@blackhole.kfki.hu>
Wed, 1 Dec 2004 09:11:33 +0000 (09:11 +0000)
committerJoszef Kadlecsik <kadlec@blackhole.kfki.hu>
Wed, 1 Dec 2004 09:11:33 +0000 (09:11 +0000)
extensions/libipt_SET.c
extensions/libipt_SET.man [new file with mode: 0644]
extensions/libipt_set.c
extensions/libipt_set.h [new file with mode: 0644]
extensions/libipt_set.man [new file with mode: 0644]

index 48c722a75141ce26bec7b126bc6cea40f0348d3e..2cf483c47c0f270ef0d7ff0ee648662bf2653014 100644 (file)
@@ -1,3 +1,13 @@
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ *                         Patrick Schaaf <bof@bof.de>
+ *                         Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.  
+ */
+
 /* Shared library add-on to iptables to add IP set mangling target. */
 #include <stdio.h>
 #include <netdb.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_set.h>
 #include <linux/netfilter_ipv4/ipt_set.h>
-#include "../ipset/libipt_set.h"
+#include "libipt_set.h"
 
 /* Function which prints out usage message. */
 static void help(void)
 {
        printf("SET v%s options:\n"
-              " --add-set name[:flags] flags\n"
-              " --del-set name[:flags] flags\n"
+              " --add-set name flags\n"
+              " --del-set name flags\n"
               "                add/del src/dst IP/port from/to named sets,\n"
               "                where flags are the comma separated list of\n"
               "                'src' and 'dst'.\n"
@@ -38,13 +48,42 @@ static void init(struct ipt_entry_target *target, unsigned int *nfcache)
            (struct ipt_set_info_target *) target->data;
 
        memset(info, 0, sizeof(struct ipt_set_info_target));
-       info->add_set.id = -1;
-       info->del_set.id = -1;
+       info->add_set.index =
+       info->del_set.index = IP_SET_INVALID_ID;
 
        /* Can't cache this */
        *nfcache |= NFC_UNKNOWN;
 }
 
+static void
+parse_target(char **argv, int invert, unsigned int *flags,
+             struct ipt_set_info *info, const char *what)
+{
+       if (info->flags[0])
+               exit_error(PARAMETER_PROBLEM,
+                          "--%s can be specified only once", what);
+
+       if (check_inverse(optarg, &invert, NULL, 0))
+               exit_error(PARAMETER_PROBLEM,
+                          "Unexpected `!' after --%s", what);
+
+       if (!argv[optind]
+           || argv[optind][0] == '-' || argv[optind][0] == '!')
+               exit_error(PARAMETER_PROBLEM,
+                          "--%s requires two args.", what);
+
+       if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
+               exit_error(PARAMETER_PROBLEM,
+                          "setname `%s' too long, max %d characters.",
+                          argv[optind-1], IP_SET_MAXNAMELEN - 1);
+
+       get_set_byname(argv[optind - 1], info);
+       parse_bindings(argv[optind], info);
+       optind++;
+       
+       *flags = 1;
+}
+
 /* Function which parses command options; returns true if it
    ate an option */
 static int
@@ -53,44 +92,15 @@ parse(int c, char **argv, int invert, unsigned int *flags,
 {
        struct ipt_set_info_target *myinfo =
            (struct ipt_set_info_target *) (*target)->data;
-       struct ipt_set_info *info;
 
        switch (c) {
-       case '1':               /* --add-set <set>[:<flags>] <flags> */
-               info = &myinfo->add_set;
-
-               if (check_inverse(optarg, &invert, NULL, 0))
-                       exit_error(PARAMETER_PROBLEM,
-                                  "Unexpected `!' after --add-set");
-
-               if (!argv[optind]
-                   || argv[optind][0] == '-' || argv[optind][0] == '!')
-                       exit_error(PARAMETER_PROBLEM,
-                                  "--add-set requires two args.");
-
-               parse_pool(argv[optind - 1], info);
-               parse_ipflags(argv[optind++], info);
-               
-               *flags = 1;
+       case '1':               /* --add-set <set> <flags> */
+               parse_target(argv, invert, flags,
+                            &myinfo->add_set, "add-set");
                break;
        case '2':               /* --del-set <set>[:<flags>] <flags> */
-               info = &myinfo->del_set;
-
-               if (check_inverse(optarg, &invert, NULL, 0))
-                       exit_error(PARAMETER_PROBLEM,
-                                  "Unexpected `!' after --del-set");
-
-               if (!argv[optind]
-                   || argv[optind][0] == '-' || argv[optind][0] == '!')
-                       exit_error(PARAMETER_PROBLEM,
-                                  "--del-set requires two args.");
-
-               parse_pool(argv[optind - 1], info);
-               if (parse_ipflags(argv[optind++], info))
-                       exit_error(PARAMETER_PROBLEM,
-                                  "Can't use overwrite flag with --del-set.");
-               
-               *flags = 1;
+               parse_target(argv, invert, flags,
+                            &myinfo->del_set, "del-set");
                break;
 
        default:
@@ -112,21 +122,17 @@ print_target(const char *prefix, const struct ipt_set_info *info)
 {
        int i;
        char setname[IP_SET_MAXNAMELEN];
-
-       if (info->id >= 0) {
-               get_set_byid(setname, info->id);
-               printf("%s %s", prefix, setname);
-               for (i = 0; i < info->set_level; i++)
-                       printf("%s%s",
-                              i == 0 ? ":" : ",",
-                              info->flags[i] & IPSET_SRC ? "src" : "dst");
-               for (i = info->set_level; i < info->ip_level; i++)
-                       printf("%s%s%s",
-                              i == info->set_level ? " " : ",",
-                              info->flags[i] & IPSET_ADD_OVERWRITE ? "+" : "",
-                              info->flags[i] & IPSET_SRC ? "src" : "dst");
-               printf(" ");
+       
+       get_set_byid(setname, info->index);
+       printf("%s %s", prefix, setname);
+       for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
+               if (!info->flags[i])
+                       break;          
+               printf("%s%s",
+                      i == 0 ? " " : ",",
+                      info->flags[i] & IPSET_SRC ? "src" : "dst");
        }
+       printf(" ");
 }
 
 /* Prints out the targinfo. */
diff --git a/extensions/libipt_SET.man b/extensions/libipt_SET.man
new file mode 100644 (file)
index 0000000..8f25bea
--- /dev/null
@@ -0,0 +1,16 @@
+This modules adds and/or deletes entries from IP sets which can be defined 
+by ipset(8).
+.TP
+.BR "--add-set " "setname flag[,flag...]"
+add the address(es)/port(s) of the packet to the sets
+.TP
+.BR "--del-set " "setname flag[,flag...]"
+delete the address(es)/port(s) of the packet from the sets,
+where flags are
+.BR "src"
+and/or
+.BR "dst"
+and there can be no more than six of them.
+.TP
+The bindings to follow must previously be defined in order to use 
+multilevel adding/deleting by the SET target.
index 06691f35efaf467511dbdf36fdb929d3f47b041d..7ab78ff790e9d259f7a9af2efff4d76eb8fa68c2 100644 (file)
@@ -1,4 +1,14 @@
-/* Shared library add-on to iptables to add IP address set matching. */
+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
+ *                         Patrick Schaaf <bof@bof.de>
+ *                         Martin Josefsson <gandalf@wlug.westbo.se>
+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.  
+ */
+
+/* Shared library add-on to iptables to add IP set matching. */
 #include <stdio.h>
 #include <netdb.h>
 #include <string.h>
 #include <iptables.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ipt_set.h>
-#include "../ipset/libipt_set.h"
+#include "libipt_set.h"
 
 /* Function which prints out usage message. */
 static void help(void)
 {
        printf("set v%s options:\n"
-              " [!] --set     name[:flags] flags\n"
-              "                'name' is the set name from to match.\n" 
+              " [!] --set     name flags\n"
+              "                'name' is the set name from to match,\n" 
               "                'flags' are the comma separated list of\n"
               "                'src' and 'dst'.\n"
               "\n", IPTABLES_VERSION);
@@ -36,7 +46,6 @@ static void init(struct ipt_entry_match *match, unsigned int *nfcache)
        
 
        memset(info, 0, sizeof(struct ipt_set_info_match));
-       info->match.id = -1;
 
        /* Can't cache this - XXX */
        *nfcache |= NFC_UNKNOWN;
@@ -50,23 +59,33 @@ parse(int c, char **argv, int invert, unsigned int *flags,
 {
        struct ipt_set_info_match *myinfo = 
                (struct ipt_set_info_match *) (*match)->data;
-       struct ipt_set_info *info = &myinfo->match;
+       struct ipt_set_info *info = &myinfo->match_set;
 
        switch (c) {
-       case '1':               /* --set <set>[:<flags>] <flags> */
+       case '1':               /* --set <set> <flag>[,<flag> */
+               if (info->flags[0])
+                       exit_error(PARAMETER_PROBLEM,
+                                  "--set can be specified only once");
+
                check_inverse(optarg, &invert, &optind, 0);
                if (invert)
                        info->flags[0] |= IPSET_MATCH_INV;
 
                if (!argv[optind]
-                   || argv[optind][0] == '-' || argv[optind][0] == '!')
+                   || argv[optind][0] == '-'
+                   || argv[optind][0] == '!')
                        exit_error(PARAMETER_PROBLEM,
                                   "--set requires two args.");
 
-               parse_pool(argv[optind - 1], info);
-               if (parse_ipflags(argv[optind++], info))
+               if (strlen(argv[optind-1]) > IP_SET_MAXNAMELEN - 1)
                        exit_error(PARAMETER_PROBLEM,
-                                  "Can't use overwrite flag with --set.");
+                                  "setname `%s' too long, max %d characters.",
+                                  argv[optind-1], IP_SET_MAXNAMELEN - 1);
+
+               get_set_byname(argv[optind - 1], info);
+               parse_bindings(argv[optind], info);
+               DEBUGP("parse: set index %u\n", info->index);
+               optind++;
                
                *flags = 1;
                break;
@@ -83,7 +102,8 @@ static void final_check(unsigned int flags)
 {
        if (!flags)
                exit_error(PARAMETER_PROBLEM,
-                          "You must specify either `--set'");
+                          "You must specify `--set' with proper arguments");
+       DEBUGP("final check OK\n");
 }
 
 static void
@@ -92,22 +112,19 @@ print_match(const char *prefix, const struct ipt_set_info *info)
        int i;
        char setname[IP_SET_MAXNAMELEN];
 
-       if (info->id >= 0) {
-               get_set_byid(setname, info->id);
-               printf("%s%s %s", 
-                      (info->flags[0] & IPSET_MATCH_INV) ? "!" : "",
-                      prefix,
-                      setname); 
-               for (i = 0; i < info->set_level; i++)
-                       printf("%s%s",
-                              i == 0 ? ":" : ",",
-                              info->flags[i] & IPSET_SRC ? "src" : "dst");
-               for (i = info->set_level; i < info->ip_level; i++)
-                       printf("%s%s",
-                              i == info->set_level ? " " : ",",
-                              info->flags[i] & IPSET_SRC ? "src" : "dst");
-               printf(" ");
+       get_set_byid(setname, info->index);
+       printf("%s%s %s", 
+              (info->flags[0] & IPSET_MATCH_INV) ? "!" : "",
+              prefix,
+              setname); 
+       for (i = 0; i < IP_SET_MAX_BINDINGS; i++) {
+               if (!info->flags[i])
+                       break;          
+               printf("%s%s",
+                      i == 0 ? " " : ",",
+                      info->flags[i] & IPSET_SRC ? "src" : "dst");
        }
+       printf(" ");
 }
 
 /* Prints out the matchinfo. */
@@ -118,7 +135,7 @@ print(const struct ipt_ip *ip,
        struct ipt_set_info_match *info = 
                (struct ipt_set_info_match *) match->data;
 
-       print_match("set", &info->match);
+       print_match("set", &info->match_set);
 }
 
 /* Saves the matchinfo in parsable form to stdout. */
@@ -128,11 +145,11 @@ static void save(const struct ipt_ip *ip,
        struct ipt_set_info_match *info = 
                (struct ipt_set_info_match *) match->data;
 
-       print_match("--set", &info->match);
+       print_match("--set", &info->match_set);
 }
 
 static
-struct iptables_match set = { NULL,
+struct iptables_match set = {
        .name           = "set",
        .version        = IPTABLES_VERSION,
        .size           = IPT_ALIGN(sizeof(struct ipt_set_info_match)),
diff --git a/extensions/libipt_set.h b/extensions/libipt_set.h
new file mode 100644 (file)
index 0000000..0d6b329
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef _LIBIPT_SET_H
+#define _LIBIPT_SET_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#ifdef DEBUG
+#define DEBUGP(x, args...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args...) 
+#endif
+
+static void
+parse_bindings(const char *optarg, struct ipt_set_info *info)
+{
+       char *saved = strdup(optarg);
+       char *ptr, *tmp = saved;
+       int i = 0;
+       
+       while (i < (IP_SET_MAX_BINDINGS - 1) && tmp != NULL) {
+               ptr = strsep(&tmp, ",");
+               if (strncmp(ptr, "src", 3) == 0)
+                       info->flags[i++] |= IPSET_SRC;
+               else if (strncmp(ptr, "dst", 3) == 0)
+                       info->flags[i++] |= IPSET_DST;
+               else
+                       exit_error(PARAMETER_PROBLEM,
+                                  "You must spefify (the comma separated list of) 'src' or 'dst'.");
+       }
+
+       if (tmp)
+               exit_error(PARAMETER_PROBLEM,
+                          "Can't follow bindings deeper than %i.", 
+                          IP_SET_MAX_BINDINGS - 1);
+
+       free(saved);
+}
+
+static int get_set_getsockopt(void *data, size_t * size)
+{
+       int sockfd = -1;
+       sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+       if (sockfd < 0)
+               exit_error(OTHER_PROBLEM,
+                          "Can't open socket to ipset.\n");
+       /* Send! */
+       return getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size);
+}
+
+static void get_set_byname(const char *setname, struct ipt_set_info *info)
+{
+       struct ip_set_req_get_set req;
+       int size = sizeof(struct ip_set_req_get_set);
+       int res;
+
+       req.op = IP_SET_OP_GET_BYNAME;
+       req.version = IP_SET_PROTOCOL_VERSION;
+       strncpy(req.set.name, setname, IP_SET_MAXNAMELEN);
+       req.set.name[IP_SET_MAXNAMELEN - 1] = '\0';
+       res = get_set_getsockopt(&req, &size);
+       if (res != 0)
+               exit_error(OTHER_PROBLEM,
+                          "Problem when communicating with ipset, errno=%d.\n",
+                          errno);
+       if (size != sizeof(struct ip_set_req_get_set))
+               exit_error(OTHER_PROBLEM,
+                          "Incorrect return size from kernel during ipset lookup, "
+                          "(want %d, got %d)\n",
+                          sizeof(struct ip_set_req_get_set), size);
+       if (req.set.index == IP_SET_INVALID_ID)
+               exit_error(PARAMETER_PROBLEM,
+                          "Set %s doesn't exist.\n", setname);
+
+       info->index = req.set.index;
+}
+
+static void get_set_byid(char * setname, ip_set_id_t index)
+{
+       struct ip_set_req_get_set req;
+       int size = sizeof(struct ip_set_req_get_set);
+       int res;
+
+       req.op = IP_SET_OP_GET_BYINDEX;
+       req.version = IP_SET_PROTOCOL_VERSION;
+       req.set.index = index;
+       res = get_set_getsockopt(&req, &size);
+       if (res != 0)
+               exit_error(OTHER_PROBLEM,
+                          "Problem when communicating with ipset, errno=%d.\n",
+                          errno);
+       if (size != sizeof(struct ip_set_req_get_set))
+               exit_error(OTHER_PROBLEM,
+                          "Incorrect return size from kernel during ipset lookup, "
+                          "(want %d, got %d)\n",
+                          sizeof(struct ip_set_req_get_set), size);
+       if (req.set.name[0] == '\0')
+               exit_error(PARAMETER_PROBLEM,
+                          "Set id %i in kernel doesn't exist.\n", index);
+
+       strncpy(setname, req.set.name, IP_SET_MAXNAMELEN);
+}
+
+#endif /*_LIBIPT_SET_H*/
diff --git a/extensions/libipt_set.man b/extensions/libipt_set.man
new file mode 100644 (file)
index 0000000..d280577
--- /dev/null
@@ -0,0 +1,17 @@
+This modules macthes IP sets which can be defined by ipset(8).
+.TP
+.BR "--set " "setname flag[,flag...]"
+where flags are
+.BR "src"
+and/or
+.BR "dst" 
+and there can be no more than six of them. Hence the command
+.nf
+ iptables -A FORWARD -m set --set test src,dst
+.fi
+will match packets, for which (depending on the type of the set) the source
+address or port number of the packet can be found in the specified set. If 
+there is a binding belonging to the mached set element or there is a default 
+binding for the given set, then the rule will match the packet only if 
+additionally (depending on the type of the set) the destination address or 
+port number of the packet can be found in the set according to the binding.