libipt_ECN.c revision 1829ed482efbc8b390cc760d012b3a4450494e1a
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 *
98caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira * $Id$
10385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte */
11385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <stdio.h>
12385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <string.h>
13385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <stdlib.h>
14385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <getopt.h>
15385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
165d9678ad3eabc34ac40dfe055d7f6a8e44445a5aJan Engelhardt#include <xtables.h>
17385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <linux/netfilter_ipv4/ip_tables.h>
18385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <linux/netfilter_ipv4/ipt_ECN.h>
19385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
201d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_help(void)
21385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
22385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	printf(
238b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"ECN target options\n"
248b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n");
2531d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte}
2631d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte
2731d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#if 0
281c8fa733e6092029d97bc5b2b6a4cb13b513f2f0Harald Welte"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
29c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
30c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
3192cad5f4a349daac294332b8f8f696b43c55d3fcHarald Welte"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
3231d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#endif
3331d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte
34385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
351d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic const struct option ECN_opts[] = {
36500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "ecn-tcp-remove", 0, NULL, 'F' },
37500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "ecn-tcp-cwr", 1, NULL, 'G' },
38500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "ecn-tcp-ece", 1, NULL, 'H' },
39500f483fff529dcd88ec96b9d5054be6cd6363a0Patrick McHardy	{ "ecn-ip-ect", 1, NULL, '9' },
409ee386a1b6d7704b259460152c959ab0e79e02aaMax Kellermann	{ .name = NULL }
41385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
42385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
431d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic int ECN_parse(int c, char **argv, int invert, unsigned int *flags,
441d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt                     const void *entry, struct xt_entry_target **target)
45385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
46c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	unsigned int result;
475a15c9a8b29871fc3246ed91423f271041a87c21Harald Welte	struct ipt_ECN_info *einfo
48385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		= (struct ipt_ECN_info *)(*target)->data;
49385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
50385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	switch (c) {
51385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	case 'F':
52385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		if (*flags)
531829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
54c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			        "ECN target: Only use --ecn-tcp-remove ONCE!");
55c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
56c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.ece = 0;
57c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.cwr = 0;
58385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		*flags = 1;
59385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		break;
60c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	case 'G':
61c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (*flags & IPT_ECN_OP_SET_CWR)
621829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
63c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-tcp-cwr ONCE!");
645f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(optarg, NULL, &result, 0, 1))
651829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
66c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				   "ECN target: Value out of range");
67c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_CWR;
68c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.cwr = result;
69c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		*flags |= IPT_ECN_OP_SET_CWR;
70c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		break;
71c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	case 'H':
72c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (*flags & IPT_ECN_OP_SET_ECE)
731829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
74c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-tcp-ece ONCE!");
755f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(optarg, NULL, &result, 0, 1))
761829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
77c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				   "ECN target: Value out of range");
78c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_ECE;
79c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.ece = result;
80c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		*flags |= IPT_ECN_OP_SET_ECE;
81c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		break;
82c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	case '9':
83c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (*flags & IPT_ECN_OP_SET_IP)
841829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
85c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-ip-ect ONCE!");
865f2922cfc0bbfbeb878f5c12e9fb3eb602ae5507Jan Engelhardt		if (!xtables_strtoui(optarg, NULL, &result, 0, 3))
871829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
88c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				   "ECN target: Value out of range");
89c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_IP;
90c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->ip_ect = result;
91c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte		*flags |= IPT_ECN_OP_SET_IP;
92c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte		break;
93385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	default:
94385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		return 0;
95385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
96385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
97385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	return 1;
98385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
99385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1001d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_check(unsigned int flags)
101385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
102385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	if (!flags)
1031829ed482efbc8b390cc760d012b3a4450494e1aJan Engelhardt		xtables_error(PARAMETER_PROBLEM,
1044ac9fddb50eb4898f145d6daf14cbf97702ee763Harald Welte		           "ECN target: Parameter --ecn-tcp-remove is required");
105385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
106385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1071d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_print(const void *ip, const struct xt_entry_target *target,
1081d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt                      int numeric)
109385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
110385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
111385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
112385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
113385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	printf("ECN ");
114385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1157b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1167b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1177b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
1187b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		printf("TCP remove ");
1197b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
1207b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
121c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("ECE=%u ", einfo->proto.tcp.ece);
1227b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1237b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
124c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("CWR=%u ", einfo->proto.tcp.cwr);
1257b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1267b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
127c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("ECT codepoint=%u ", einfo->ip_ect);
128385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
129385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
130385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1311d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_save(const void *ip, const struct xt_entry_target *target)
132385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
133385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
134385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
135385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1367b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1377b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1387b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
1397b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		printf("--ecn-tcp-remove ");
1407b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
141c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1427b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
1437b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
1447b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1457b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
1467b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
147c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1487b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
1497b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-ip-ect %d ", einfo->ip_ect);
150385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
151385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
152385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1538b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target ecn_tg_reg = {
1548caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira	.name		= "ECN",
1558b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.version	= XTABLES_VERSION,
15603d99486d8283552705b58dc55b6085dffc38792Jan Engelhardt	.family		= NFPROTO_IPV4,
1578b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.size		= XT_ALIGN(sizeof(struct ipt_ECN_info)),
1588b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ECN_info)),
1591d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.help		= ECN_help,
1601d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.parse		= ECN_parse,
1611d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.final_check	= ECN_check,
1621d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.print		= ECN_print,
1631d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.save		= ECN_save,
1641d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.extra_opts	= ECN_opts,
165385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
166385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
167385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltevoid _init(void)
168385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
1698b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	xtables_register_target(&ecn_tg_reg);
170385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
171