/*
* 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 <stdio.h>
#include <string.h>
#include <xtables.h>
#include <netinet/tcp.h>
#include <linux/netfilter/xt_TCPOPTSTRIP.h>
#ifndef TCPOPT_MD5SIG
# define TCPOPT_MD5SIG 19
#endif
enum {
O_STRIP_OPTION = 0,
};
struct tcp_optionmap {
const char *name, *desc;
const unsigned int option;
};
static const struct xt_option_entry tcpoptstrip_tg_opts[] = {
{.name = "strip-options", .id = O_STRIP_OPTION, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
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},
{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
parse_list(struct xt_tcpoptstrip_target_info *info, const 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 &&
!xtables_strtoui(arg, NULL, &option, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Bad TCP option value \"%s\"", arg);
if (option < 2)
xtables_error(PARAMETER_PROBLEM,
"Option value may not be 0 or 1");
if (tcpoptstrip_test_bit(info->strip_bmap, option))
xtables_error(PARAMETER_PROBLEM,
"Option \"%s\" already specified", arg);
tcpoptstrip_set_bit(info->strip_bmap, option);
if (p == NULL)
break;
arg = p + 1;
}
}
static void tcpoptstrip_tg_parse(struct xt_option_call *cb)
{
struct xt_tcpoptstrip_target_info *info = cb->data;
xtables_option_parse(cb);
parse_list(info, cb->arg);
}
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 = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)),
.help = tcpoptstrip_tg_help,
.print = tcpoptstrip_tg_print,
.save = tcpoptstrip_tg_save,
.x6_parse = tcpoptstrip_tg_parse,
.x6_options = tcpoptstrip_tg_opts,
};
void _init(void)
{
xtables_register_target(&tcpoptstrip_tg_reg);
}