blob: bd74e379a7f6a8d4f58010afe3f9a1f613e3d414 [file] [log] [blame]
/*
* Shared library add-on to iptables to add TCPOPTSTRIP target support.
* Copyright (c) 2007 Sven Schnelle <svens@bitebene.org>
* Copyright © CC Computer Consultants GmbH, 2007
* Jan Engelhardt <jengelh@computergmbh.de>
*/
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_TCPOPTSTRIP.h>
#ifndef TCPOPT_MD5SIG
# define TCPOPT_MD5SIG 19
#endif
enum {
FLAG_STRIP = 1 << 0,
};
struct tcp_optionmap {
const char *name, *desc;
const unsigned int option;
};
static const struct option tcpoptstrip_tg_opts[] = {
{.name = "strip-options", .has_arg = true, .val = 's'},
{ .name = NULL }
};
static const struct tcp_optionmap tcp_optionmap[] = {
{"wscale", "Window scale", TCPOPT_WINDOW},
{"mss", "Maximum Segment Size", TCPOPT_MAXSEG},
{"sack-permitted", "SACK permitted", TCPOPT_SACK_PERMITTED},
{"sack", "Selective ACK", TCPOPT_SACK},
{"timestamp", "Timestamp", TCPOPT_TIMESTAMP},
{"md5", "MD5 signature", TCPOPT_MD5SIG},
{ .name = NULL }
};
static void tcpoptstrip_tg_help(void)
{
const struct tcp_optionmap *w;
printf(
"TCPOPTSTRIP target options:\n"
" --strip-options value strip specified TCP options denoted by value\n"
" (separated by comma) from TCP header\n"
" Instead of the numeric value, you can also use the following names:\n"
);
for (w = tcp_optionmap; w->name != NULL; ++w)
printf(" %-14s strip \"%s\" option\n", w->name, w->desc);
}
static void tcpoptstrip_tg_init(struct xt_entry_target *t)
{
struct xt_tcpoptstrip_target_info *info = (void *)t->data;
/* strictly necessary? play safe for now. */
memset(info->strip_bmap, 0, sizeof(info->strip_bmap));
}
static void parse_list(struct xt_tcpoptstrip_target_info *info, char *arg)
{
unsigned int option;
char *p;
int i;
while (true) {
p = strchr(arg, ',');
if (p != NULL)
*p = '\0';
option = 0;
for (i = 0; tcp_optionmap[i].name != NULL; ++i)
if (strcmp(tcp_optionmap[i].name, arg) == 0) {
option = tcp_optionmap[i].option;
break;
}
if (option == 0 && string_to_number(arg, 0, 255, &option) == -1)
exit_error(PARAMETER_PROBLEM,
"Bad TCP option value \"%s\"", arg);
if (option < 2)
exit_error(PARAMETER_PROBLEM,
"Option value may not be 0 or 1");
if (tcpoptstrip_test_bit(info->strip_bmap, option))
exit_error(PARAMETER_PROBLEM,
"Option \"%s\" already specified", arg);
tcpoptstrip_set_bit(info->strip_bmap, option);
if (p == NULL)
break;
arg = p + 1;
}
}
static int tcpoptstrip_tg_parse(int c, char **argv, int invert,
unsigned int *flags, const void *entry,
struct xt_entry_target **target)
{
struct xt_tcpoptstrip_target_info *info = (void *)(*target)->data;
switch (c) {
case 's':
if (*flags & FLAG_STRIP)
exit_error(PARAMETER_PROBLEM,
"You can specify --strip-options only once");
parse_list(info, optarg);
*flags |= FLAG_STRIP;
return true;
}
return false;
}
static void tcpoptstrip_tg_check(unsigned int flags)
{
if (flags == 0)
exit_error(PARAMETER_PROBLEM,
"TCPOPTSTRIP: --strip-options parameter required");
}
static void
tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
bool numeric)
{
unsigned int i, j;
const char *name;
bool first = true;
for (i = 0; i < 256; ++i) {
if (!tcpoptstrip_test_bit(info->strip_bmap, i))
continue;
if (!first)
printf(",");
first = false;
name = NULL;
if (!numeric)
for (j = 0; tcp_optionmap[j].name != NULL; ++j)
if (tcp_optionmap[j].option == i)
name = tcp_optionmap[j].name;
if (name != NULL)
printf("%s", name);
else
printf("%u", i);
}
}
static void
tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tcpoptstrip_target_info *info =
(const void *)target->data;
printf("TCPOPTSTRIP options ");
tcpoptstrip_print_list(info, numeric);
}
static void
tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tcpoptstrip_target_info *info =
(const void *)target->data;
printf("--strip-options ");
tcpoptstrip_print_list(info, true);
}
static struct xtables_target tcpoptstrip_tg_reg = {
.version = XTABLES_VERSION,
.name = "TCPOPTSTRIP",
.family = AF_INET,
.size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
.help = tcpoptstrip_tg_help,
.init = tcpoptstrip_tg_init,
.parse = tcpoptstrip_tg_parse,
.final_check = tcpoptstrip_tg_check,
.print = tcpoptstrip_tg_print,
.save = tcpoptstrip_tg_save,
.extra_opts = tcpoptstrip_tg_opts,
};
static struct xtables_target tcpoptstrip_tg6_reg = {
.version = XTABLES_VERSION,
.name = "TCPOPTSTRIP",
.family = AF_INET6,
.size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
.help = tcpoptstrip_tg_help,
.init = tcpoptstrip_tg_init,
.parse = tcpoptstrip_tg_parse,
.final_check = tcpoptstrip_tg_check,
.print = tcpoptstrip_tg_print,
.save = tcpoptstrip_tg_save,
.extra_opts = tcpoptstrip_tg_opts,
};
void _init(void)
{
xtables_register_target(&tcpoptstrip_tg_reg);
xtables_register_target(&tcpoptstrip_tg6_reg);
}