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