]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
extensions: add CT extension
authorPatrick McHardy <kaber@trash.net>
Mon, 8 Mar 2010 12:57:24 +0000 (13:57 +0100)
committerPatrick McHardy <kaber@trash.net>
Mon, 8 Mar 2010 12:57:24 +0000 (13:57 +0100)
Signed-off-by: Patrick McHardy <kaber@trash.net>
extensions/libxt_CT.c [new file with mode: 0644]
include/linux/netfilter/nf_conntrack_common.h
include/linux/netfilter/xt_CT.h [new file with mode: 0644]

diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
new file mode 100644 (file)
index 0000000..79fa8d0
--- /dev/null
@@ -0,0 +1,188 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <getopt.h>
+#include <xtables.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/xt_CT.h>
+
+static void ct_help(void)
+{
+       printf(
+"CT target options:\n"
+" --notrack                    Don't track connection\n"
+" --helper name                        Use conntrack helper 'name' for connection\n"
+" --ctevents event[,event...]  Generate specified conntrack vents for connection\n"
+" --expevents event[,event...] Generate specified expectation events for connection\n"
+" --zone ID                    Assign/Lookup connection in zone ID\n"
+       );
+}
+
+enum ct_options {
+       CT_OPT_NOTRACK          = 0x1,
+       CT_OPT_HELPER           = 0x2,
+       CT_OPT_CTEVENTS         = 0x4,
+       CT_OPT_EXPEVENTS        = 0x8,
+       CT_OPT_ZONE             = 0x10,
+};
+
+static const struct option ct_opts[] = {
+       { "notrack",    0, NULL, CT_OPT_NOTRACK },
+       { "helper",     1, NULL, CT_OPT_HELPER },
+       { "ctevents",   1, NULL, CT_OPT_CTEVENTS },
+       { "expevents",  1, NULL, CT_OPT_EXPEVENTS },
+       { "zone",       1, NULL, CT_OPT_ZONE },
+       { .name = NULL },
+};
+
+struct event_tbl {
+       const char      *name;
+       unsigned int    event;
+};
+
+static const struct event_tbl ct_event_tbl[] = {
+       { "new",                IPCT_NEW },
+       { "related",            IPCT_RELATED },
+       { "destroy",            IPCT_DESTROY },
+       { "reply",              IPCT_REPLY },
+       { "assured",            IPCT_ASSURED },
+       { "protoinfo",          IPCT_PROTOINFO },
+       { "helper",             IPCT_HELPER },
+       { "mark",               IPCT_MARK },
+       { "natseqinfo",         IPCT_NATSEQADJ },
+       { "secmark",            IPCT_SECMARK },
+};
+
+static const struct event_tbl exp_event_tbl[] = {
+       { "new",                IPEXP_NEW },
+};
+
+static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
+                               const char *events)
+{
+       char str[strlen(events) + 1], *e = str, *t;
+       unsigned int mask = 0, i;
+
+       strcpy(str, events);
+       while ((t = strsep(&e, ","))) {
+               for (i = 0; i < size; i++) {
+                       if (strcmp(t, tbl->name))
+                               continue;
+                       mask |= 1 << tbl->event;
+                       break;
+               }
+
+               if (i == size)
+                       xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t);
+       }
+
+       return mask;
+}
+
+static void ct_print_events(const char *pfx, const struct event_tbl *tbl,
+                           unsigned int size, uint32_t mask)
+{
+       const char *sep = "";
+       unsigned int i;
+
+       printf("%s ", pfx);
+       for (i = 0; i < size; i++) {
+               if (mask & (1 << tbl[i].event)) {
+                       printf("%s%s", sep, tbl[i].name);
+                       sep = ",";
+               }
+       }
+       printf(" ");
+}
+
+static int ct_parse(int c, char **argv, int invert, unsigned int *flags,
+                   const void *entry, struct xt_entry_target **target)
+{
+       struct xt_ct_target_info *info = (struct xt_ct_target_info *)(*target)->data;
+       unsigned int zone;
+
+       switch (c) {
+       case CT_OPT_NOTRACK:
+               xtables_param_act(XTF_ONLY_ONCE, "CT", "--notrack", *flags & CT_OPT_NOTRACK);
+               info->flags |= XT_CT_NOTRACK;
+               break;
+       case CT_OPT_HELPER:
+               xtables_param_act(XTF_ONLY_ONCE, "CT", "--helper", *flags & CT_OPT_HELPER);
+               strncpy(info->helper, optarg, sizeof(info->helper));
+               info->helper[sizeof(info->helper) - 1] = '\0';
+               break;
+       case CT_OPT_CTEVENTS:
+               xtables_param_act(XTF_ONLY_ONCE, "CT", "--ctevents", *flags & CT_OPT_CTEVENTS);
+               info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), optarg);
+               break;
+       case CT_OPT_EXPEVENTS:
+               xtables_param_act(XTF_ONLY_ONCE, "CT", "--expevents", *flags & CT_OPT_EXPEVENTS);
+               info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), optarg);
+               break;
+       case CT_OPT_ZONE:
+               xtables_param_act(XTF_ONLY_ONCE, "CT", "--zone", *flags & CT_OPT_ZONE);
+               if (!xtables_strtoui(optarg, NULL, &zone, 0, UINT16_MAX))
+                       xtables_error(PARAMETER_PROBLEM, "Bad zone value \"%s\"", optarg);
+               info->zone = zone;
+               break;
+       default:
+               return 0;
+       }
+
+       *flags |= c;
+       return 1;
+}
+
+static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
+{
+       const struct xt_ct_target_info *info =
+               (const struct xt_ct_target_info *)target->data;
+
+       printf("CT ");
+       if (info->flags & XT_CT_NOTRACK)
+               printf("notrack ");
+       if (info->helper[0])
+               printf("helper %s ", info->helper);
+       if (info->ct_events)
+               ct_print_events("ctevents", ct_event_tbl,
+                               ARRAY_SIZE(ct_event_tbl), info->ct_events);
+       if (info->exp_events)
+               ct_print_events("expevents", exp_event_tbl,
+                               ARRAY_SIZE(exp_event_tbl), info->exp_events);
+}
+
+static void ct_save(const void *ip, const struct xt_entry_target *target)
+{
+       const struct xt_ct_target_info *info =
+               (const struct xt_ct_target_info *)target->data;
+
+       if (info->flags & XT_CT_NOTRACK)
+               printf("--notrack ");
+       if (info->helper[0])
+               printf("--helper %s ", info->helper);
+       if (info->ct_events)
+               ct_print_events("--ctevents", ct_event_tbl,
+                               ARRAY_SIZE(ct_event_tbl), info->ct_events);
+       if (info->exp_events)
+               ct_print_events("--expevents", exp_event_tbl,
+                               ARRAY_SIZE(exp_event_tbl), info->exp_events);
+}
+
+static struct xtables_target ct_target = {
+       .family         = NFPROTO_UNSPEC,
+       .name           = "CT",
+       .version        = XTABLES_VERSION,
+       .size           = XT_ALIGN(sizeof(struct xt_ct_target_info)),
+       .userspacesize  = offsetof(struct xt_ct_target_info, ct),
+       .help           = ct_help,
+       .parse          = ct_parse,
+       .print          = ct_print,
+       .save           = ct_save,
+       .extra_opts     = ct_opts,
+};
+
+void _init(void)
+{
+       xtables_register_target(&ct_target);
+}
index 978cecd6732333f6a267ba2bf8a26c3412f21dce..34a7fc6596ef7ca6dbf385c6ebd9448e7fa8fe19 100644 (file)
@@ -72,7 +72,28 @@ enum ip_conntrack_status {
        /* Connection has fixed timeout. */
        IPS_FIXED_TIMEOUT_BIT = 10,
        IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
+
+       /* Conntrack is a template */
+       IPS_TEMPLATE_BIT = 11,
+       IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
+};
+
+/* Connection tracking event types */
+enum ip_conntrack_events {
+       IPCT_NEW,               /* new conntrack */
+       IPCT_RELATED,           /* related conntrack */
+       IPCT_DESTROY,           /* destroyed conntrack */
+       IPCT_REPLY,             /* connection has seen two-way traffic */
+       IPCT_ASSURED,           /* connection status has changed to assured */
+       IPCT_PROTOINFO,         /* protocol information has changed */
+       IPCT_HELPER,            /* new helper has been set */
+       IPCT_MARK,              /* new mark has been set */
+       IPCT_NATSEQADJ,         /* NAT is doing sequence adjustment */
+       IPCT_SECMARK,           /* new security mark has been set */
 };
 
+enum ip_conntrack_expect_events {
+       IPEXP_NEW,              /* new expectation */
+};
 
 #endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h
new file mode 100644 (file)
index 0000000..1b56410
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _XT_CT_H
+#define _XT_CT_H
+
+#define XT_CT_NOTRACK  0x1
+
+struct xt_ct_target_info {
+       u_int16_t       flags;
+       u_int16_t       zone;
+       u_int32_t       ct_events;
+       u_int32_t       exp_events;
+       char            helper[16];
+
+       /* Used internally by the kernel */
+       struct nf_conn  *ct __attribute__((aligned(8)));
+};
+
+#endif /* _XT_CT_H */