Home | History | Annotate | Download | only in extensions
      1 /*
      2  * Shared library add-on to iptables to add TCPOPTSTRIP target support.
      3  * Copyright (c) 2007 Sven Schnelle <svens (at) bitebene.org>
      4  * Copyright  CC Computer Consultants GmbH, 2007
      5  * Jan Engelhardt <jengelh (at) 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 
     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
     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 
    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
    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
    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
    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 
    179 void _init(void)
    180 {
    181 	xtables_register_target(&tcpoptstrip_tg_reg);
    182 }
    183