libipt_ECN.c revision e0f47ada0d9b447333ef9f4ece4cc32438ab989a
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.10 2002/08/06 18:46:18 laforge 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#if 0
33"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
34"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
35"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
36"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
37#endif
38
39
40static struct option opts[] = {
41	{ "ecn-tcp-remove", 0, 0, 'F' },
42	{ "ecn-tcp-cwr", 1, 0, 'G' },
43	{ "ecn-tcp-ece", 1, 0, 'H' },
44	{ "ecn-ip-ect", 1, 0, '9' },
45	{ 0 }
46};
47
48static int
49parse(int c, char **argv, int invert, unsigned int *flags,
50      const struct ipt_entry *entry,
51      struct ipt_entry_target **target)
52{
53	unsigned int result;
54	struct ipt_ECN_info *einfo
55		= (struct ipt_ECN_info *)(*target)->data;
56
57	switch (c) {
58	case 'F':
59		if (*flags)
60			exit_error(PARAMETER_PROBLEM,
61			        "ECN target: Only use --ecn-tcp-remove ONCE!");
62		einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
63		einfo->proto.tcp.ece = 0;
64		einfo->proto.tcp.cwr = 0;
65		*flags = 1;
66		break;
67	case 'G':
68		if (*flags & IPT_ECN_OP_SET_CWR)
69			exit_error(PARAMETER_PROBLEM,
70				"ECN target: Only use --ecn-tcp-cwr ONCE!");
71		if (string_to_number(optarg, 0, 1, &result))
72			exit_error(PARAMETER_PROBLEM,
73				   "ECN target: Value out of range");
74		einfo->operation |= IPT_ECN_OP_SET_CWR;
75		einfo->proto.tcp.cwr = result;
76		*flags |= IPT_ECN_OP_SET_CWR;
77		break;
78	case 'H':
79		if (*flags & IPT_ECN_OP_SET_ECE)
80			exit_error(PARAMETER_PROBLEM,
81				"ECN target: Only use --ecn-tcp-ece ONCE!");
82		if (string_to_number(optarg, 0, 1, &result))
83			exit_error(PARAMETER_PROBLEM,
84				   "ECN target: Value out of range");
85		einfo->operation |= IPT_ECN_OP_SET_ECE;
86		einfo->proto.tcp.ece = result;
87		*flags |= IPT_ECN_OP_SET_ECE;
88		break;
89	case '9':
90		if (*flags & IPT_ECN_OP_SET_IP)
91			exit_error(PARAMETER_PROBLEM,
92				"ECN target: Only use --ecn-ip-ect ONCE!");
93		if (string_to_number(optarg, 0, 3, &result))
94			exit_error(PARAMETER_PROBLEM,
95				   "ECN target: Value out of range");
96		einfo->operation |= IPT_ECN_OP_SET_IP;
97		einfo->ip_ect = result;
98		*flags |= IPT_ECN_OP_SET_IP;
99		break;
100	default:
101		return 0;
102	}
103
104	return 1;
105}
106
107static void
108final_check(unsigned int flags)
109{
110	if (!flags)
111		exit_error(PARAMETER_PROBLEM,
112		           "ECN target: Parameter --ecn-remove is required");
113}
114
115/* Prints out the targinfo. */
116static void
117print(const struct ipt_ip *ip,
118      const struct ipt_entry_target *target,
119      int numeric)
120{
121	const struct ipt_ECN_info *einfo =
122		(const struct ipt_ECN_info *)target->data;
123
124	printf("ECN ");
125
126	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
127	    && einfo->proto.tcp.ece == 0
128	    && einfo->proto.tcp.cwr == 0)
129		printf("TCP remove ");
130	else {
131		if (einfo->operation & IPT_ECN_OP_SET_ECE)
132			printf("ECE=%u ", einfo->proto.tcp.ece);
133
134		if (einfo->operation & IPT_ECN_OP_SET_CWR)
135			printf("CWR=%u ", einfo->proto.tcp.cwr);
136
137		if (einfo->operation & IPT_ECN_OP_SET_IP)
138			printf("ECT codepoint=%u ", einfo->ip_ect);
139	}
140}
141
142/* Saves the union ipt_targinfo in parsable form to stdout. */
143static void
144save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
145{
146	const struct ipt_ECN_info *einfo =
147		(const struct ipt_ECN_info *)target->data;
148
149	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
150	    && einfo->proto.tcp.ece == 0
151	    && einfo->proto.tcp.cwr == 0)
152		printf("--ecn-tcp-remove ");
153	else {
154
155		if (einfo->operation & IPT_ECN_OP_SET_ECE)
156			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
157
158		if (einfo->operation & IPT_ECN_OP_SET_CWR)
159			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
160
161		if (einfo->operation & IPT_ECN_OP_SET_IP)
162			printf("--ecn-ip-ect %d ", einfo->ip_ect);
163	}
164}
165
166static
167struct iptables_target ecn
168= { NULL,
169    "ECN",
170    IPTABLES_VERSION,
171    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
172    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
173    &help,
174    &init,
175    &parse,
176    &final_check,
177    &print,
178    &save,
179    opts
180};
181
182void _init(void)
183{
184	register_target(&ecn);
185}
186