changing trunk/trunk to trunk
[iptables.git] / extensions / libipt_ECN.c
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$
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
20 static void ECN_help(void)
21 {
22         printf(
23 "ECN target options\n"
24 "  --ecn-tcp-remove             Remove all ECN bits from TCP header\n");
25 }
26
27 #if 0
28 "ECN target v%s EXPERIMENTAL options (use with extreme care!)\n"
29 "  --ecn-ip-ect                 Set the IPv4 ECT codepoint (0 to 3)\n"
30 "  --ecn-tcp-cwr                Set the IPv4 CWR bit (0 or 1)\n"
31 "  --ecn-tcp-ece                Set the IPv4 ECE bit (0 or 1)\n",
32 #endif
33
34
35 static const struct option ECN_opts[] = {
36         { "ecn-tcp-remove", 0, NULL, 'F' },
37         { "ecn-tcp-cwr", 1, NULL, 'G' },
38         { "ecn-tcp-ece", 1, NULL, 'H' },
39         { "ecn-ip-ect", 1, NULL, '9' },
40         { .name = NULL }
41 };
42
43 static int ECN_parse(int c, char **argv, int invert, unsigned int *flags,
44                      const void *entry, struct xt_entry_target **target)
45 {
46         unsigned int result;
47         struct ipt_ECN_info *einfo
48                 = (struct ipt_ECN_info *)(*target)->data;
49
50         switch (c) {
51         case 'F':
52                 if (*flags)
53                         exit_error(PARAMETER_PROBLEM,
54                                 "ECN target: Only use --ecn-tcp-remove ONCE!");
55                 einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR;
56                 einfo->proto.tcp.ece = 0;
57                 einfo->proto.tcp.cwr = 0;
58                 *flags = 1;
59                 break;
60         case 'G':
61                 if (*flags & IPT_ECN_OP_SET_CWR)
62                         exit_error(PARAMETER_PROBLEM,
63                                 "ECN target: Only use --ecn-tcp-cwr ONCE!");
64                 if (string_to_number(optarg, 0, 1, &result))
65                         exit_error(PARAMETER_PROBLEM,
66                                    "ECN target: Value out of range");
67                 einfo->operation |= IPT_ECN_OP_SET_CWR;
68                 einfo->proto.tcp.cwr = result;
69                 *flags |= IPT_ECN_OP_SET_CWR;
70                 break;
71         case 'H':
72                 if (*flags & IPT_ECN_OP_SET_ECE)
73                         exit_error(PARAMETER_PROBLEM,
74                                 "ECN target: Only use --ecn-tcp-ece ONCE!");
75                 if (string_to_number(optarg, 0, 1, &result))
76                         exit_error(PARAMETER_PROBLEM,
77                                    "ECN target: Value out of range");
78                 einfo->operation |= IPT_ECN_OP_SET_ECE;
79                 einfo->proto.tcp.ece = result;
80                 *flags |= IPT_ECN_OP_SET_ECE;
81                 break;
82         case '9':
83                 if (*flags & IPT_ECN_OP_SET_IP)
84                         exit_error(PARAMETER_PROBLEM,
85                                 "ECN target: Only use --ecn-ip-ect ONCE!");
86                 if (string_to_number(optarg, 0, 3, &result))
87                         exit_error(PARAMETER_PROBLEM,
88                                    "ECN target: Value out of range");
89                 einfo->operation |= IPT_ECN_OP_SET_IP;
90                 einfo->ip_ect = result;
91                 *flags |= IPT_ECN_OP_SET_IP;
92                 break;
93         default:
94                 return 0;
95         }
96
97         return 1;
98 }
99
100 static void ECN_check(unsigned int flags)
101 {
102         if (!flags)
103                 exit_error(PARAMETER_PROBLEM,
104                            "ECN target: Parameter --ecn-tcp-remove is required");
105 }
106
107 /* Prints out the targinfo. */
108 static void ECN_print(const void *ip, const struct xt_entry_target *target,
109                       int numeric)
110 {
111         const struct ipt_ECN_info *einfo =
112                 (const struct ipt_ECN_info *)target->data;
113
114         printf("ECN ");
115
116         if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
117             && einfo->proto.tcp.ece == 0
118             && einfo->proto.tcp.cwr == 0)
119                 printf("TCP remove ");
120         else {
121                 if (einfo->operation & IPT_ECN_OP_SET_ECE)
122                         printf("ECE=%u ", einfo->proto.tcp.ece);
123
124                 if (einfo->operation & IPT_ECN_OP_SET_CWR)
125                         printf("CWR=%u ", einfo->proto.tcp.cwr);
126
127                 if (einfo->operation & IPT_ECN_OP_SET_IP)
128                         printf("ECT codepoint=%u ", einfo->ip_ect);
129         }
130 }
131
132 /* Saves the union ipt_targinfo in parsable form to stdout. */
133 static void ECN_save(const void *ip, const struct xt_entry_target *target)
134 {
135         const struct ipt_ECN_info *einfo =
136                 (const struct ipt_ECN_info *)target->data;
137
138         if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)
139             && einfo->proto.tcp.ece == 0
140             && einfo->proto.tcp.cwr == 0)
141                 printf("--ecn-tcp-remove ");
142         else {
143
144                 if (einfo->operation & IPT_ECN_OP_SET_ECE)
145                         printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece);
146
147                 if (einfo->operation & IPT_ECN_OP_SET_CWR)
148                         printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr);
149
150                 if (einfo->operation & IPT_ECN_OP_SET_IP)
151                         printf("--ecn-ip-ect %d ", einfo->ip_ect);
152         }
153 }
154
155 static struct xtables_target ecn_tg_reg = {
156         .name           = "ECN",
157         .version        = XTABLES_VERSION,
158         .family         = PF_INET,
159         .size           = XT_ALIGN(sizeof(struct ipt_ECN_info)),
160         .userspacesize  = XT_ALIGN(sizeof(struct ipt_ECN_info)),
161         .help           = ECN_help,
162         .parse          = ECN_parse,
163         .final_check    = ECN_check,
164         .print          = ECN_print,
165         .save           = ECN_save,
166         .extra_opts     = ECN_opts,
167 };
168
169 void _init(void)
170 {
171         xtables_register_target(&ecn_tg_reg);
172 }