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