changing trunk/trunk to trunk
[iptables.git] / extensions / libxt_TCPOPTSTRIP.c
1 /*
2  * Shared library add-on to iptables to add TCPOPTSTRIP target support.
3  * Copyright (c) 2007 Sven Schnelle <svens@bitebene.org>
4  * Copyright © CC Computer Consultants GmbH, 2007
5  * Jan Engelhardt <jengelh@computergmbh.de>
6  */
7 #include <getopt.h>
8 #include <stdbool.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <xtables.h>
13 #include <linux/netfilter/x_tables.h>
14 #include <linux/netfilter/xt_TCPOPTSTRIP.h>
15 #ifndef TCPOPT_MD5SIG
16 #       define TCPOPT_MD5SIG 19
17 #endif
18
19 enum {
20         FLAG_STRIP = 1 << 0,
21 };
22
23 struct tcp_optionmap {
24         const char *name, *desc;
25         const unsigned int option;
26 };
27
28 static const struct option tcpoptstrip_tg_opts[] = {
29         {.name = "strip-options", .has_arg = true, .val = 's'},
30         { .name = NULL }
31 };
32
33 static const struct tcp_optionmap tcp_optionmap[] = {
34         {"wscale",         "Window scale",         TCPOPT_WINDOW},
35         {"mss",            "Maximum Segment Size", TCPOPT_MAXSEG},
36         {"sack-permitted", "SACK permitted",       TCPOPT_SACK_PERMITTED},
37         {"sack",           "Selective ACK",        TCPOPT_SACK},
38         {"timestamp",      "Timestamp",            TCPOPT_TIMESTAMP},
39         {"md5",            "MD5 signature",        TCPOPT_MD5SIG},
40         { .name = NULL }
41 };
42
43 static void tcpoptstrip_tg_help(void)
44 {
45         const struct tcp_optionmap *w;
46
47         printf(
48 "TCPOPTSTRIP target options:\n"
49 "  --strip-options value     strip specified TCP options denoted by value\n"
50 "                            (separated by comma) from TCP header\n"
51 "  Instead of the numeric value, you can also use the following names:\n"
52         );
53
54         for (w = tcp_optionmap; w->name != NULL; ++w)
55                 printf("    %-14s    strip \"%s\" option\n", w->name, w->desc);
56 }
57
58 static void tcpoptstrip_tg_init(struct xt_entry_target *t)
59 {
60         struct xt_tcpoptstrip_target_info *info = (void *)t->data;
61
62         /* strictly necessary? play safe for now. */
63         memset(info->strip_bmap, 0, sizeof(info->strip_bmap));
64 }
65
66 static void parse_list(struct xt_tcpoptstrip_target_info *info, char *arg)
67 {
68         unsigned int option;
69         char *p;
70         int i;
71
72         while (true) {
73                 p = strchr(arg, ',');
74                 if (p != NULL)
75                         *p = '\0';
76
77                 option = 0;
78                 for (i = 0; tcp_optionmap[i].name != NULL; ++i)
79                         if (strcmp(tcp_optionmap[i].name, arg) == 0) {
80                                 option = tcp_optionmap[i].option;
81                                 break;
82                         }
83
84                 if (option == 0 && string_to_number(arg, 0, 255, &option) == -1)
85                         exit_error(PARAMETER_PROBLEM,
86                                    "Bad TCP option value \"%s\"", arg);
87
88                 if (option < 2)
89                         exit_error(PARAMETER_PROBLEM,
90                                    "Option value may not be 0 or 1");
91
92                 if (tcpoptstrip_test_bit(info->strip_bmap, option))
93                         exit_error(PARAMETER_PROBLEM,
94                                    "Option \"%s\" already specified", arg);
95
96                 tcpoptstrip_set_bit(info->strip_bmap, option);
97                 if (p == NULL)
98                         break;
99                 arg = p + 1;
100         }
101 }
102
103 static int tcpoptstrip_tg_parse(int c, char **argv, int invert,
104                                 unsigned int *flags, const void *entry,
105                                 struct xt_entry_target **target)
106 {
107         struct xt_tcpoptstrip_target_info *info = (void *)(*target)->data;
108
109         switch (c) {
110         case 's':
111                 if (*flags & FLAG_STRIP)
112                         exit_error(PARAMETER_PROBLEM,
113                                    "You can specify --strip-options only once");
114                 parse_list(info, optarg);
115                 *flags |= FLAG_STRIP;
116                 return true;
117         }
118
119         return false;
120 }
121
122 static void tcpoptstrip_tg_check(unsigned int flags)
123 {
124         if (flags == 0)
125                 exit_error(PARAMETER_PROBLEM,
126                            "TCPOPTSTRIP: --strip-options parameter required");
127 }
128
129 static void
130 tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
131                        bool numeric)
132 {
133         unsigned int i, j;
134         const char *name;
135         bool first = true;
136
137         for (i = 0; i < 256; ++i) {
138                 if (!tcpoptstrip_test_bit(info->strip_bmap, i))
139                         continue;
140                 if (!first)
141                         printf(",");
142
143                 first = false;
144                 name  = NULL;
145                 if (!numeric)
146                         for (j = 0; tcp_optionmap[j].name != NULL; ++j)
147                                 if (tcp_optionmap[j].option == i)
148                                         name = tcp_optionmap[j].name;
149
150                 if (name != NULL)
151                         printf("%s", name);
152                 else
153                         printf("%u", i);
154         }
155 }
156
157 static void
158 tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
159                      int numeric)
160 {
161         const struct xt_tcpoptstrip_target_info *info =
162                 (const void *)target->data;
163
164         printf("TCPOPTSTRIP options ");
165         tcpoptstrip_print_list(info, numeric);
166 }
167
168 static void
169 tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
170 {
171         const struct xt_tcpoptstrip_target_info *info =
172                 (const void *)target->data;
173
174         printf("--strip-options ");
175         tcpoptstrip_print_list(info, true);
176 }
177
178 static struct xtables_target tcpoptstrip_tg_reg = {
179         .version       = XTABLES_VERSION,
180         .name          = "TCPOPTSTRIP",
181         .family        = AF_INET,
182         .size          = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
183         .userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
184         .help          = tcpoptstrip_tg_help,
185         .init          = tcpoptstrip_tg_init,
186         .parse         = tcpoptstrip_tg_parse,
187         .final_check   = tcpoptstrip_tg_check,
188         .print         = tcpoptstrip_tg_print,
189         .save          = tcpoptstrip_tg_save,
190         .extra_opts    = tcpoptstrip_tg_opts,
191 };
192
193 static struct xtables_target tcpoptstrip_tg6_reg = {
194         .version       = XTABLES_VERSION,
195         .name          = "TCPOPTSTRIP",
196         .family        = AF_INET6,
197         .size          = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
198         .userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
199         .help          = tcpoptstrip_tg_help,
200         .init          = tcpoptstrip_tg_init,
201         .parse         = tcpoptstrip_tg_parse,
202         .final_check   = tcpoptstrip_tg_check,
203         .print         = tcpoptstrip_tg_print,
204         .save          = tcpoptstrip_tg_save,
205         .extra_opts    = tcpoptstrip_tg_opts,
206 };
207
208 void _init(void)
209 {
210         xtables_register_target(&tcpoptstrip_tg_reg);
211         xtables_register_target(&tcpoptstrip_tg6_reg);
212 }