From 9fdbaa71452edaac9d5906716c15937f670341fa Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 8 Mar 2010 13:57:24 +0100 Subject: extensions: add CT extension Signed-off-by: Patrick McHardy --- extensions/libxt_CT.c | 188 ++++++++++++++++++++++++++ include/linux/netfilter/nf_conntrack_common.h | 21 +++ include/linux/netfilter/xt_CT.h | 17 +++ 3 files changed, 226 insertions(+) create mode 100644 extensions/libxt_CT.c create mode 100644 include/linux/netfilter/xt_CT.h 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 +#include +#include +#include +#include +#include +#include +#include + +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 */ -- cgit v1.2.3