]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables: SET target: Add mapping of meta informations (skbinfo ipset extension)
authorAnton Danilov <littlesmilingcloud@gmail.com>
Tue, 2 Sep 2014 10:15:53 +0000 (14:15 +0400)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Sun, 14 Sep 2014 18:17:32 +0000 (20:17 +0200)
This feature add support of mapping metainformation to packets like nftables maps or
ipfw tables. Currently we can map firewall mark, tc priority and hardware NIC queue.
Usage of this functionality allowed only from mangle table. We can map tc priority
only in OUTPUT/FORWARD/POSTROUTING chains because it rewrite by route decision.
If entry doesn't exist in the set nothing of fields changed.

Example of classify by destination address:
iptables -t mangle -A POSTROUTING -o eth0 -j SET --map-set DST2CLASS dst --map-prio

Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com>
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
extensions/libxt_SET.c
extensions/libxt_SET.man
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/xt_set.h

index a11db39520149edc8abbb81a3f8e78f7f48fc68d..2a7640a07efc3ec4000978482f95849d22759fb4 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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.  
+ * published by the Free Software Foundation.
  */
 
 /* Shared library add-on to iptables to add IP set mangling target. */
@@ -80,7 +80,7 @@ parse_target_v0(char **argv, int invert, unsigned int *flags,
        get_set_byname(optarg, (struct xt_set_info *)info);
        parse_dirs_v0(argv[optind], info);
        optind++;
-       
+
        *flags = 1;
 }
 
@@ -116,7 +116,7 @@ print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
        printf(" %s %s", prefix, setname);
        for (i = 0; i < IPSET_DIM_MAX; i++) {
                if (!info->u.flags[i])
-                       break;          
+                       break;
                printf("%s%s",
                       i == 0 ? " " : ",",
                       info->u.flags[i] & IPSET_SRC ? "src" : "dst");
@@ -125,7 +125,7 @@ print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
 
 static void
 set_target_print_v0(const void *ip, const struct xt_entry_target *target,
-                    int numeric)
+                   int numeric)
 {
        const struct xt_set_info_target_v0 *info = (const void *)target->data;
 
@@ -158,6 +158,10 @@ set_target_init_v1(struct xt_entry_target *target)
 #define SET_TARGET_DEL         0x2
 #define SET_TARGET_EXIST       0x4
 #define SET_TARGET_TIMEOUT     0x8
+#define SET_TARGET_MAP         0x10
+#define SET_TARGET_MAP_MARK    0x20
+#define SET_TARGET_MAP_PRIO    0x40
+#define SET_TARGET_MAP_QUEUE   0x80
 
 static void
 parse_target(char **argv, int invert, struct xt_set_info *info,
@@ -314,7 +318,7 @@ set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
                                      "or out of range 0-%u", UINT32_MAX - 1);
                myinfo->timeout = timeout;
                *flags |= SET_TARGET_TIMEOUT;
-               break;  
+               break;
        }
        return 1;
 }
@@ -346,6 +350,170 @@ set_target_save_v2(const void *ip, const struct xt_entry_target *target)
        print_target("--del-set", &info->del_set);
 }
 
