Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables for ECN matching
      2  *
      3  * (C) 2002 by Harald Welte <laforge (at) netfilter.org>
      4  * (C) 2011 by Patrick McHardy <kaber (at) trash.net>
      5  *
      6  * This program is distributed under the terms of GNU GPL v2, 1991
      7  *
      8  * libipt_ecn.c borrowed heavily from libipt_dscp.c
      9  *
     10  */
     11 #include <stdio.h>
     12 #include <xtables.h>
     13 #include <linux/netfilter/xt_ecn.h>
     14 
     15 enum {
     16 	O_ECN_TCP_CWR = 0,
     17 	O_ECN_TCP_ECE,
     18 	O_ECN_IP_ECT,
     19 };
     20 
     21 static void ecn_help(void)
     22 {
     23 	printf(
     24 "ECN match options\n"
     25 "[!] --ecn-tcp-cwr 		Match CWR bit of TCP header\n"
     26 "[!] --ecn-tcp-ece		Match ECE bit of TCP header\n"
     27 "[!] --ecn-ip-ect [0..3]	Match ECN codepoint in IPv4/IPv6 header\n");
     28 }
     29 
     30 static const struct xt_option_entry ecn_opts[] = {
     31 	{.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_NONE,
     32 	 .flags = XTOPT_INVERT},
     33 	{.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_NONE,
     34 	 .flags = XTOPT_INVERT},
     35 	{.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8,
     36 	 .min = 0, .max = 3, .flags = XTOPT_INVERT},
     37 	XTOPT_TABLEEND,
     38 };
     39 
     40 static void ecn_parse(struct xt_option_call *cb)
     41 {
     42 	struct xt_ecn_info *einfo = cb->data;
     43 
     44 	xtables_option_parse(cb);
     45 	switch (cb->entry->id) {
     46 	case O_ECN_TCP_CWR:
     47 		einfo->operation |= XT_ECN_OP_MATCH_CWR;
     48 		if (cb->invert)
     49 			einfo->invert |= XT_ECN_OP_MATCH_CWR;
     50 		break;
     51 	case O_ECN_TCP_ECE:
     52 		einfo->operation |= XT_ECN_OP_MATCH_ECE;
     53 		if (cb->invert)
     54 			einfo->invert |= XT_ECN_OP_MATCH_ECE;
     55 		break;
     56 	case O_ECN_IP_ECT:
     57 		if (cb->invert)
     58 			einfo->invert |= XT_ECN_OP_MATCH_IP;
     59 		einfo->operation |= XT_ECN_OP_MATCH_IP;
     60 		einfo->ip_ect = cb->val.u8;
     61 		break;
     62 	}
     63 }
     64 
     65 static void ecn_check(struct xt_fcheck_call *cb)
     66 {
     67 	if (cb->xflags == 0)
     68 		xtables_error(PARAMETER_PROBLEM,
     69 		           "ECN match: some option required");
     70 }
     71 
     72 static void ecn_print(const void *ip, const struct xt_entry_match *match,
     73                       int numeric)
     74 {
     75 	const struct xt_ecn_info *einfo =
     76 		(const struct xt_ecn_info *)match->data;
     77 
     78 	printf(" ECN match");
     79 
     80 	if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
     81 		printf(" %sECE",
     82 		       (einfo->invert & XT_ECN_OP_MATCH_ECE) ? "!" : "");
     83 	}
     84 
     85 	if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
     86 		printf(" %sCWR",
     87 		       (einfo->invert & XT_ECN_OP_MATCH_CWR) ? "!" : "");
     88 	}
     89 
     90 	if (einfo->operation & XT_ECN_OP_MATCH_IP) {
     91 		printf(" %sECT=%d",
     92 		       (einfo->invert & XT_ECN_OP_MATCH_IP) ? "!" : "",
     93 		       einfo->ip_ect);
     94 	}
     95 }
     96 
     97 static void ecn_save(const void *ip, const struct xt_entry_match *match)
     98 {
     99 	const struct xt_ecn_info *einfo =
    100 		(const struct xt_ecn_info *)match->data;
    101 
    102 	if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
    103 		if (einfo->invert & XT_ECN_OP_MATCH_ECE)
    104 			printf(" !");
    105 		printf(" --ecn-tcp-ece");
    106 	}
    107 
    108 	if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
    109 		if (einfo->invert & XT_ECN_OP_MATCH_CWR)
    110 			printf(" !");
    111 		printf(" --ecn-tcp-cwr");
    112 	}
    113 
    114 	if (einfo->operation & XT_ECN_OP_MATCH_IP) {
    115 		if (einfo->invert & XT_ECN_OP_MATCH_IP)
    116 			printf(" !");
    117 		printf(" --ecn-ip-ect %d", einfo->ip_ect);
    118 	}
    119 }
    120 
    121 static int ecn_xlate(struct xt_xlate *xl,
    122 		     const struct xt_xlate_mt_params *params)
    123 {
    124 	const struct xt_ecn_info *einfo =
    125 		(const struct xt_ecn_info *)params->match->data;
    126 
    127 	if (!(einfo->operation & XT_ECN_OP_MATCH_IP))
    128 		return 0;
    129 
    130 	xt_xlate_add(xl, "ip ecn ");
    131 	if (einfo->invert)
    132 		xt_xlate_add(xl,"!= ");
    133 
    134 	switch (einfo->ip_ect) {
    135 	case 0:
    136 		xt_xlate_add(xl, "not-ect");
    137 		break;
    138 	case 1:
    139 		xt_xlate_add(xl, "ect1");
    140 		break;
    141 	case 2:
    142 		xt_xlate_add(xl, "ect0");
    143 		break;
    144 	case 3:
    145 		xt_xlate_add(xl, "ce");
    146 		break;
    147 	}
    148 	return 1;
    149 }
    150 
    151 static struct xtables_match ecn_mt_reg = {
    152 	.name          = "ecn",
    153 	.version       = XTABLES_VERSION,
    154 	.family        = NFPROTO_UNSPEC,
    155 	.size          = XT_ALIGN(sizeof(struct xt_ecn_info)),
    156 	.userspacesize = XT_ALIGN(sizeof(struct xt_ecn_info)),
    157 	.help          = ecn_help,
    158 	.print         = ecn_print,
    159 	.save          = ecn_save,
    160 	.x6_parse      = ecn_parse,
    161 	.x6_fcheck     = ecn_check,
    162 	.x6_options    = ecn_opts,
    163 	.xlate	       = ecn_xlate,
    164 };
    165 
    166 void _init(void)
    167 {
    168 	xtables_register_match(&ecn_mt_reg);
    169 }
    170