libipt_ECN.c revision 7b49af40179706d42d98cb72330a07df37dcb7ea
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.6 2002/05/29 13:08:16 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 CWR 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	default:
96		return 0;
97	}
98
99	return 1;
100}
101
102static void
103final_check(unsigned int flags)
104{
105	if (!flags)
106		exit_error(PARAMETER_PROBLEM,
107		           "ECN target: Parameter --ecn-remove is required");
108}
109
110/* Prints out the targinfo. */
111static void
112print(const struct ipt_ip *ip,
113      const struct ipt_entry_target *target,
114      int numeric)
115{
116	const struct ipt_ECN_info *einfo =
117		(const struct ipt_ECN_info *)target->data;
118
119	printf("ECN ");
120
121	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
122	    && einfo->proto.tcp.ece == 0
123	    && einfo->proto.tcp.cwr == 0)
124		printf("TCP remove ");
125	else {
126		if (einfo->operation & IPT_ECN_OP_SET_ECE)
127			printf("ECE=%u ", einfo->proto.tcp.ece);
128
129		if (einfo->operation & IPT_ECN_OP_SET_CWR)
130			printf("CWR=%u ", einfo->proto.tcp.cwr);
131
132		if (einfo->operation & IPT_ECN_OP_SET_IP)
133			printf("ECT codepoint=%u ", einfo->ip_ect);
134	}
135}
136
137/* Saves the union ipt_targinfo in parsable form to stdout. */
138static void
139save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
140{
141	const struct ipt_ECN_info *einfo =
142		(const struct ipt_ECN_info *)target->data;
143
144	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
145	    && einfo->proto.tcp.ece == 0
146	    && einfo->proto.tcp.cwr == 0)
147		printf("--ecn-tcp-remove ");
148	else {
149
150		if (einfo->operation & IPT_ECN_OP_SET_ECE)
151			printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
152
153		if (einfo->operation & IPT_ECN_OP_SET_CWR)
154			printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
155
156		if (einfo->operation & IPT_ECN_OP_SET_IP)
157			printf("--ecn-ip-ect %d ", einfo->ip_ect);
158	}
159}
160
161static
162struct iptables_target ecn
163= { NULL,
164    "ECN",
165    IPTABLES_VERSION,
166    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
167    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
168    &help,
169    &init,
170    &parse,
171    &final_check,
172    &print,
173    &save,
174    opts
175};
176
177void _init(void)
178{
179	register_target(&ecn);
180}
181