+
+/* Revision 3 */
+
+static void
+set_target_help_v3(void)
+{
+       printf("SET target options:\n"
+              " --add-set name flags [--exist] [--timeout n]\n"
+              " --del-set name flags\n"
+              " --map-set name flags"
+              " [--map-mark] [--map-prio] [--map-queue]\n"
+              "                add/del src/dst IP/port from/to named sets,\n"
+              "                where flags are the comma separated list of\n"
+              "                'src' and 'dst' specifications.\n");
+}
+
+static const struct option set_target_opts_v3[] = {
+       {.name = "add-set",     .has_arg = true,  .val = '1'},
+       {.name = "del-set",     .has_arg = true,  .val = '2'},
+       {.name = "exist",       .has_arg = false, .val = '3'},
+       {.name = "timeout",     .has_arg = true,  .val = '4'},
+       {.name = "map-set",     .has_arg = true,  .val = '5'},
+       {.name = "map-mark",    .has_arg = false, .val = '6'},
+       {.name = "map-prio",    .has_arg = false, .val = '7'},
+       {.name = "map-queue",   .has_arg = false, .val = '8'},
+       XT_GETOPT_TABLEEND,
+};
+
+static void
+set_target_check_v3(unsigned int flags)
+{
+       if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL|SET_TARGET_MAP)))
+               xtables_error(PARAMETER_PROBLEM,
+                             "You must specify either `--add-set' or "
+                             "`--del-set' or `--map-set'");
+       if (!(flags & SET_TARGET_ADD)) {
+               if (flags & SET_TARGET_EXIST)
+                       xtables_error(PARAMETER_PROBLEM,
+                               "Flag `--exist' can be used with `--add-set' only");
+               if (flags & SET_TARGET_TIMEOUT)
+                       xtables_error(PARAMETER_PROBLEM,
+                               "Option `--timeout' can be used with `--add-set' only");
+       }
+       if (!(flags & SET_TARGET_MAP)) {
+               if (flags & SET_TARGET_MAP_MARK)
+                       xtables_error(PARAMETER_PROBLEM,
+                               "Flag `--map-mark' can be used with `--map-set' only");
+               if (flags & SET_TARGET_MAP_PRIO)
+                       xtables_error(PARAMETER_PROBLEM,
+                               "Flag `--map-prio' can be used with `--map-set' only");
+               if (flags & SET_TARGET_MAP_QUEUE)
+                       xtables_error(PARAMETER_PROBLEM,
+                               "Flag `--map-queue' can be used with `--map-set' only");
+       }
+       if ((flags & SET_TARGET_MAP) && !(flags & (SET_TARGET_MAP_MARK |
+                                                  SET_TARGET_MAP_PRIO |
+                                                  SET_TARGET_MAP_QUEUE)))
+               xtables_error(PARAMETER_PROBLEM,
+                       "You must specify flags `--map-mark' or "
+                       "'--map-prio` or `--map-queue'");
+}
+
+static void
+set_target_init_v3(struct xt_entry_target *target)
+{
+       struct xt_set_info_target_v3 *info =
+               (struct xt_set_info_target_v3 *) target->data;
+
+       info->add_set.index =
+       info->del_set.index =
+       info->map_set.index = IPSET_INVALID_ID;
+       info->timeout = UINT32_MAX;
+}
+
+static int
+set_target_parse_v3(int c, char **argv, int invert, unsigned int *flags,
+                   const void *entry, struct xt_entry_target **target)
+{
+       struct xt_set_info_target_v3 *myinfo =
+               (struct xt_set_info_target_v3 *) (*target)->data;
+       unsigned int timeout;
+
+       switch (c) {
+       case '1':               /* --add-set <set> <flags> */
+               parse_target(argv, invert, &myinfo->add_set, "add-set");
+               *flags |= SET_TARGET_ADD;
+               break;
+       case '2':               /* --del-set <set>[:<flags>] <flags> */
+               parse_target(argv, invert, &myinfo->del_set, "del-set");
+               *flags |= SET_TARGET_DEL;
+               break;
+       case '3':
+               myinfo->flags |= IPSET_FLAG_EXIST;
+               *flags |= SET_TARGET_EXIST;
+               break;
+       case '4':
+               if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "Invalid value for option --timeout "
+                                     "or out of range 0-%u", UINT32_MAX - 1);
+               myinfo->timeout = timeout;
+               *flags |= SET_TARGET_TIMEOUT;
+               break;
+       case '5':               /* --map-set <set> <flags> */
+               parse_target(argv, invert, &myinfo->map_set, "map-set");
+               *flags |= SET_TARGET_MAP;
+               break;
+       case '6':
+               myinfo->flags |= IPSET_FLAG_MAP_SKBMARK;
+               *flags |= SET_TARGET_MAP_MARK;
+               break;
+       case '7':
+               myinfo->flags |= IPSET_FLAG_MAP_SKBPRIO;
+               *flags |= SET_TARGET_MAP_PRIO;
+               break;
+       case '8':
+               myinfo->flags |= IPSET_FLAG_MAP_SKBQUEUE;
+               *flags |= SET_TARGET_MAP_QUEUE;
+               break;
+       }
+       return 1;
+}
+
+static void
+set_target_print_v3(const void *ip, const struct xt_entry_target *target,
+                   int numeric)
+{
+       const struct xt_set_info_target_v3 *info = (const void *)target->data;
+
+       print_target("add-set", &info->add_set);
+       if (info->flags & IPSET_FLAG_EXIST)
+               printf(" exist");
+       if (info->timeout != UINT32_MAX)
+               printf(" timeout %u", info->timeout);
+       print_target("del-set", &info->del_set);
+       print_target("map-set", &info->map_set);
+       if (info->flags & IPSET_FLAG_MAP_SKBMARK)
+               printf(" map-mark");
+       if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
+               printf(" map-prio");
+       if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
+               printf(" map-queue");
+}
+
+static void
+set_target_save_v3(const void *ip, const struct xt_entry_target *target)
+{
+       const struct xt_set_info_target_v3 *info = (const void *)target->data;
+
+       print_target("--add-set", &info->add_set);
+       if (info->flags & IPSET_FLAG_EXIST)
+               printf(" --exist");
+       if (info->timeout != UINT32_MAX)
+               printf(" --timeout %u", info->timeout);
+       print_target("--del-set", &info->del_set);
+       print_target("--map-set", &info->map_set);
+       if (info->flags & IPSET_FLAG_MAP_SKBMARK)
+               printf(" --map-mark");
+       if (info->flags & IPSET_FLAG_MAP_SKBPRIO)
+               printf(" --map-prio");
+       if (info->flags & IPSET_FLAG_MAP_SKBQUEUE)
+               printf(" --map-queue");
+}
+
 static struct xtables_target set_tg_reg[] = {
        {
                .name           = "SET",
@@ -392,6 +560,21 @@ static struct xtables_target set_tg_reg[] = {
                .save           = set_target_save_v2,
                .extra_opts     = set_target_opts_v2,
        },
+       {
+               .name           = "SET",
+               .revision       = 3,
+               .version        = XTABLES_VERSION,
+               .family         = NFPROTO_UNSPEC,
+               .size           = XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
+               .userspacesize  = XT_ALIGN(sizeof(struct xt_set_info_target_v3)),
+               .help           = set_target_help_v3,
+               .init           = set_target_init_v3,
+               .parse          = set_target_parse_v3,
+               .final_check    = set_target_check_v3,
+               .print          = set_target_print_v3,
+               .save           = set_target_save_v3,
+               .extra_opts     = set_target_opts_v3,
+       },
 };
 
 void _init(void)
index c35ba93d1704c0f412cce225c830250c58c74de4..78a9ae0fdc5113f99b2a1712d1f9407a3cbb948d 100644 (file)
@@ -6,6 +6,10 @@ add the address(es)/port(s) of the packet to the set
 .TP
 \fB\-\-del\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
 delete the address(es)/port(s) of the packet from the set
+.TP
+\fB\-\-map\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...] 
+[\-\-map\-mark] [\-\-map\-prio] [\-\-map\-queue]
+map packet properties (firewall mark, tc priority, hardware queue)
 .IP
 where \fIflag\fP(s) are
 .BR "src"
