blob: c053a8b158b0593c86ca64cc0858061a56f8d6dd [file] [log] [blame]
Sven Schnelleaef4c1e2008-01-20 13:45:16 +00001/*
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>
Jan Engelhardtef18e812008-08-04 12:47:48 +020013#include <netinet/tcp.h>
Sven Schnelleaef4c1e2008-01-20 13:45:16 +000014#include <linux/netfilter/x_tables.h>
15#include <linux/netfilter/xt_TCPOPTSTRIP.h>
16#ifndef TCPOPT_MD5SIG
17# define TCPOPT_MD5SIG 19
18#endif
19
20enum {
21 FLAG_STRIP = 1 << 0,
22};
23
24struct tcp_optionmap {
25 const char *name, *desc;
Jan Engelhardt7a236f42008-03-03 12:30:41 +010026 const unsigned int option;
Sven Schnelleaef4c1e2008-01-20 13:45:16 +000027};
28
29static const struct option tcpoptstrip_tg_opts[] = {
30 {.name = "strip-options", .has_arg = true, .val = 's'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000031 { .name = NULL }
Sven Schnelleaef4c1e2008-01-20 13:45:16 +000032};
33
34static const struct tcp_optionmap tcp_optionmap[] = {
35 {"wscale", "Window scale", TCPOPT_WINDOW},
36 {"mss", "Maximum Segment Size", TCPOPT_MAXSEG},
37 {"sack-permitted", "SACK permitted", TCPOPT_SACK_PERMITTED},
38 {"sack", "Selective ACK", TCPOPT_SACK},
39 {"timestamp", "Timestamp", TCPOPT_TIMESTAMP},
40 {"md5", "MD5 signature", TCPOPT_MD5SIG},
Max Kellermann9ee386a2008-01-29 13:48:05 +000041 { .name = NULL }
Sven Schnelleaef4c1e2008-01-20 13:45:16 +000042};
43
44static void tcpoptstrip_tg_help(void)
45{
46 const struct tcp_optionmap *w;
47
48 printf(
49"TCPOPTSTRIP target options:\n"
50" --strip-options value strip specified TCP options denoted by value\n"
51" (separated by comma) from TCP header\n"
52" Instead of the numeric value, you can also use the following names:\n"
53 );
54
55 for (w = tcp_optionmap; w->name != NULL; ++w)
56 printf(" %-14s strip \"%s\" option\n", w->name, w->desc);
57}
58
59static void tcpoptstrip_tg_init(struct xt_entry_target *t)
60{
61 struct xt_tcpoptstrip_target_info *info = (void *)t->data;
62
63 /* strictly necessary? play safe for now. */
64 memset(info->strip_bmap, 0, sizeof(info->strip_bmap));
65}
66
67static void parse_list(struct xt_tcpoptstrip_target_info *info, char *arg)
68{
69 unsigned int option;
70 char *p;
71 int i;
72
73 while (true) {
74 p = strchr(arg, ',');
75 if (p != NULL)
76 *p = '\0';
77
78 option = 0;
79 for (i = 0; tcp_optionmap[i].name != NULL; ++i)
80 if (strcmp(tcp_optionmap[i].name, arg) == 0) {
81 option = tcp_optionmap[i].option;
82 break;
83 }
84
Jan Engelhardt5f2922c2009-01-27 18:43:01 +010085 if (option == 0 &&
86 !xtables_strtoui(arg, NULL, &option, 0, UINT8_MAX))
Sven Schnelleaef4c1e2008-01-20 13:45:16 +000087 exit_error(PARAMETER_PROBLEM,
88 "Bad TCP option value \"%s\"", arg);
89
90 if (option < 2)
91 exit_error(PARAMETER_PROBLEM,
92 "Option value may not be 0 or 1");
93
94 if (tcpoptstrip_test_bit(info->strip_bmap, option))
95 exit_error(PARAMETER_PROBLEM,
96 "Option \"%s\" already specified", arg);
97
98 tcpoptstrip_set_bit(info->strip_bmap, option);
99 if (p == NULL)
100 break;
101 arg = p + 1;
102 }
103}
104
105static int tcpoptstrip_tg_parse(int c, char **argv, int invert,
106 unsigned int *flags, const void *entry,
107 struct xt_entry_target **target)
108{
109 struct xt_tcpoptstrip_target_info *info = (void *)(*target)->data;
110
111 switch (c) {
112 case 's':
113 if (*flags & FLAG_STRIP)
114 exit_error(PARAMETER_PROBLEM,
115 "You can specify --strip-options only once");
116 parse_list(info, optarg);
117 *flags |= FLAG_STRIP;
118 return true;
119 }
120
121 return false;
122}
123
124static void tcpoptstrip_tg_check(unsigned int flags)
125{
126 if (flags == 0)
127 exit_error(PARAMETER_PROBLEM,
128 "TCPOPTSTRIP: --strip-options parameter required");
129}
130
131static void
132tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
133 bool numeric)
134{
135 unsigned int i, j;
136 const char *name;
137 bool first = true;
138
139 for (i = 0; i < 256; ++i) {
140 if (!tcpoptstrip_test_bit(info->strip_bmap, i))
141 continue;
142 if (!first)
143 printf(",");
144
145 first = false;
146 name = NULL;
147 if (!numeric)
148 for (j = 0; tcp_optionmap[j].name != NULL; ++j)
149 if (tcp_optionmap[j].option == i)
150 name = tcp_optionmap[j].name;
151
152 if (name != NULL)
153 printf("%s", name);
154 else
155 printf("%u", i);
156 }
157}
158
159static void
160tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
161 int numeric)
162{
163 const struct xt_tcpoptstrip_target_info *info =
164 (const void *)target->data;
165
166 printf("TCPOPTSTRIP options ");
167 tcpoptstrip_print_list(info, numeric);
168}
169
170static void
171tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
172{
173 const struct xt_tcpoptstrip_target_info *info =
174 (const void *)target->data;
175
176 printf("--strip-options ");
177 tcpoptstrip_print_list(info, true);
178}
179
180static struct xtables_target tcpoptstrip_tg_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200181 .version = XTABLES_VERSION,
Sven Schnelleaef4c1e2008-01-20 13:45:16 +0000182 .name = "TCPOPTSTRIP",
Jan Engelhardt03d99482008-11-18 12:27:54 +0100183 .family = NFPROTO_IPV4,
Sven Schnelleaef4c1e2008-01-20 13:45:16 +0000184 .size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
185 .userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
186 .help = tcpoptstrip_tg_help,
187 .init = tcpoptstrip_tg_init,
188 .parse = tcpoptstrip_tg_parse,
189 .final_check = tcpoptstrip_tg_check,
190 .print = tcpoptstrip_tg_print,
191 .save = tcpoptstrip_tg_save,
192 .extra_opts = tcpoptstrip_tg_opts,
193};
194
195static struct xtables_target tcpoptstrip_tg6_reg = {
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200196 .version = XTABLES_VERSION,
Sven Schnelleaef4c1e2008-01-20 13:45:16 +0000197 .name = "TCPOPTSTRIP",
Jan Engelhardt03d99482008-11-18 12:27:54 +0100198 .family = NFPROTO_IPV6,
Sven Schnelleaef4c1e2008-01-20 13:45:16 +0000199 .size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
200 .userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
201 .help = tcpoptstrip_tg_help,
202 .init = tcpoptstrip_tg_init,
203 .parse = tcpoptstrip_tg_parse,
204 .final_check = tcpoptstrip_tg_check,
205 .print = tcpoptstrip_tg_print,
206 .save = tcpoptstrip_tg_save,
207 .extra_opts = tcpoptstrip_tg_opts,
208};
209
210void _init(void)
211{
212 xtables_register_target(&tcpoptstrip_tg_reg);
213 xtables_register_target(&tcpoptstrip_tg6_reg);
214}