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