17a44731615d950a2966737d1d1c960859023f3a3Harald Welte/* Shared library add-on to iptables for ECN matching
27a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
398e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy * (C) 2002 by Harald Welte <laforge@netfilter.org>
498e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy * (C) 2011 by Patrick McHardy <kaber@trash.net>
57a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
67a44731615d950a2966737d1d1c960859023f3a3Harald Welte * This program is distributed under the terms of GNU GPL v2, 1991
77a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
87a44731615d950a2966737d1d1c960859023f3a3Harald Welte * libipt_ecn.c borrowed heavily from libipt_dscp.c
97a44731615d950a2966737d1d1c960859023f3a3Harald Welte *
107a44731615d950a2966737d1d1c960859023f3a3Harald Welte */
117a44731615d950a2966737d1d1c960859023f3a3Harald Welte#include <stdio.h>
125d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h>
1398e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy#include <linux/netfilter/xt_ecn.h>
147a44731615d950a2966737d1d1c960859023f3a3Harald Welte
15e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtenum {
16e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_TCP_CWR = 0,
17e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_TCP_ECE,
18e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_IP_ECT,
19e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt};
20e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt
2159d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_help(void)
227a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
237a44731615d950a2966737d1d1c960859023f3a3Harald Welte	printf(
248b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"ECN match options\n"
257a44731615d950a2966737d1d1c960859023f3a3Harald Welte"[!] --ecn-tcp-cwr 		Match CWR bit of TCP header\n"
267a44731615d950a2966737d1d1c960859023f3a3Harald Welte"[!] --ecn-tcp-ece		Match ECE bit of TCP header\n"
2798e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy"[!] --ecn-ip-ect [0..3]	Match ECN codepoint in IPv4/IPv6 header\n");
287a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
297a44731615d950a2966737d1d1c960859023f3a3Harald Welte
30e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtstatic const struct xt_option_entry ecn_opts[] = {
31e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_NONE,
32e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .flags = XTOPT_INVERT},
33e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_NONE,
34e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .flags = XTOPT_INVERT},
35e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8,
36e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .min = 0, .max = 3, .flags = XTOPT_INVERT},
37e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	XTOPT_TABLEEND,
387a44731615d950a2966737d1d1c960859023f3a3Harald Welte};
397a44731615d950a2966737d1d1c960859023f3a3Harald Welte
40e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtstatic void ecn_parse(struct xt_option_call *cb)
417a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
4298e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	struct xt_ecn_info *einfo = cb->data;
43e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt
44e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	xtables_option_parse(cb);
45e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	switch (cb->entry->id) {
46e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_TCP_CWR:
4798e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		einfo->operation |= XT_ECN_OP_MATCH_CWR;
48e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		if (cb->invert)
4998e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy			einfo->invert |= XT_ECN_OP_MATCH_CWR;
507a44731615d950a2966737d1d1c960859023f3a3Harald Welte		break;
51e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_TCP_ECE:
5298e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		einfo->operation |= XT_ECN_OP_MATCH_ECE;
53e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		if (cb->invert)
5498e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy			einfo->invert |= XT_ECN_OP_MATCH_ECE;
557a44731615d950a2966737d1d1c960859023f3a3Harald Welte		break;
56e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_IP_ECT:
57e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		if (cb->invert)
5898e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy			einfo->invert |= XT_ECN_OP_MATCH_IP;
5998e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		einfo->operation |= XT_ECN_OP_MATCH_IP;
60e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		einfo->ip_ect = cb->val.u8;
617a44731615d950a2966737d1d1c960859023f3a3Harald Welte		break;
627a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
637a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
647a44731615d950a2966737d1d1c960859023f3a3Harald Welte
65e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtstatic void ecn_check(struct xt_fcheck_call *cb)
667a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
67e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	if (cb->xflags == 0)
681829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
697a44731615d950a2966737d1d1c960859023f3a3Harald Welte		           "ECN match: some option required");
707a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
717a44731615d950a2966737d1d1c960859023f3a3Harald Welte
7259d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_print(const void *ip, const struct xt_entry_match *match,
7359d164019340d110d302634e429320577f0db7beJan Engelhardt                      int numeric)
747a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
7598e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	const struct xt_ecn_info *einfo =
7698e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		(const struct xt_ecn_info *)match->data;
777a44731615d950a2966737d1d1c960859023f3a3Harald Welte
7873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" ECN match");
797a44731615d950a2966737d1d1c960859023f3a3Harald Welte
8098e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
8173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" %sECE",
8298e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		       (einfo->invert & XT_ECN_OP_MATCH_ECE) ? "!" : "");
837a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
847a44731615d950a2966737d1d1c960859023f3a3Harald Welte
8598e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
8673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" %sCWR",
8798e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		       (einfo->invert & XT_ECN_OP_MATCH_CWR) ? "!" : "");
887a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
897a44731615d950a2966737d1d1c960859023f3a3Harald Welte
9098e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	if (einfo->operation & XT_ECN_OP_MATCH_IP) {
9173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" %sECT=%d",
9298e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		       (einfo->invert & XT_ECN_OP_MATCH_IP) ? "!" : "",
9373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		       einfo->ip_ect);
947a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
957a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
967a44731615d950a2966737d1d1c960859023f3a3Harald Welte
9759d164019340d110d302634e429320577f0db7beJan Engelhardtstatic void ecn_save(const void *ip, const struct xt_entry_match *match)
987a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
9998e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	const struct xt_ecn_info *einfo =
10098e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		(const struct xt_ecn_info *)match->data;
10198e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy
10298e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
10398e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		if (einfo->invert & XT_ECN_OP_MATCH_ECE)
10473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" !");
10573866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --ecn-tcp-ece");
1067a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1077a44731615d950a2966737d1d1c960859023f3a3Harald Welte
10898e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
10998e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		if (einfo->invert & XT_ECN_OP_MATCH_CWR)
11073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" !");
11173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --ecn-tcp-cwr");
1127a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1137a44731615d950a2966737d1d1c960859023f3a3Harald Welte
11498e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	if (einfo->operation & XT_ECN_OP_MATCH_IP) {
11598e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy		if (einfo->invert & XT_ECN_OP_MATCH_IP)
11673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" !");
11773866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --ecn-ip-ect %d", einfo->ip_ect);
1187a44731615d950a2966737d1d1c960859023f3a3Harald Welte	}
1197a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
1207a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1218b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_match ecn_mt_reg = {
122e1df221d7a1b3df0224d94865ec05ba336995608Jan Engelhardt	.name          = "ecn",
123e1df221d7a1b3df0224d94865ec05ba336995608Jan Engelhardt	.version       = XTABLES_VERSION,
12498e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	.family        = NFPROTO_UNSPEC,
12598e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	.size          = XT_ALIGN(sizeof(struct xt_ecn_info)),
12698e1769b65b71989e3f16b25529b40f374aef323Patrick McHardy	.userspacesize = XT_ALIGN(sizeof(struct xt_ecn_info)),
127e1df221d7a1b3df0224d94865ec05ba336995608Jan Engelhardt	.help          = ecn_help,
128e1df221d7a1b3df0224d94865ec05ba336995608Jan Engelhardt	.print         = ecn_print,
129e1df221d7a1b3df0224d94865ec05ba336995608Jan Engelhardt	.save          = ecn_save,
130e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	.x6_parse      = ecn_parse,
131e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	.x6_fcheck     = ecn_check,
132e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	.x6_options    = ecn_opts,
1337a44731615d950a2966737d1d1c960859023f3a3Harald Welte};
1347a44731615d950a2966737d1d1c960859023f3a3Harald Welte
1357a44731615d950a2966737d1d1c960859023f3a3Harald Weltevoid _init(void)
1367a44731615d950a2966737d1d1c960859023f3a3Harald Welte{
1378b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	xtables_register_match(&ecn_mt_reg);
1387a44731615d950a2966737d1d1c960859023f3a3Harald Welte}
139