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