libipt_ECN.c revision 4ac9fddb50eb4898f145d6daf14cbf97702ee763
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 *
94ac9fddb50eb4898f145d6daf14cbf97702ee763Harald Welte * $Id: libipt_ECN.c,v 1.11 2002/08/07 10:04:42 laforge Exp $
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
20385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic void init(struct ipt_entry_target *t, unsigned int *nfcache)
21385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
22385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
23385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
24385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic void help(void)
25385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
26385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	printf(
271c8fa733e6092029d97bc5b2b6a4cb13b513f2f0Harald Welte"ECN target v%s options\n"
2831d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n",
29e0f47ada0d9b447333ef9f4ece4cc32438ab989aHarald Welte		IPTABLES_VERSION);
3031d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte}
3131d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte
3231d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#if 0
331c8fa733e6092029d97bc5b2b6a4cb13b513f2f0Harald Welte"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
34c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
35c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
3692cad5f4a349daac294332b8f8f696b43c55d3fcHarald Welte"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
3731d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte#endif
3831d12a598c80f609e68550cf043b1c6b2fd0e35eHarald Welte
39385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
40385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic struct option opts[] = {
41c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	{ "ecn-tcp-remove", 0, 0, 'F' },
42c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	{ "ecn-tcp-cwr", 1, 0, 'G' },
43c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	{ "ecn-tcp-ece", 1, 0, 'H' },
44c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	{ "ecn-ip-ect", 1, 0, '9' },
45385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	{ 0 }
46385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
47385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
48385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic int
49385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welteparse(int c, char **argv, int invert, unsigned int *flags,
50385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte      const struct ipt_entry *entry,
51385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte      struct ipt_entry_target **target)
52385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
53c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	unsigned int result;
545a15c9a8b29871fc3246ed91423f271041a87c21Harald Welte	struct ipt_ECN_info *einfo
55385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		= (struct ipt_ECN_info *)(*target)->data;
56385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
57385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	switch (c) {
58385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	case 'F':
59385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		if (*flags)
60385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte			exit_error(PARAMETER_PROBLEM,
61c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			        "ECN target: Only use --ecn-tcp-remove ONCE!");
62c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
63c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.ece = 0;
64c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.cwr = 0;
65385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		*flags = 1;
66385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		break;
67c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	case 'G':
68c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (*flags & IPT_ECN_OP_SET_CWR)
69c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
70c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-tcp-cwr ONCE!");
71c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (string_to_number(optarg, 0, 1, &result))
72c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
73c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				   "ECN target: Value out of range");
74c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_CWR;
75c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.cwr = result;
76c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		*flags |= IPT_ECN_OP_SET_CWR;
77c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		break;
78c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	case 'H':
79c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (*flags & IPT_ECN_OP_SET_ECE)
80c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
81c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-tcp-ece ONCE!");
82c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (string_to_number(optarg, 0, 1, &result))
83c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
84c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				   "ECN target: Value out of range");
85c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_ECE;
86c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->proto.tcp.ece = result;
87c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		*flags |= IPT_ECN_OP_SET_ECE;
88c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		break;
89c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte	case '9':
90c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (*flags & IPT_ECN_OP_SET_IP)
91c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
92c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				"ECN target: Only use --ecn-ip-ect ONCE!");
93c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		if (string_to_number(optarg, 0, 3, &result))
94c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			exit_error(PARAMETER_PROBLEM,
95c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte				   "ECN target: Value out of range");
96c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->operation |= IPT_ECN_OP_SET_IP;
97c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte		einfo->ip_ect = result;
98c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte		*flags |= IPT_ECN_OP_SET_IP;
99c05c44fc6018fcd94df499c981d846ff20882c4cHarald Welte		break;
100385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	default:
101385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		return 0;
102385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
103385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
104385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	return 1;
105385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
106385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
107385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic void
108385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltefinal_check(unsigned int flags)
109385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
110385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	if (!flags)
111385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		exit_error(PARAMETER_PROBLEM,
1124ac9fddb50eb4898f145d6daf14cbf97702ee763Harald Welte		           "ECN target: Parameter --ecn-tcp-remove is required");
113385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
114385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
115385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Prints out the targinfo. */
116385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic void
117385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welteprint(const struct ipt_ip *ip,
118385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte      const struct ipt_entry_target *target,
119385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte      int numeric)
120385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
121385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
122385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
123385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
124385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	printf("ECN ");
125385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1267b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1277b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1287b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
1297b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		printf("TCP remove ");
1307b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
1317b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
132c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("ECE=%u ", einfo->proto.tcp.ece);
1337b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1347b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
135c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("CWR=%u ", einfo->proto.tcp.cwr);
1367b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1377b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
138c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte			printf("ECT codepoint=%u ", einfo->ip_ect);
139385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
140385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
141385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
142385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte/* Saves the union ipt_targinfo in parsable form to stdout. */
143385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic void
144385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltesave(const struct ipt_ip *ip, const struct ipt_entry_target *target)
145385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
146385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	const struct ipt_ECN_info *einfo =
147385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte		(const struct ipt_ECN_info *)target->data;
148385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
1497b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
1507b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.ece == 0
1517b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	    && einfo->proto.tcp.cwr == 0)
1527b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		printf("--ecn-tcp-remove ");
1537b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte	else {
154c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1557b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_ECE)
1567b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
1577b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte
1587b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_CWR)
1597b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
160c980a240bad8f8995805df3bfdfb18180dd08d03Harald Welte
1617b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte		if (einfo->operation & IPT_ECN_OP_SET_IP)
1627b49af40179706d42d98cb72330a07df37dcb7eaHarald Welte			printf("--ecn-ip-ect %d ", einfo->ip_ect);
163385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	}
164385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
165385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
166385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestatic
167385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltestruct iptables_target ecn
168385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte= { NULL,
169385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    "ECN",
17080fe35d6339b53a12ddaec41885613e4e37ed031Harald Welte    IPTABLES_VERSION,
171385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
172385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
173385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    &help,
174385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    &init,
175385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    &parse,
176385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    &final_check,
177385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    &print,
178385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    &save,
179385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte    opts
180385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte};
181385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte
182385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Weltevoid _init(void)
183385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte{
184385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte	register_target(&ecn);
185385a1dd0f3b01fc0fbd6bcdee9796e0240ea77c1Harald Welte}
186