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#include <stdio.h>
10#include <xtables.h>
11#include <linux/netfilter_ipv4/ipt_ECN.h>
12
13enum {
14	O_ECN_TCP_REMOVE = 0,
15	O_ECN_TCP_CWR,
16	O_ECN_TCP_ECE,
17	O_ECN_IP_ECT,
18	F_ECN_TCP_REMOVE = 1 << O_ECN_TCP_REMOVE,
19	F_ECN_TCP_CWR    = 1 << O_ECN_TCP_CWR,
20	F_ECN_TCP_ECE    = 1 << O_ECN_TCP_ECE,
21};
22
23static void ECN_help(void)
24{
25	printf(
26"ECN target options\n"
27"  --ecn-tcp-remove		Remove all ECN bits from TCP header\n");
28}
29
30#if 0
31"ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
32"  --ecn-ip-ect			Set the IPv4 ECT codepoint (0 to 3)\n"
33"  --ecn-tcp-cwr		Set the IPv4 CWR bit (0 or 1)\n"
34"  --ecn-tcp-ece		Set the IPv4 ECE bit (0 or 1)\n",
35#endif
36
37static const struct xt_option_entry ECN_opts[] = {
38	{.name = "ecn-tcp-remove", .id = O_ECN_TCP_REMOVE, .type = XTTYPE_NONE,
39	 .excl = F_ECN_TCP_CWR | F_ECN_TCP_ECE},
40	{.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_UINT8,
41	 .min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE},
42	{.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_UINT8,
43	 .min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE},
44	{.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8,
45	 .min = 0, .max = 3},
46	XTOPT_TABLEEND,
47};
48
49static void ECN_parse(struct xt_option_call *cb)
50{
51	struct ipt_ECN_info *einfo = cb->data;
52
53	xtables_option_parse(cb);
54	switch (cb->entry->id) {
55	case O_ECN_TCP_REMOVE:
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		break;
60	case O_ECN_TCP_CWR:
61		einfo->operation |= IPT_ECN_OP_SET_CWR;
62		einfo->proto.tcp.cwr = cb->val.u8;
63		break;
64	case O_ECN_TCP_ECE:
65		einfo->operation |= IPT_ECN_OP_SET_ECE;
66		einfo->proto.tcp.ece = cb->val.u8;
67		break;
68	case O_ECN_IP_ECT:
69		einfo->operation |= IPT_ECN_OP_SET_IP;
70		einfo->ip_ect = cb->val.u8;
71		break;
72	}
73}
74
75static void ECN_check(struct xt_fcheck_call *cb)
76{
77	if (cb->xflags == 0)
78		xtables_error(PARAMETER_PROBLEM,
79		           "ECN target: An operation is required");
80}
81
82static void ECN_print(const void *ip, const struct xt_entry_target *target,
83                      int numeric)
84{
85	const struct ipt_ECN_info *einfo =
86		(const struct ipt_ECN_info *)target->data;
87
88	printf(" ECN");
89
90	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
91	    && einfo->proto.tcp.ece == 0
92	    && einfo->proto.tcp.cwr == 0)
93		printf(" TCP remove");
94	else {
95		if (einfo->operation & IPT_ECN_OP_SET_ECE)
96			printf(" ECE=%u", einfo->proto.tcp.ece);
97
98		if (einfo->operation & IPT_ECN_OP_SET_CWR)
99			printf(" CWR=%u", einfo->proto.tcp.cwr);
100
101		if (einfo->operation & IPT_ECN_OP_SET_IP)
102			printf(" ECT codepoint=%u", einfo->ip_ect);
103	}
104}
105
106static void ECN_save(const void *ip, const struct xt_entry_target *target)
107{
108	const struct ipt_ECN_info *einfo =
109		(const struct ipt_ECN_info *)target->data;
110
111	if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
112	    && einfo->proto.tcp.ece == 0
113	    && einfo->proto.tcp.cwr == 0)
114		printf(" --ecn-tcp-remove");
115	else {
116
117		if (einfo->operation & IPT_ECN_OP_SET_ECE)
118			printf(" --ecn-tcp-ece %d", einfo->proto.tcp.ece);
119
120		if (einfo->operation & IPT_ECN_OP_SET_CWR)
121			printf(" --ecn-tcp-cwr %d", einfo->proto.tcp.cwr);
122
123		if (einfo->operation & IPT_ECN_OP_SET_IP)
124			printf(" --ecn-ip-ect %d", einfo->ip_ect);
125	}
126}
127
128static struct xtables_target ecn_tg_reg = {
129	.name		= "ECN",
130	.version	= XTABLES_VERSION,
131	.family		= NFPROTO_IPV4,
132	.size		= XT_ALIGN(sizeof(struct ipt_ECN_info)),
133	.userspacesize	= XT_ALIGN(sizeof(struct ipt_ECN_info)),
134	.help		= ECN_help,
135	.print		= ECN_print,
136	.save		= ECN_save,
137	.x6_parse	= ECN_parse,
138	.x6_fcheck	= ECN_check,
139	.x6_options	= ECN_opts,
140};
141
142void _init(void)
143{
144	xtables_register_target(&ecn_tg_reg);
145}
146