libxt_TCPOPTSTRIP.c revision e88a7c2c7175742b58b6aa03f2b5aba2d80330a1
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 <netinet/tcp.h>
14#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;
26	const unsigned int option;
27};
28
29static const struct option tcpoptstrip_tg_opts[] = {
30	{.name = "strip-options", .has_arg = true, .val = 's'},
31	XT_GETOPT_TABLEEND,
32};
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},
41	XT_GETOPT_TABLEEND,
42};
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 parse_list(struct xt_tcpoptstrip_target_info *info, char *arg)
60{
61	unsigned int option;
62	char *p;
63	int i;
64
65	while (true) {
66		p = strchr(arg, ',');
67		if (p != NULL)
68			*p = '\0';
69
70		option = 0;
71		for (i = 0; tcp_optionmap[i].name != NULL; ++i)
72			if (strcmp(tcp_optionmap[i].name, arg) == 0) {
73				option = tcp_optionmap[i].option;
74				break;
75			}
76
77		if (option == 0 &&
78		    !xtables_strtoui(arg, NULL, &option, 0, UINT8_MAX))
79			xtables_error(PARAMETER_PROBLEM,
80			           "Bad TCP option value \"%s\"", arg);
81
82		if (option < 2)
83			xtables_error(PARAMETER_PROBLEM,
84			           "Option value may not be 0 or 1");
85
86		if (tcpoptstrip_test_bit(info->strip_bmap, option))
87			xtables_error(PARAMETER_PROBLEM,
88			           "Option \"%s\" already specified", arg);
89
90		tcpoptstrip_set_bit(info->strip_bmap, option);
91		if (p == NULL)
92			break;
93		arg = p + 1;
94	}
95}
96
97static int tcpoptstrip_tg_parse(int c, char **argv, int invert,
98                                unsigned int *flags, const void *entry,
99                                struct xt_entry_target **target)
100{
101	struct xt_tcpoptstrip_target_info *info = (void *)(*target)->data;
102
103	switch (c) {
104	case 's':
105		if (*flags & FLAG_STRIP)
106			xtables_error(PARAMETER_PROBLEM,
107			           "You can specify --strip-options only once");
108		parse_list(info, optarg);
109		*flags |= FLAG_STRIP;
110		return true;
111	}
112
113	return false;
114}
115
116static void tcpoptstrip_tg_check(unsigned int flags)
117{
118	if (flags == 0)
119		xtables_error(PARAMETER_PROBLEM,
120		           "TCPOPTSTRIP: --strip-options parameter required");
121}
122
123static void
124tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
125                       bool numeric)
126{
127	unsigned int i, j;
128	const char *name;
129	bool first = true;
130
131	for (i = 0; i < 256; ++i) {
132		if (!tcpoptstrip_test_bit(info->strip_bmap, i))
133			continue;
134		if (!first)
135			printf(",");
136
137		first = false;
138		name  = NULL;
139		if (!numeric)
140			for (j = 0; tcp_optionmap[j].name != NULL; ++j)
141				if (tcp_optionmap[j].option == i)
142					name = tcp_optionmap[j].name;
143
144		if (name != NULL)
145			printf("%s", name);
146		else
147			printf("%u", i);
148	}
149}
150
151static void
152tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
153                     int numeric)
154{
155	const struct xt_tcpoptstrip_target_info *info =
156		(const void *)target->data;
157
158	printf(" TCPOPTSTRIP options ");
159	tcpoptstrip_print_list(info, numeric);
160}
161
162static void
163tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
164{
165	const struct xt_tcpoptstrip_target_info *info =
166		(const void *)target->data;
167
168	printf(" --strip-options ");
169	tcpoptstrip_print_list(info, true);
170}
171
172static struct xtables_target tcpoptstrip_tg_reg = {
173	.version       = XTABLES_VERSION,
174	.name          = "TCPOPTSTRIP",
175	.family        = NFPROTO_UNSPEC,
176	.size          = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
177	.userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
178	.help          = tcpoptstrip_tg_help,
179	.parse         = tcpoptstrip_tg_parse,
180	.final_check   = tcpoptstrip_tg_check,
181	.print         = tcpoptstrip_tg_print,
182	.save          = tcpoptstrip_tg_save,
183	.extra_opts    = tcpoptstrip_tg_opts,
184};
185
186void _init(void)
187{
188	xtables_register_target(&tcpoptstrip_tg_reg);
189}
190