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 <stdio.h>
8 #include <string.h>
9 #include <xtables.h>
10 #include <netinet/tcp.h>
11 #include <linux/netfilter/xt_TCPOPTSTRIP.h>
12 #ifndef TCPOPT_MD5SIG
13 # define TCPOPT_MD5SIG 19
14 #endif
15 #ifndef TCPOPT_MAXSEG
16 # define TCPOPT_MAXSEG 2
17 #endif
18 #ifndef TCPOPT_WINDOW
19 # define TCPOPT_WINDOW 3
20 #endif
21 #ifndef TCPOPT_SACK_PERMITTED
22 # define TCPOPT_SACK_PERMITTED 4
23 #endif
24 #ifndef TCPOPT_SACK
25 # define TCPOPT_SACK 5
26 #endif
27 #ifndef TCPOPT_TIMESTAMP
28 # define TCPOPT_TIMESTAMP 8
29 #endif
30
31 enum {
32 O_STRIP_OPTION = 0,
33 };
34
35 struct tcp_optionmap {
36 const char *name, *desc;
37 const unsigned int option;
38 };
39
40 static const struct xt_option_entry tcpoptstrip_tg_opts[] = {
41 {.name = "strip-options", .id = O_STRIP_OPTION, .type = XTTYPE_STRING},
42 XTOPT_TABLEEND,
43 };
44
45 static const struct tcp_optionmap tcp_optionmap[] = {
46 {"wscale", "Window scale", TCPOPT_WINDOW},
47 {"mss", "Maximum Segment Size", TCPOPT_MAXSEG},
48 {"sack-permitted", "SACK permitted", TCPOPT_SACK_PERMITTED},
49 {"sack", "Selective ACK", TCPOPT_SACK},
50 {"timestamp", "Timestamp", TCPOPT_TIMESTAMP},
51 {"md5", "MD5 signature", TCPOPT_MD5SIG},
52 {NULL},
53 };
54
tcpoptstrip_tg_help(void)55 static void tcpoptstrip_tg_help(void)
56 {
57 const struct tcp_optionmap *w;
58
59 printf(
60 "TCPOPTSTRIP target options:\n"
61 " --strip-options value strip specified TCP options denoted by value\n"
62 " (separated by comma) from TCP header\n"
63 " Instead of the numeric value, you can also use the following names:\n"
64 );
65
66 for (w = tcp_optionmap; w->name != NULL; ++w)
67 printf(" %-14s strip \"%s\" option\n", w->name, w->desc);
68 }
69
70 static void
parse_list(struct xt_tcpoptstrip_target_info * info,const char * arg)71 parse_list(struct xt_tcpoptstrip_target_info *info, const char *arg)
72 {
73 unsigned int option;
74 char *p;
75 int i;
76
77 while (true) {
78 p = strchr(arg, ',');
79 if (p != NULL)
80 *p = '\0';
81
82 option = 0;
83 for (i = 0; tcp_optionmap[i].name != NULL; ++i)
84 if (strcmp(tcp_optionmap[i].name, arg) == 0) {
85 option = tcp_optionmap[i].option;
86 break;
87 }
88
89 if (option == 0 &&
90 !xtables_strtoui(arg, NULL, &option, 0, UINT8_MAX))
91 xtables_error(PARAMETER_PROBLEM,
92 "Bad TCP option value \"%s\"", arg);
93
94 if (option < 2)
95 xtables_error(PARAMETER_PROBLEM,
96 "Option value may not be 0 or 1");
97
98 if (tcpoptstrip_test_bit(info->strip_bmap, option))
99 xtables_error(PARAMETER_PROBLEM,
100 "Option \"%s\" already specified", arg);
101
102 tcpoptstrip_set_bit(info->strip_bmap, option);
103 if (p == NULL)
104 break;
105 arg = p + 1;
106 }
107 }
108
tcpoptstrip_tg_parse(struct xt_option_call * cb)109 static void tcpoptstrip_tg_parse(struct xt_option_call *cb)
110 {
111 struct xt_tcpoptstrip_target_info *info = cb->data;
112
113 xtables_option_parse(cb);
114 parse_list(info, cb->arg);
115 }
116
117 static void
tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info * info,bool numeric)118 tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
119 bool numeric)
120 {
121 unsigned int i, j;
122 const char *name;
123 bool first = true;
124
125 for (i = 0; i < 256; ++i) {
126 if (!tcpoptstrip_test_bit(info->strip_bmap, i))
127 continue;
128 if (!first)
129 printf(",");
130
131 first = false;
132 name = NULL;
133 if (!numeric)
134 for (j = 0; tcp_optionmap[j].name != NULL; ++j)
135 if (tcp_optionmap[j].option == i)
136 name = tcp_optionmap[j].name;
137
138 if (name != NULL)
139 printf("%s", name);
140 else
141 printf("%u", i);
142 }
143 }
144
145 static void
tcpoptstrip_tg_print(const void * ip,const struct xt_entry_target * target,int numeric)146 tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
147 int numeric)
148 {
149 const struct xt_tcpoptstrip_target_info *info =
150 (const void *)target->data;
151
152 printf(" TCPOPTSTRIP options ");
153 tcpoptstrip_print_list(info, numeric);
154 }
155
156 static void
tcpoptstrip_tg_save(const void * ip,const struct xt_entry_target * target)157 tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
158 {
159 const struct xt_tcpoptstrip_target_info *info =
160 (const void *)target->data;
161
162 printf(" --strip-options ");
163 tcpoptstrip_print_list(info, true);
164 }
165
166 static struct xtables_target tcpoptstrip_tg_reg = {
167 .version = XTABLES_VERSION,
168 .name = "TCPOPTSTRIP",
169 .family = NFPROTO_UNSPEC,
170 .size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
171 .userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
172 .help = tcpoptstrip_tg_help,
173 .print = tcpoptstrip_tg_print,
174 .save = tcpoptstrip_tg_save,
175 .x6_parse = tcpoptstrip_tg_parse,
176 .x6_options = tcpoptstrip_tg_opts,
177 };
178
_init(void)179 void _init(void)
180 {
181 xtables_register_target(&tcpoptstrip_tg_reg);
182 }
183