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