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: libipt_ECN.c,v 1.1.1.1 2007/10/11 00:26:49 Exp $
10 */
11#include <stdio.h>
12#include <string.h>
13#include <stdlib.h>
14#include <getopt.h>
15
16#include <iptables.h>
17#include <linux/netfilter_ipv4/ip_tables.h>
18#include <linux/netfilter_ipv4/ipt_ECN.h>
19
20static void init(struct ipt_entry_target *t, unsigned int *nfcache)
21{
22}
23
24static void help(void)
25{
26	printf(
27"ECN target v%s options\n"
28"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n",
29		IPTABLES_VERSION);
30}
31
32
33
34static struct option opts[] = {
35	{ "ecn-tcp-remove", 0, 0, 'F' },
36	{ "ecn-tcp-cwr", 1, 0, 'G' },
37	{ "ecn-tcp-ece", 1, 0, 'H' },
38	{ "ecn-ip-ect", 1, 0, '9' },
39	{ 0 }
40};
41
42static int
43parse(int c, char **argv, int invert, unsigned int *flags,
44      const struct ipt_entry *entry,
45      struct ipt_entry_target **target)
46{
47	unsigned int result;
48	struct ipt_ECN_info *einfo
49		= (struct ipt_ECN_info *)(*target)->data;
50
51	switch (c) {
52	case 'F':
53		if (*flags)
54			exit_error(PARAMETER_PROBLEM,
55			        "ECN target: Only use --ecn-tcp-remove ONCE!");
56		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
57		einfo->proto.tcp.ece = 0;
58		einfo->proto.tcp.cwr = 0;
59		*flags = 1;
60		break;
61	case 'G':
62		if (*flags & IPT_ECN_OP_SET_CWR)
63			exit_error(PARAMETER_PROBLEM,
64				"ECN target: Only use --ecn-tcp-cwr ONCE!");
65		if (string_to_number(optarg, 0, 1, &result))
66			exit_error(PARAMETER_PROBLEM,
67				   "ECN target: Value out of range");
68		einfo->operation |= IPT_ECN_OP_SET_CWR;
69		einfo->proto.tcp.cwr = result;
70		*flags |= IPT_ECN_OP_SET_CWR;
71		break;
72	case 'H':
73		if (*flags & IPT_ECN_OP_SET_ECE)
74			exit_error(PARAMETER_PROBLEM,
75				"ECN target: Only use --ecn-tcp-ece ONCE!");
76		if (string_to_number(optarg, 0, 1, &result))
77			exit_error(PARAMETER_PROBLEM,
78				   "ECN target: Value out of range");
79		einfo->operation |= IPT_ECN_OP_SET_ECE;
80		einfo->proto.tcp.ece = result;
81		*flags |= IPT_ECN_OP_SET_ECE;
82		break;
83	case '9':
84		if (*flags & IPT_ECN_OP_SET_IP)
85			exit_error(PARAMETER_PROBLEM,
86				"ECN target: Only use --ecn-ip-ect ONCE!");
87		if (string_to_number(optarg, 0, 3, &result))
88			exit_error(PARAMETER_PROBLEM,
89				   "ECN target: Value out of range");
90		einfo->operation |= IPT_ECN_OP_SET_IP;
91		einfo->ip_ect = result;
92		*flags |= IPT_ECN_OP_SET_IP;
93		break;
94	default:
95		return 0;
96	}
97
98	return 1;
99}
100
101static void
102final_check(unsigned int flags)
103{
104	if (!flags)
105		exit_error(PARAMETER_PROBLEM,
106		           "ECN target: Parameter --ecn-tcp-remove is required");
107}
108
109/* Prints out the targinfo. */
110static void
111print(const struct ipt_ip *ip,
112      const struct ipt_entry_target *target,
113      int numeric)
114{
115	const struct ipt_ECN_info *einfo =
116		(const struct ipt_ECN_info *)target->data;
117
118	printf("ECN ");
119
120	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
121	    && einfo->proto.tcp.ece == 0
122	    && einfo->proto.tcp.cwr == 0)
123		printf("TCP remove ");
124	else {
125		if (einfo->operation & IPT_ECN_OP_SET_ECE)
126			printf("ECE=%u ", einfo->proto.tcp.ece);
127
128		if (einfo->operation & IPT_ECN_OP_SET_CWR)
129			printf("CWR=%u ", einfo->proto.tcp.cwr);
130
131		if (einfo->operation & IPT_ECN_OP_SET_IP)
132			printf("ECT codepoint=%u ", einfo->ip_ect);
133	}
134}
135
136/* Saves the union ipt_targinfo in parsable form to stdout. */
137static void
138save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
139{
140	const struct ipt_ECN_info *einfo =
141		(const struct ipt_ECN_info *)target->data;
142
143	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
144	    && einfo->proto.tcp.ece == 0
145	    && einfo->proto.tcp.cwr == 0)
146		printf("--ecn-tcp-remove ");
147	else {
148
149		if (einfo->operation & IPT_ECN_OP_SET_ECE)
150			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
151
152		if (einfo->operation & IPT_ECN_OP_SET_CWR)
153			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
154
155		if (einfo->operation & IPT_ECN_OP_SET_IP)
156			printf("--ecn-ip-ect %d ", einfo->ip_ect);
157	}
158}
159
160static
161struct iptables_target ecn = {
162	.next		= NULL,
163	.name		= "ECN",
164	.version	= IPTABLES_VERSION,
165	.size		= IPT_ALIGN(sizeof(struct ipt_ECN_info)),
166	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_ECN_info)),
167	.help		= &help,
168	.init		= &init,
169	.parse		= &parse,
170	.final_check	= &final_check,
171	.print		= &print,
172	.save		= &save,
173	.extra_opts	= opts
174};
175
176void _init(void)
177{
178	register_target(&ecn);
179}
180