summaryrefslogtreecommitdiff
path: root/extensions/libxt_CT.c
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/libxt_CT.c')
-rw-r--r--extensions/libxt_CT.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c
new file mode 100644
index 0000000..6be6ea0
--- /dev/null
+++ b/extensions/libxt_CT.c
@@ -0,0 +1,192 @@
+#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 events 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[i].name))
+ continue;
+ mask |= 1 << tbl[i].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);
+ if (info->zone)
+ printf("zone %u ", info->zone);
+}
+
+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);
+ if (info->zone)
+ printf("--zone %u ", info->zone);
+}
+
+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);
+}