1 /* Shared library add-on to iptables for ECN matching
2  *
3  * (C) 2002 by Harald Welte <laforge@netfilter.org>
4  * (C) 2011 by Patrick McHardy <kaber@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 
ecn_help(void)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 
ecn_parse(struct xt_option_call * cb)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 
ecn_check(struct xt_fcheck_call * cb)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 
ecn_print(const void * ip,const struct xt_entry_match * match,int numeric)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 
ecn_save(const void * ip,const struct xt_entry_match * match)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 
ecn_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)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 
_init(void)166 void _init(void)
167 {
168 	xtables_register_match(&ecn_mt_reg);
169 }
170