1385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Shared library add-on to iptables for ECN, $Version$
2385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte *
3385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * (C) 2002 by Harald Welte <laforge@gnumonks.org>
4385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte *
5385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * This program is distributed under the terms of GNU GPL v2, 1991
6385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte *
7385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte * libipt_ECN.c borrowed heavily from libipt_DSCP.c
8385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte */
9385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <stdio.h>
105d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h>
11385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <linux/netfilter_ipv4/ipt_ECN.h>
12385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
13e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtenum {
14e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_TCP_REMOVE = 0,
15e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_TCP_CWR,
16e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_TCP_ECE,
17e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	O_ECN_IP_ECT,
18e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	F_ECN_TCP_REMOVE = 1 << O_ECN_TCP_REMOVE,
19e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	F_ECN_TCP_CWR    = 1 << O_ECN_TCP_CWR,
20e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	F_ECN_TCP_ECE    = 1 << O_ECN_TCP_ECE,
21e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt};
22e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt
231d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_help(void)
24385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
25385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	printf(
268b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"ECN target options\n"
278b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n");
2831d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte}
2931d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte
3031d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#if 0
311c8fa733e6092029d97bc5b2b6a4cb13b513f2f0Harald Welte"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
32c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
33c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
3492cad5f4a349daac294332b8f8f696b43c55d3fcHarald Welte"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
3531d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#endif
3631d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte
37e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtstatic const struct xt_option_entry ECN_opts[] = {
38e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-tcp-remove", .id = O_ECN_TCP_REMOVE, .type = XTTYPE_NONE,
39e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .excl = F_ECN_TCP_CWR | F_ECN_TCP_ECE},
40e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_UINT8,
41e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE},
42e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_UINT8,
43e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE},
44e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	{.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8,
45e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	 .min = 0, .max = 3},
46e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	XTOPT_TABLEEND,
47385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
48385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
49e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtstatic void ECN_parse(struct xt_option_call *cb)
50385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
51e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	struct ipt_ECN_info *einfo = cb->data;
52e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt
53e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	xtables_option_parse(cb);
54e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	switch (cb->entry->id) {
55e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_TCP_REMOVE:
56c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
57c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.ece = 0;
58c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.cwr = 0;
59385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		break;
60e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_TCP_CWR:
61c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_CWR;
62e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		einfo->proto.tcp.cwr = cb->val.u8;
63c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		break;
64e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_TCP_ECE:
65c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_ECE;
66e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		einfo->proto.tcp.ece = cb->val.u8;
67c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		break;
68e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	case O_ECN_IP_ECT:
69c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_IP;
70e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt		einfo->ip_ect = cb->val.u8;
71c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte		break;
72385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
73385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
74385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
75e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardtstatic void ECN_check(struct xt_fcheck_call *cb)
76385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
77e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	if (cb->xflags == 0)
781829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
794e5d4bff933d77158d9d32b4f87c5842decf670eJan Engelhardt		           "ECN target: An operation is required");
80385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
81385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
821d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_print(const void *ip, const struct xt_entry_target *target,
831d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt                      int numeric)
84385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
85385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
86385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
87385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
8873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" ECN");
89385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
907b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
917b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
927b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
9373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" TCP remove");
947b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
957b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
9673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" ECE=%u", einfo->proto.tcp.ece);
977b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
987b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
9973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" CWR=%u", einfo->proto.tcp.cwr);
1007b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1017b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
10273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" ECT codepoint=%u", einfo->ip_ect);
103385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
104385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
105385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1061d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_save(const void *ip, const struct xt_entry_target *target)
107385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
108385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
109385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
110385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1117b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1127b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1137b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
11473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" --ecn-tcp-remove");
1157b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
116c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1177b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
11873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --ecn-tcp-ece %d", einfo->proto.tcp.ece);
1197b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1207b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
12173866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --ecn-tcp-cwr %d", einfo->proto.tcp.cwr);
122c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1237b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
12473866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --ecn-ip-ect %d", einfo->ip_ect);
125385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
126385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
127385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1288b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target ecn_tg_reg = {
1298caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira	.name		= "ECN",
1308b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.version	= XTABLES_VERSION,
13103d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt	.family		= NFPROTO_IPV4,
1328b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.size		= XT_ALIGN(sizeof(struct ipt_ECN_info)),
1338b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ECN_info)),
1341d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.help		= ECN_help,
1351d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.print		= ECN_print,
1361d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.save		= ECN_save,
137e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	.x6_parse	= ECN_parse,
138e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	.x6_fcheck	= ECN_check,
139e36463232e2f1fe9363700b2740c2a82dbf1821dJan Engelhardt	.x6_options	= ECN_opts,
140385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
141385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
142385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltevoid _init(void)
143385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
1448b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	xtables_register_target(&ecn_tg_reg);
145385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
146