libipt_ECN.c revision afe6b357db60c7d70379a27360c10a352bf55203
1/* Shared library add-on to iptables for ECN, $Version$
2 *
3 * (C) 2002 by Harald Welte <laforge@gnumonks.org>
4 *
5 * This program is distributed under the terms of GNU GPL v2, 1991
6 *
7 * libipt_ECN.c borrowed heavily from libipt_DSCP.c
8 *
9 * $Id$
10 */
11#include <stdio.h>
12#include <string.h>
13#include <stdlib.h>
14#include <getopt.h>
15
16#include <xtables.h>
17#include <linux/netfilter_ipv4/ipt_ECN.h>
18
19static void ECN_help(void)
20{
21	printf(
22"ECN target options\n"
23"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n");
24}
25
26#if 0
27"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
28"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
29"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
30"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
31#endif
32
33
34static const struct option ECN_opts[] = {
35	{ "ecn-tcp-remove", 0, NULL, 'F' },
36	{ "ecn-tcp-cwr", 1, NULL, 'G' },
37	{ "ecn-tcp-ece", 1, NULL, 'H' },
38	{ "ecn-ip-ect", 1, NULL, '9' },
39	{ .name = NULL }
40};
41
42static int ECN_parse(int c, char **argv, int invert, unsigned int *flags,
43                     const void *entry, struct xt_entry_target **target)
44{
45	unsigned int result;
46	struct ipt_ECN_info *einfo
47		= (struct ipt_ECN_info *)(*target)->data;
48
49	switch (c) {
50	case 'F':
51		if (*flags)
52			xtables_error(PARAMETER_PROBLEM,
53			        "ECN target: Only use --ecn-tcp-remove ONCE!");
54		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
55		einfo->proto.tcp.ece = 0;
56		einfo->proto.tcp.cwr = 0;
57		*flags = 1;
58		break;
59	case 'G':
60		if (*flags & IPT_ECN_OP_SET_CWR)
61			xtables_error(PARAMETER_PROBLEM,
62				"ECN target: Only use --ecn-tcp-cwr ONCE!");
63		if (!xtables_strtoui(optarg, NULL, &result, 0, 1))
64			xtables_error(PARAMETER_PROBLEM,
65				   "ECN target: Value out of range");
66		einfo->operation |= IPT_ECN_OP_SET_CWR;
67		einfo->proto.tcp.cwr = result;
68		*flags |= IPT_ECN_OP_SET_CWR;
69		break;
70	case 'H':
71		if (*flags & IPT_ECN_OP_SET_ECE)
72			xtables_error(PARAMETER_PROBLEM,
73				"ECN target: Only use --ecn-tcp-ece ONCE!");
74		if (!xtables_strtoui(optarg, NULL, &result, 0, 1))
75			xtables_error(PARAMETER_PROBLEM,
76				   "ECN target: Value out of range");
77		einfo->operation |= IPT_ECN_OP_SET_ECE;
78		einfo->proto.tcp.ece = result;
79		*flags |= IPT_ECN_OP_SET_ECE;
80		break;
81	case '9':
82		if (*flags & IPT_ECN_OP_SET_IP)
83			xtables_error(PARAMETER_PROBLEM,
84				"ECN target: Only use --ecn-ip-ect ONCE!");
85		if (!xtables_strtoui(optarg, NULL, &result, 0, 3))
86			xtables_error(PARAMETER_PROBLEM,
87				   "ECN target: Value out of range");
88		einfo->operation |= IPT_ECN_OP_SET_IP;
89		einfo->ip_ect = result;
90		*flags |= IPT_ECN_OP_SET_IP;
91		break;
92	default:
93		return 0;
94	}
95
96	return 1;
97}
98
99static void ECN_check(unsigned int flags)
100{
101	if (!flags)
102		xtables_error(PARAMETER_PROBLEM,
103		           "ECN target: Parameter --ecn-tcp-remove is required");
104}
105
106static void ECN_print(const void *ip, const struct xt_entry_target *target,
107                      int numeric)
108{
109	const struct ipt_ECN_info *einfo =
110		(const struct ipt_ECN_info *)target->data;
111
112	printf("ECN ");
113
114	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
115	    && einfo->proto.tcp.ece == 0
116	    && einfo->proto.tcp.cwr == 0)
117		printf("TCP remove ");
118	else {
119		if (einfo->operation & IPT_ECN_OP_SET_ECE)
120			printf("ECE=%u ", einfo->proto.tcp.ece);
121
122		if (einfo->operation & IPT_ECN_OP_SET_CWR)
123			printf("CWR=%u ", einfo->proto.tcp.cwr);
124
125		if (einfo->operation & IPT_ECN_OP_SET_IP)
126			printf("ECT codepoint=%u ", einfo->ip_ect);
127	}
128}
129
130static void ECN_save(const void *ip, const struct xt_entry_target *target)
131{
132	const struct ipt_ECN_info *einfo =
133		(const struct ipt_ECN_info *)target->data;
134
135	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
136	    && einfo->proto.tcp.ece == 0
137	    && einfo->proto.tcp.cwr == 0)
138		printf("--ecn-tcp-remove ");
139	else {
140
141		if (einfo->operation & IPT_ECN_OP_SET_ECE)
142			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
143
144		if (einfo->operation & IPT_ECN_OP_SET_CWR)
145			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
146
147		if (einfo->operation & IPT_ECN_OP_SET_IP)
148			printf("--ecn-ip-ect %d ", einfo->ip_ect);
149	}
150}
151
152static struct xtables_target ecn_tg_reg = {
153	.name		= "ECN",
154	.version	= XTABLES_VERSION,
155	.family		= NFPROTO_IPV4,
156	.size		= XT_ALIGN(sizeof(struct ipt_ECN_info)),
157	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ECN_info)),
158	.help		= ECN_help,
159	.parse		= ECN_parse,
160	.final_check	= ECN_check,
161	.print		= ECN_print,
162	.save		= ECN_save,
163	.extra_opts	= ECN_opts,
164};
165
166void _init(void)
167{
168	xtables_register_target(&ecn_tg_reg);
169}
170