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 
13 enum {
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 
ECN_help(void)23 static 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 
37 static 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 
ECN_parse(struct xt_option_call * cb)49 static 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 
ECN_check(struct xt_fcheck_call * cb)75 static 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 
ECN_print(const void * ip,const struct xt_entry_target * target,int numeric)82 static 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 
ECN_save(const void * ip,const struct xt_entry_target * target)106 static 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 
128 static 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 
_init(void)142 void _init(void)
143 {
144 	xtables_register_target(&ecn_tg_reg);
145 }
146