libipt_ECN.c revision 8b7c64d6ba156a99008fcd810cba874c73294333
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
16385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte#include <iptables.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)
53385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte			exit_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)
62c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
63c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-tcp-cwr ONCE!");
64c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (string_to_number(optarg, 0, 1, &result))
65c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_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)
73c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
74c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-tcp-ece ONCE!");
75c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (string_to_number(optarg, 0, 1, &result))
76c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_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)
84c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
85c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-ip-ect ONCE!");
86c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (string_to_number(optarg, 0, 3, &result))
87c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_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)
103385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		exit_error(PARAMETER_PROBLEM,
1044ac9fddb50eb4898f145d6daf14cbf97702ee763Harald Welte		           "ECN target: Parameter --ecn-tcp-remove is required");
105385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
106385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
107385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Prints out the targinfo. */
1081d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_print(const void *ip, const struct xt_entry_target *target,
1091d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt                      int numeric)
110385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
111385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
112385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
113385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
114385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	printf("ECN ");
115385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1167b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1177b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1187b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
1197b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		printf("TCP remove ");
1207b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
1217b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
122c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("ECE=%u ", einfo->proto.tcp.ece);
1237b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1247b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
125c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("CWR=%u ", einfo->proto.tcp.cwr);
1267b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1277b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
128c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("ECT codepoint=%u ", einfo->ip_ect);
129385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
130385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
131385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
132385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Saves the union ipt_targinfo in parsable form to stdout. */
1331d5b63d12984d12c8d87242179855e17657be16dJan Engelhardtstatic void ECN_save(const void *ip, const struct xt_entry_target *target)
134385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
135385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
136385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
137385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1387b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1397b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1407b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
1417b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		printf("--ecn-tcp-remove ");
1427b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
143c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1447b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
1457b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
1467b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1477b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
1487b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
149c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1507b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
1517b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-ip-ect %d ", einfo->ip_ect);
152385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
153385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
154385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1558b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardtstatic struct xtables_target ecn_tg_reg = {
1568caee8b9e34fed4562fcff553197c161fc9d9979Pablo Neira	.name		= "ECN",
1578b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.version	= XTABLES_VERSION,
1588b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.family		= PF_INET,
1598b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.size		= XT_ALIGN(sizeof(struct ipt_ECN_info)),
1608b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ECN_info)),
1611d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.help		= ECN_help,
1621d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.parse		= ECN_parse,
1631d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.final_check	= ECN_check,
1641d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.print		= ECN_print,
1651d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.save		= ECN_save,
1661d5b63d12984d12c8d87242179855e17657be16dJan Engelhardt	.extra_opts	= ECN_opts,
167385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
168385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
169385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltevoid _init(void)
170385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
1718b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	xtables_register_target(&ecn_tg_reg);
172385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
173