Merge commit 'origin/trunk@12184' into fedora
[iptables.git] / extensions / .#libipt_ECN.c.1.7
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.7 2002/05/29 15:11:36 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
20 static void init(struct ipt_entry_target *t, unsigned int *nfcache) 
21 {
22 }
23
24 static 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
37 static 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
45 static int
46 parse(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 << IPT_ECN_SHIFT);
95         default:
96                 return 0;
97         }
98
99         return 1;
100 }
101
102 static void
103 final_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. */
111 static void
112 print(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. */
138 static void
139 save(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
161 static
162 struct 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
177 void _init(void)
178 {
179         register_target(&ecn);
180 }