summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-03-08 13:57:24 +0100
committerPatrick McHardy <kaber@trash.net>2010-03-08 13:57:24 +0100
commit9fdbaa71452edaac9d5906716c15937f670341fa (patch)
tree521112d85dbded7df6cad7a66205551d9be5be6a
parentcf7e42ffbb624c27591f6d55606bdccd358c7785 (diff)
extensions: add CT extension
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--extensions/libxt_CT.c188
-rw-r--r--include/linux/netfilter/nf_conntrack_common.h21
-rw-r--r--include/linux/netfilter/xt_CT.h17
3 files changed, 226 insertions, 0 deletions
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
new file mode 100644
index 00000000..79fa8d04
--- /dev/null
+++ b/extensions/libxt_CT.c
@@ -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);
+}
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 978cecd6..34a7fc65 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -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
index 00000000..1b564106
--- /dev/null
+++ b/include/linux/netfilter/xt_CT.h
@@ -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 */