@@ -20,6 +24,23 @@ one from the set definition
 \fB\-\-exist\fP
 when adding an entry if it already exists, reset the timeout value
 to the specified one or to the default from the set definition
+.TP
+\fB\-\-map\-set\fP \fIset\-name\fP
+the set-name should be created with --skbinfo option
+\fB\-\-map\-mark\fP
+map firewall mark to packet by lookup of value in the set
+\fB\-\-map\-prio\fP
+map traffic control priority to packet by lookup of value in the set
+\fB\-\-map\-queue\fP
+map hardware NIC queue to packet by lookup of value in the set
+.IP
+The
+\fB\-\-map\-set\fP
+option can be used from the mangle table only. The
+\fB\-\-map\-prio\fP
+and
+\fB\-\-map\-queue\fP
+flags can be used in the OUTPUT, FORWARD and POSTROUTING chains.
 .PP
 Use of -j SET requires that ipset kernel support is provided, which, for
 standard kernels, is the case since Linux 2.6.39.
index 0dcf5ddfdf91784e666b692d79e691633d03fb1d..7f1d604109a35d5036221a02db6da92af0e91fab 100644 (file)
@@ -110,6 +110,9 @@ enum {
        IPSET_ATTR_IFACE,
        IPSET_ATTR_BYTES,
        IPSET_ATTR_PACKETS,
+       IPSET_ATTR_SKBMARK,
+       IPSET_ATTR_SKBPRIO,
+       IPSET_ATTR_SKBQUEUE,
        __IPSET_ATTR_ADT_MAX,
 };
 #define IPSET_ATTR_ADT_MAX     (__IPSET_ATTR_ADT_MAX - 1)
@@ -140,6 +143,7 @@ enum ipset_errno {
        IPSET_ERR_IPADDR_IPV4,
        IPSET_ERR_IPADDR_IPV6,
        IPSET_ERR_COUNTER,
+       IPSET_ERR_SKBINFO,
 
        /* Type specific error codes */
        IPSET_ERR_TYPE_SPECIFIC = 4352,
@@ -163,6 +167,12 @@ enum ipset_cmd_flags {
        IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS),
        IPSET_FLAG_BIT_RETURN_NOMATCH = 7,
        IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH),
+       IPSET_FLAG_BIT_MAP_SKBMARK = 8,
+       IPSET_FLAG_MAP_SKBMARK = (1 << IPSET_FLAG_BIT_MAP_SKBMARK),
+       IPSET_FLAG_BIT_MAP_SKBPRIO = 9,
+       IPSET_FLAG_MAP_SKBPRIO = (1 << IPSET_FLAG_BIT_MAP_SKBPRIO),
+       IPSET_FLAG_BIT_MAP_SKBQUEUE = 10,
+       IPSET_FLAG_MAP_SKBQUEUE = (1 << IPSET_FLAG_BIT_MAP_SKBQUEUE),
        IPSET_FLAG_CMD_MAX = 15,
 };
 
index 964d3d42f8749d7e697aee47c42e3e31b67c5e48..d6a1df1f2947ba6aa0cc8680a2efb8f61a0ae178 100644 (file)
@@ -71,4 +71,14 @@ struct xt_set_info_match_v3 {
        __u32 flags;
 };
 
+/* Revision 3 target */
+
+struct xt_set_info_target_v3 {
+       struct xt_set_info add_set;
+       struct xt_set_info del_set;
+       struct xt_set_info map_set;
+       __u32 flags;
+       __u32 timeout;
+};
+
 #endif /*_XT_SET_H*/