/* Shared library add-on to iptables for ECN matching * * (C) 2002 by Harald Welte <laforge@netfilter.org> * (C) 2011 by Patrick McHardy <kaber@trash.net> * * This program is distributed under the terms of GNU GPL v2, 1991 * * libipt_ecn.c borrowed heavily from libipt_dscp.c * */ #include <stdio.h> #include <xtables.h> #include <linux/netfilter/xt_ecn.h> enum { O_ECN_TCP_CWR = 0, O_ECN_TCP_ECE, O_ECN_IP_ECT, }; static void ecn_help(void) { printf( "ECN match options\n" "[!] --ecn-tcp-cwr Match CWR bit of TCP header\n" "[!] --ecn-tcp-ece Match ECE bit of TCP header\n" "[!] --ecn-ip-ect [0..3] Match ECN codepoint in IPv4/IPv6 header\n"); } static const struct xt_option_entry ecn_opts[] = { {.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_NONE, .flags = XTOPT_INVERT}, {.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_NONE, .flags = XTOPT_INVERT}, {.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8, .min = 0, .max = 3, .flags = XTOPT_INVERT}, XTOPT_TABLEEND, }; static void ecn_parse(struct xt_option_call *cb) { struct xt_ecn_info *einfo = cb->data; xtables_option_parse(cb); switch (cb->entry->id) { case O_ECN_TCP_CWR: einfo->operation |= XT_ECN_OP_MATCH_CWR; if (cb->invert) einfo->invert |= XT_ECN_OP_MATCH_CWR; break; case O_ECN_TCP_ECE: einfo->operation |= XT_ECN_OP_MATCH_ECE; if (cb->invert) einfo->invert |= XT_ECN_OP_MATCH_ECE; break; case O_ECN_IP_ECT: if (cb->invert) einfo->invert |= XT_ECN_OP_MATCH_IP; einfo->operation |= XT_ECN_OP_MATCH_IP; einfo->ip_ect = cb->val.u8; break; } } static void ecn_check(struct xt_fcheck_call *cb) { if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "ECN match: some option required"); } static void ecn_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_ecn_info *einfo = (const struct xt_ecn_info *)match->data; printf(" ECN match"); if (einfo->operation & XT_ECN_OP_MATCH_ECE) { printf(" %sECE", (einfo->invert & XT_ECN_OP_MATCH_ECE) ? "!" : ""); } if (einfo->operation & XT_ECN_OP_MATCH_CWR) { printf(" %sCWR", (einfo->invert & XT_ECN_OP_MATCH_CWR) ? "!" : ""); } if (einfo->operation & XT_ECN_OP_MATCH_IP) { printf(" %sECT=%d", (einfo->invert & XT_ECN_OP_MATCH_IP) ? "!" : "", einfo->ip_ect); } } static void ecn_save(const void *ip, const struct xt_entry_match *match) { const struct xt_ecn_info *einfo = (const struct xt_ecn_info *)match->data; if (einfo->operation & XT_ECN_OP_MATCH_ECE) { if (einfo->invert & XT_ECN_OP_MATCH_ECE) printf(" !"); printf(" --ecn-tcp-ece"); } if (einfo->operation & XT_ECN_OP_MATCH_CWR) { if (einfo->invert & XT_ECN_OP_MATCH_CWR) printf(" !"); printf(" --ecn-tcp-cwr"); } if (einfo->operation & XT_ECN_OP_MATCH_IP) { if (einfo->invert & XT_ECN_OP_MATCH_IP) printf(" !"); printf(" --ecn-ip-ect %d", einfo->ip_ect); } } static struct xtables_match ecn_mt_reg = { .name = "ecn", .version = XTABLES_VERSION, .family = NFPROTO_UNSPEC, .size = XT_ALIGN(sizeof(struct xt_ecn_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_ecn_info)), .help = ecn_help, .print = ecn_print, .save = ecn_save, .x6_parse = ecn_parse, .x6_fcheck = ecn_check, .x6_options = ecn_opts, }; void _init(void) { xtables_register_match(&ecn_mt_reg); }