libipt_ECN.c revision 1c8fa733e6092029d97bc5b2b6a4cb13b513f2f0
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.3 2002/04/10 13:12:53 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		NETFILTER_VERSION, NETFILTER_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	switch (einfo->operation) {
122		case IPT_ECN_OP_SET_ECE:
123			printf("ECE=%u ", einfo->proto.tcp.ece);
124			break;
125		case IPT_ECN_OP_SET_CWR:
126			printf("CWR=%u ", einfo->proto.tcp.cwr);
127			break;
128		case IPT_ECN_OP_SET_IP:
129			printf("ECT codepoint=%u ", einfo->ip_ect);
130		default:
131			printf("unsupported_ecn_operation ");
132			break;
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) {
144		printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
145	}
146
147	if (einfo->operation & IPT_ECN_OP_SET_CWR) {
148		printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
149	}
150
151	if (einfo->operation & IPT_ECN_OP_SET_IP) {
152		printf("--ecn-ip-ect %d ", einfo->ip_ect);
153	}
154}
155
156static
157struct iptables_target ecn
158= { NULL,
159    "ECN",
160    NETFILTER_VERSION,
161    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
162    IPT_ALIGN(sizeof(struct ipt_ECN_info)),
163    &help,
164    &init,
165    &parse,
166    &final_check,
167    &print,
168    &save,
169    opts
170};
171
172void _init(void)
173{
174	register_target(&ecn);
175}
176