Commit 7e95a8db authored by Arturo Borrero Gonzalez's avatar Arturo Borrero Gonzalez
Browse files

Imported Upstream version 1.4.21

parents
This target is only valid in the
.B nat
table, in the
.B PREROUTING
and
.B OUTPUT
chains, and user-defined chains which are only called from those
chains. It redirects the packet to the machine itself by changing the
destination IP to the primary address of the incoming interface
(locally-generated packets are mapped to the localhost address,
127.0.0.1 for IPv4 and ::1 for IPv6).
.TP
\fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP]
This specifies a destination port or range of ports to use: without
this, the destination port is never altered. This is only valid
if the rule also specifies one of the following protocols:
\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP.
.TP
\fB\-\-random\fP
If option
\fB\-\-random\fP
is used then port mapping will be randomized (kernel >= 2.6.22).
.TP
IPv6 support available starting Linux kernels >= 3.7.
/*
* Shared library add-on to iptables to add SECMARK target support.
*
* Based on the MARK target.
*
* Copyright (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter/xt_SECMARK.h>
#define PFX "SECMARK target: "
enum {
O_SELCTX = 0,
};
static void SECMARK_help(void)
{
printf(
"SECMARK target options:\n"
" --selctx value Set the SELinux security context\n");
}
static const struct xt_option_entry SECMARK_opts[] = {
{.name = "selctx", .id = O_SELCTX, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_PUT,
XTOPT_POINTER(struct xt_secmark_target_info, secctx)},
XTOPT_TABLEEND,
};
static void SECMARK_parse(struct xt_option_call *cb)
{
struct xt_secmark_target_info *info = cb->data;
xtables_option_parse(cb);
info->mode = SECMARK_MODE_SEL;
}
static void print_secmark(const struct xt_secmark_target_info *info)
{
switch (info->mode) {
case SECMARK_MODE_SEL:
printf("selctx %s", info->secctx);
break;
default:
xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
}
}
static void SECMARK_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_secmark_target_info *info =
(struct xt_secmark_target_info*)(target)->data;
printf(" SECMARK ");
print_secmark(info);
}
static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_secmark_target_info *info =
(struct xt_secmark_target_info*)target->data;
printf(" --");
print_secmark(info);
}
static struct xtables_target secmark_target = {
.family = NFPROTO_UNSPEC,
.name = "SECMARK",
.version = XTABLES_VERSION,
.revision = 0,
.size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
.help = SECMARK_help,
.print = SECMARK_print,
.save = SECMARK_save,
.x6_parse = SECMARK_parse,
.x6_options = SECMARK_opts,
};
void _init(void)
{
xtables_register_target(&secmark_target);
}
This is used to set the security mark value associated with the
packet for use by security subsystems such as SELinux. It is
valid in the
.B security
table (for backwards compatibility with older kernels, it is also
valid in the
.B mangle
table). The mark is 32 bits wide.
.TP
\fB\-\-selctx\fP \fIsecurity_context\fP
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* Shared library add-on to iptables to add IP set mangling target. */
#include <stdbool.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <xtables.h>
#include <linux/netfilter/xt_set.h>
#include "libxt_set.h"
/* Revision 0 */
static void
set_target_help_v0(void)
{
printf("SET target options:\n"
" --add-set name flags\n"
" --del-set name flags\n"
" add/del src/dst IP/port from/to named sets,\n"
" where flags are the comma separated list of\n"
" 'src' and 'dst' specifications.\n");
}
static const struct option set_target_opts_v0[] = {
{.name = "add-set", .has_arg = true, .val = '1'},
{.name = "del-set", .has_arg = true, .val = '2'},
XT_GETOPT_TABLEEND,
};
static void
set_target_check_v0(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM,
"You must specify either `--add-set' or `--del-set'");
}
static void
set_target_init_v0(struct xt_entry_target *target)
{
struct xt_set_info_target_v0 *info =
(struct xt_set_info_target_v0 *) target->data;
info->add_set.index =
info->del_set.index = IPSET_INVALID_ID;
}
static void
parse_target_v0(char **argv, int invert, unsigned int *flags,
struct xt_set_info_v0 *info, const char *what)
{
if (info->u.flags[0])
xtables_error(PARAMETER_PROBLEM,
"--%s can be specified only once", what);
if (!argv[optind]
|| argv[optind][0] == '-' || argv[optind][0] == '!')
xtables_error(PARAMETER_PROBLEM,
"--%s requires two args.", what);
if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
xtables_error(PARAMETER_PROBLEM,
"setname `%s' too long, max %d characters.",
optarg, IPSET_MAXNAMELEN - 1);
get_set_byname(optarg, (struct xt_set_info *)info);
parse_dirs_v0(argv[optind], info);
optind++;
*flags = 1;
}
static int
set_target_parse_v0(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_set_info_target_v0 *myinfo =
(struct xt_set_info_target_v0 *) (*target)->data;
switch (c) {
case '1': /* --add-set <set> <flags> */
parse_target_v0(argv, invert, flags,
&myinfo->add_set, "add-set");
break;
case '2': /* --del-set <set>[:<flags>] <flags> */
parse_target_v0(argv, invert, flags,
&myinfo->del_set, "del-set");
break;
}
return 1;
}
static void
print_target_v0(const char *prefix, const struct xt_set_info_v0 *info)
{
int i;
char setname[IPSET_MAXNAMELEN];
if (info->index == IPSET_INVALID_ID)
return;
get_set_byid(setname, info->index);
printf(" %s %s", prefix, setname);
for (i = 0; i < IPSET_DIM_MAX; i++) {
if (!info->u.flags[i])
break;
printf("%s%s",
i == 0 ? " " : ",",
info->u.flags[i] & IPSET_SRC ? "src" : "dst");
}
}
static void
set_target_print_v0(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_set_info_target_v0 *info = (const void *)target->data;
print_target_v0("add-set", &info->add_set);
print_target_v0("del-set", &info->del_set);
}
static void
set_target_save_v0(const void *ip, const struct xt_entry_target *target)
{
const struct xt_set_info_target_v0 *info = (const void *)target->data;
print_target_v0("--add-set", &info->add_set);
print_target_v0("--del-set", &info->del_set);
}
/* Revision 1 */
static void
set_target_init_v1(struct xt_entry_target *target)
{
struct xt_set_info_target_v1 *info =
(struct xt_set_info_target_v1 *) target->data;
info->add_set.index =
info->del_set.index = IPSET_INVALID_ID;
}
#define SET_TARGET_ADD 0x1
#define SET_TARGET_DEL 0x2
#define SET_TARGET_EXIST 0x4
#define SET_TARGET_TIMEOUT 0x8
static void
parse_target(char **argv, int invert, struct xt_set_info *info,
const char *what)
{
if (info->dim)
xtables_error(PARAMETER_PROBLEM,
"--%s can be specified only once", what);
if (!argv[optind]
|| argv[optind][0] == '-' || argv[optind][0] == '!')
xtables_error(PARAMETER_PROBLEM,
"--%s requires two args.", what);
if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
xtables_error(PARAMETER_PROBLEM,
"setname `%s' too long, max %d characters.",
optarg, IPSET_MAXNAMELEN - 1);
get_set_byname(optarg, info);
parse_dirs(argv[optind], info);
optind++;
}
static int
set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_set_info_target_v1 *myinfo =
(struct xt_set_info_target_v1 *) (*target)->data;
switch (c) {
case '1': /* --add-set <set> <flags> */
parse_target(argv, invert, &myinfo->add_set, "add-set");
*flags |= SET_TARGET_ADD;
break;
case '2': /* --del-set <set>[:<flags>] <flags> */
parse_target(argv, invert, &myinfo->del_set, "del-set");
*flags |= SET_TARGET_DEL;
break;
}
return 1;
}
static void
print_target(const char *prefix, const struct xt_set_info *info)
{
int i;
char setname[IPSET_MAXNAMELEN];
if (info->index == IPSET_INVALID_ID)
return;
get_set_byid(setname, info->index);
printf(" %s %s", prefix, setname);
for (i = 1; i <= info->dim; i++) {
printf("%s%s",
i == 1 ? " " : ",",
info->flags & (1 << i) ? "src" : "dst");
}
}
static void
set_target_print_v1(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_set_info_target_v1 *info = (const void *)target->data;
print_target("add-set", &info->add_set);
print_target("del-set", &info->del_set);
}
static void
set_target_save_v1(const void *ip, const struct xt_entry_target *target)
{
const struct xt_set_info_target_v1 *info = (const void *)target->data;
print_target("--add-set", &info->add_set);
print_target("--del-set", &info->del_set);
}
/* Revision 2 */
static void
set_target_help_v2(void)
{
printf("SET target options:\n"
" --add-set name flags [--exist] [--timeout n]\n"
" --del-set name flags\n"
" add/del src/dst IP/port from/to named sets,\n"
" where flags are the comma separated list of\n"
" 'src' and 'dst' specifications.\n");
}
static const struct option set_target_opts_v2[] = {
{.name = "add-set", .has_arg = true, .val = '1'},
{.name = "del-set", .has_arg = true, .val = '2'},
{.name = "exist", .has_arg = false, .val = '3'},
{.name = "timeout", .has_arg = true, .val = '4'},
XT_GETOPT_TABLEEND,
};
static void
set_target_check_v2(unsigned int flags)
{
if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL)))
xtables_error(PARAMETER_PROBLEM,
"You must specify either `--add-set' or `--del-set'");
if (!(flags & SET_TARGET_ADD)) {
if (flags & SET_TARGET_EXIST)
xtables_error(PARAMETER_PROBLEM,
"Flag `--exist' can be used with `--add-set' only");
if (flags & SET_TARGET_TIMEOUT)
xtables_error(PARAMETER_PROBLEM,
"Option `--timeout' can be used with `--add-set' only");
}
}
static void
set_target_init_v2(struct xt_entry_target *target)
{
struct xt_set_info_target_v2 *info =
(struct xt_set_info_target_v2 *) target->data;
info->add_set.index =
info->del_set.index = IPSET_INVALID_ID;
info->timeout = UINT32_MAX;
}
static int
set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_set_info_target_v2 *myinfo =
(struct xt_set_info_target_v2 *) (*target)->data;
unsigned int timeout;
switch (c) {
case '1': /* --add-set <set> <flags> */
parse_target(argv, invert, &myinfo->add_set, "add-set");
*flags |= SET_TARGET_ADD;
break;
case '2': /* --del-set <set>[:<flags>] <flags> */
parse_target(argv, invert, &myinfo->del_set, "del-set");
*flags |= SET_TARGET_DEL;
break;
case '3':
myinfo->flags |= IPSET_FLAG_EXIST;
*flags |= SET_TARGET_EXIST;
break;
case '4':
if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1))
xtables_error(PARAMETER_PROBLEM,
"Invalid value for option --timeout "
"or out of range 0-%u", UINT32_MAX - 1);
myinfo->timeout = timeout;
*flags |= SET_TARGET_TIMEOUT;
break;
}
return 1;
}
static void
set_target_print_v2(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_set_info_target_v2 *info = (const void *)target->data;
print_target("add-set", &info->add_set);
if (info->flags & IPSET_FLAG_EXIST)
printf(" exist");
if (info->timeout != UINT32_MAX)
printf(" timeout %u", info->timeout);
print_target("del-set", &info->del_set);
}
static void
set_target_save_v2(const void *ip, const struct xt_entry_target *target)
{
const struct xt_set_info_target_v2 *info = (const void *)target->data;
print_target("--add-set", &info->add_set);
if (info->flags & IPSET_FLAG_EXIST)
printf(" --exist");
if (info->timeout != UINT32_MAX)
printf(" --timeout %u", info->timeout);
print_target("--del-set", &info->del_set);
}
static struct xtables_target set_tg_reg[] = {
{
.name = "SET",
.revision = 0,
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
.userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)),
.help = set_target_help_v0,
.init = set_target_init_v0,
.parse = set_target_parse_v0,
.final_check = set_target_check_v0,
.print = set_target_print_v0,
.save = set_target_save_v0,
.extra_opts = set_target_opts_v0,
},
{
.name = "SET",
.revision = 1,
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v1)),
.help = set_target_help_v0,
.init = set_target_init_v1,
.parse = set_target_parse_v1,
.final_check = set_target_check_v0,
.print = set_target_print_v1,
.save = set_target_save_v1,
.extra_opts = set_target_opts_v0,
},
{
.name = "SET",
.revision = 2,
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
.userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v2)),
.help = set_target_help_v2,
.init = set_target_init_v2,
.parse = set_target_parse_v2,
.final_check = set_target_check_v2,
.print = set_target_print_v2,
.save = set_target_save_v2,
.extra_opts = set_target_opts_v2,
},
};
void _init(void)
{
xtables_register_targets(set_tg_reg, ARRAY_SIZE(set_tg_reg));
}
This module adds and/or deletes entries from IP sets which can be defined
by ipset(8).
.TP
\fB\-\-add\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
add the address(es)/port(s) of the packet to the set
.TP
\fB\-\-del\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...]
delete the address(es)/port(s) of the packet from the set
.IP
where \fIflag\fP(s) are
.BR "src"
and/or
.BR "dst"
specifications and there can be no more than six of them.
.TP
\fB\-\-timeout\fP \fIvalue\fP
when adding an entry, the timeout value to use instead of the default
one from the set definition
.TP
\fB\-\-exist\fP
when adding an entry if it already exists, reset the timeout value
to the specified one or to the default from the set definition
.PP
Use of -j SET requires that ipset kernel support is provided, which, for
standard kernels, is the case since Linux 2.6.39.
This target is only valid in the
.B nat
table, in the
.B POSTROUTING
and
.B INPUT
chains, and user-defined chains which are only called from those
chains. It specifies that the source address of the packet should be
modified (and all future packets in this connection will also be
mangled), and rules should cease being examined. It takes the
following options:
.TP
\fB\-\-to\-source\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]]
which can specify a single new source IP address, an inclusive range
of IP addresses. Optionally a port range,
if the rule also specifies one of the following protocols:
\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP.
If no port range is specified, then source ports below 512 will be
mapped to other ports below 512: those between 512 and 1023 inclusive
will be mapped to ports below 1024, and other ports will be mapped to
1024 or above. Where possible, no port alteration will occur.
In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those
kernels, if you specify more than one source address, either via an address
range or multiple \-\-to\-source options, a simple round-robin (one after another
in cycle) takes place between these addresses.
Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
anymore.
.TP
\fB\-\-random\fP
If option
\fB\-\-random\fP
is used then port mapping will be randomized (kernel >= 2.6.21).
.TP
\fB\-\-persistent\fP
Gives a client the same source-/destination-address for each connection.
This supersedes the SAME target. Support for persistent mappings is available
from 2.6.29-rc2.
.PP
Kernels prior to 2.6.36-rc1 don't have the ability to
.B SNAT
in the
.B INPUT
chain.
.TP
IPv6 support available since Linux kernels >= 3.7.
/*
* Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdbool.h>
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter/xt_SYNPROXY.h>
enum {
O_SACK_PERM = 0,
O_TIMESTAMP,
O_WSCALE,
O_MSS,
O_ECN,
};
static void SYNPROXY_help(void)
{
printf(
"SYNPROXY target options:\n"
" --sack-perm Set SACK_PERM\n"
" --timestamp Set TIMESTAMP\n"
" --wscale value Set window scaling factor\n"
" --mss value Set MSS value\n"
" --ecn Set ECN\n");
}
static const struct xt_option_entry SYNPROXY_opts[] = {
{.name = "sack-perm", .id = O_SACK_PERM, .type = XTTYPE_NONE, },
{.name = "timestamp", .id = O_TIMESTAMP, .type = XTTYPE_NONE, },
{.name = "wscale", .id = O_WSCALE, .type = XTTYPE_UINT32, },
{.name = "mss", .id = O_MSS, .type = XTTYPE_UINT32, },
{.name = "ecn", .id = O_ECN, .type = XTTYPE_NONE, },
XTOPT_TABLEEND,
};
static void SYNPROXY_parse(struct xt_option_call *cb)
{
struct xt_synproxy_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SACK_PERM:
info->options |= XT_SYNPROXY_OPT_SACK_PERM;
break;
case O_TIMESTAMP:
info->options |= XT_SYNPROXY_OPT_TIMESTAMP;
break;
case O_WSCALE:
info->options |= XT_SYNPROXY_OPT_WSCALE;
info->wscale = cb->val.u32;
break;
case O_MSS:
info->options |= XT_SYNPROXY_OPT_MSS;
info->mss = cb->val.u32;
break;
case O_ECN:
info->options |= XT_SYNPROXY_OPT_ECN;
break;
}
}
static void SYNPROXY_check(struct xt_fcheck_call *cb)
{
}
static void SYNPROXY_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_synproxy_info *info =
(const struct xt_synproxy_info *)target->data;
printf(" SYNPROXY ");
if (info->options & XT_SYNPROXY_OPT_SACK_PERM)
printf("sack-perm ");
if (info->options & XT_SYNPROXY_OPT_TIMESTAMP)
printf("timestamp ");
if (info->options & XT_SYNPROXY_OPT_WSCALE)
printf("wscale %u ", info->wscale);
if (info->options & XT_SYNPROXY_OPT_MSS)
printf("mss %u ", info->mss);
if (info->options & XT_SYNPROXY_OPT_ECN)
printf("ecn ");
}
static void SYNPROXY_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_synproxy_info *info =
(const struct xt_synproxy_info *)target->data;
if (info->options & XT_SYNPROXY_OPT_SACK_PERM)
printf(" --sack-perm");
if (info->options & XT_SYNPROXY_OPT_TIMESTAMP)
printf(" --timestamp");
if (info->options & XT_SYNPROXY_OPT_WSCALE)
printf(" --wscale %u", info->wscale);
if (info->options & XT_SYNPROXY_OPT_MSS)
printf(" --mss %u", info->mss);
if (info->options & XT_SYNPROXY_OPT_ECN)
printf(" --ecn");
}
static struct xtables_target synproxy_tg_reg = {
.family = NFPROTO_UNSPEC,
.name = "SYNPROXY",
.version = XTABLES_VERSION,
.revision = 0,
.size = XT_ALIGN(sizeof(struct xt_synproxy_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_synproxy_info)),
.help = SYNPROXY_help,
.print = SYNPROXY_print,
.save = SYNPROXY_save,
.x6_parse = SYNPROXY_parse,
.x6_fcheck = SYNPROXY_check,
.x6_options = SYNPROXY_opts,
};
void _init(void)
{
xtables_register_target(&synproxy_tg_reg);
}
/* Shared library add-on to iptables to add TCPMSS target support.
*
* Copyright (c) 2000 Marc Boucher
*/
#include "config.h"
#include <stdio.h>
#include <xtables.h>
#include <netinet/ip.h>
#include <linux/netfilter/xt_TCPMSS.h>
enum {
O_SET_MSS = 0,
O_CLAMP_MSS,
};
struct mssinfo {
struct xt_entry_target t;
struct xt_tcpmss_info mss;
};
static void __TCPMSS_help(int hdrsize)
{
printf(
"TCPMSS target mutually-exclusive options:\n"
" --set-mss value explicitly set MSS option to specified value\n"
" --clamp-mss-to-pmtu automatically clamp MSS value to (path_MTU - %d)\n",
hdrsize);
}
static void TCPMSS_help(void)
{
__TCPMSS_help(sizeof(struct iphdr));
}
static void TCPMSS_help6(void)
{
__TCPMSS_help(SIZEOF_STRUCT_IP6_HDR);
}
static const struct xt_option_entry TCPMSS4_opts[] = {
{.name = "set-mss", .id = O_SET_MSS, .type = XTTYPE_UINT16,
.min = 0, .max = UINT16_MAX - sizeof(struct iphdr),
.flags = XTOPT_PUT, XTOPT_POINTER(struct xt_tcpmss_info, mss)},
{.name = "clamp-mss-to-pmtu", .id = O_CLAMP_MSS, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static const struct xt_option_entry TCPMSS6_opts[] = {
{.name = "set-mss", .id = O_SET_MSS, .type = XTTYPE_UINT16,
.min = 0, .max = UINT16_MAX - SIZEOF_STRUCT_IP6_HDR,
.flags = XTOPT_PUT, XTOPT_POINTER(struct xt_tcpmss_info, mss)},
{.name = "clamp-mss-to-pmtu", .id = O_CLAMP_MSS, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static void TCPMSS_parse(struct xt_option_call *cb)
{
struct xt_tcpmss_info *mssinfo = cb->data;
xtables_option_parse(cb);
if (cb->entry->id == O_CLAMP_MSS)
mssinfo->mss = XT_TCPMSS_CLAMP_PMTU;
}
static void TCPMSS_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
xtables_error(PARAMETER_PROBLEM,
"TCPMSS target: At least one parameter is required");
}
static void TCPMSS_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tcpmss_info *mssinfo =
(const struct xt_tcpmss_info *)target->data;
if(mssinfo->mss == XT_TCPMSS_CLAMP_PMTU)
printf(" TCPMSS clamp to PMTU");
else
printf(" TCPMSS set %u", mssinfo->mss);
}
static void TCPMSS_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tcpmss_info *mssinfo =
(const struct xt_tcpmss_info *)target->data;
if(mssinfo->mss == XT_TCPMSS_CLAMP_PMTU)
printf(" --clamp-mss-to-pmtu");
else
printf(" --set-mss %u", mssinfo->mss);
}
static struct xtables_target tcpmss_tg_reg[] = {
{
.family = NFPROTO_IPV4,
.name = "TCPMSS",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_tcpmss_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_info)),
.help = TCPMSS_help,
.print = TCPMSS_print,
.save = TCPMSS_save,
.x6_parse = TCPMSS_parse,
.x6_fcheck = TCPMSS_check,
.x6_options = TCPMSS4_opts,
},
{
.family = NFPROTO_IPV6,
.name = "TCPMSS",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_tcpmss_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_info)),
.help = TCPMSS_help6,
.print = TCPMSS_print,
.save = TCPMSS_save,
.x6_parse = TCPMSS_parse,
.x6_fcheck = TCPMSS_check,
.x6_options = TCPMSS6_opts,
},
};
void _init(void)
{
xtables_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
}
This target allows to alter the MSS value of TCP SYN packets, to control
the maximum size for that connection (usually limiting it to your
outgoing interface's MTU minus 40 for IPv4 or 60 for IPv6, respectively).
Of course, it can only be used
in conjunction with
\fB\-p tcp\fP.
.PP
This target is used to overcome criminally braindead ISPs or servers
which block "ICMP Fragmentation Needed" or "ICMPv6 Packet Too Big"
packets. The symptoms of this
problem are that everything works fine from your Linux
firewall/router, but machines behind it can never exchange large
packets:
.IP 1. 4
Web browsers connect, then hang with no data received.
.IP 2. 4
Small mail works fine, but large emails hang.
.IP 3. 4
ssh works fine, but scp hangs after initial handshaking.
.PP
Workaround: activate this option and add a rule to your firewall
configuration like:
.IP
iptables \-t mangle \-A FORWARD \-p tcp \-\-tcp\-flags SYN,RST SYN
\-j TCPMSS \-\-clamp\-mss\-to\-pmtu
.TP
\fB\-\-set\-mss\fP \fIvalue\fP
Explicitly sets MSS option to specified value. If the MSS of the packet is
already lower than \fIvalue\fP, it will \fBnot\fP be increased (from Linux
2.6.25 onwards) to avoid more problems with hosts relying on a proper MSS.
.TP
\fB\-\-clamp\-mss\-to\-pmtu\fP
Automatically clamp MSS value to (path_MTU \- 40 for IPv4; \-60 for IPv6).
This may not function as desired where asymmetric routes with differing
path MTU exist \(em the kernel uses the path MTU which it would use to send
packets from itself to the source and destination IP addresses. Prior to
Linux 2.6.25, only the path MTU to the destination IP address was
considered by this option; subsequent kernels also consider the path MTU
to the source IP address.
.PP
These options are mutually exclusive.
/*
* 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);
}
This target will strip TCP options off a TCP packet. (It will actually replace
them by NO-OPs.) As such, you will need to add the \fB\-p tcp\fP parameters.
.TP
\fB\-\-strip\-options\fP \fIoption\fP[\fB,\fP\fIoption\fP...]
Strip the given option(s). The options may be specified by TCP option number or
by symbolic name. The list of recognized options can be obtained by calling
iptables with \fB\-j TCPOPTSTRIP \-h\fP.
/*
* "TEE" target extension for iptables
* Copyright © Sebastian Claßen <sebastian.classen [at] freenet.ag>, 2007
* Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2010
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <sys/socket.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <xtables.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_TEE.h>
enum {
O_GATEWAY = 0,
O_OIF,
};
#define s struct xt_tee_tginfo
static const struct xt_option_entry tee_tg_opts[] = {
{.name = "gateway", .id = O_GATEWAY, .type = XTTYPE_HOST,
.flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, gw)},
{.name = "oif", .id = O_OIF, .type = XTTYPE_STRING,
.flags = XTOPT_PUT, XTOPT_POINTER(s, oif)},
XTOPT_TABLEEND,
};
#undef s
static void tee_tg_help(void)
{
printf(
"TEE target options:\n"
" --gateway IPADDR Route packet via the gateway given by address\n"
" --oif NAME Include oif in route calculation\n"
"\n");
}
static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
if (numeric)
printf(" TEE gw:%s", xtables_ipaddr_to_numeric(&info->gw.in));
else
printf(" TEE gw:%s", xtables_ipaddr_to_anyname(&info->gw.in));
if (*info->oif != '\0')
printf(" oif=%s", info->oif);
}
static void tee_tg6_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
if (numeric)
printf(" TEE gw:%s", xtables_ip6addr_to_numeric(&info->gw.in6));
else
printf(" TEE gw:%s", xtables_ip6addr_to_anyname(&info->gw.in6));
if (*info->oif != '\0')
printf(" oif=%s", info->oif);
}
static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
printf(" --gateway %s", xtables_ipaddr_to_numeric(&info->gw.in));
if (*info->oif != '\0')
printf(" --oif %s", info->oif);
}
static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
printf(" --gateway %s", xtables_ip6addr_to_numeric(&info->gw.in6));
if (*info->oif != '\0')
printf(" --oif %s", info->oif);
}
static struct xtables_target tee_tg_reg[] = {
{
.name = "TEE",
.version = XTABLES_VERSION,
.revision = 1,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.help = tee_tg_help,
.print = tee_tg_print,
.save = tee_tg_save,
.x6_parse = xtables_option_parse,
.x6_options = tee_tg_opts,
},
{
.name = "TEE",
.version = XTABLES_VERSION,
.revision = 1,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.help = tee_tg_help,
.print = tee_tg6_print,
.save = tee_tg6_save,
.x6_parse = xtables_option_parse,
.x6_options = tee_tg_opts,
},
};
void _init(void)
{
xtables_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
}
The \fBTEE\fP target will clone a packet and redirect this clone to another
machine on the \fBlocal\fP network segment. In other words, the nexthop
must be the target, or you will have to configure the nexthop to forward it
further if so desired.
.TP
\fB\-\-gateway\fP \fIipaddr\fP
Send the cloned packet to the host reachable at the given IP address.
Use of 0.0.0.0 (for IPv4 packets) or :: (IPv6) is invalid.
.PP
To forward all incoming traffic on eth0 to an Network Layer logging box:
.PP
\-t mangle \-A PREROUTING \-i eth0 \-j TEE \-\-gateway 2001:db8::1
/*
* Shared library add-on to iptables to add TOS target support
*
* Copyright © CC Computer Consultants GmbH, 2007
* Contact: Jan Engelhardt <jengelh@medozas.de>
*/
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <xtables.h>
#include <linux/netfilter/xt_DSCP.h>
#include "tos_values.c"
struct ipt_tos_target_info {
uint8_t tos;
};
enum {
O_SET_TOS = 0,
O_AND_TOS,
O_OR_TOS,
O_XOR_TOS,
F_SET_TOS = 1 << O_SET_TOS,
F_AND_TOS = 1 << O_AND_TOS,
F_OR_TOS = 1 << O_OR_TOS,
F_XOR_TOS = 1 << O_XOR_TOS,
F_ANY = F_SET_TOS | F_AND_TOS | F_OR_TOS | F_XOR_TOS,
};
static const struct xt_option_entry tos_tg_opts_v0[] = {
{.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK,
.excl = F_ANY, .max = 0xFF},
XTOPT_TABLEEND,
};
static const struct xt_option_entry tos_tg_opts[] = {
{.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK,
.excl = F_ANY, .max = 0x3F},
{.name = "and-tos", .id = O_AND_TOS, .type = XTTYPE_UINT8,
.excl = F_ANY},
{.name = "or-tos", .id = O_OR_TOS, .type = XTTYPE_UINT8,
.excl = F_ANY},
{.name = "xor-tos", .id = O_XOR_TOS, .type = XTTYPE_UINT8,
.excl = F_ANY},
XTOPT_TABLEEND,
};
static void tos_tg_help_v0(void)
{
const struct tos_symbol_info *symbol;
printf(
"TOS target options:\n"
" --set-tos value Set Type of Service/Priority field to value\n"
" --set-tos symbol Set TOS field (IPv4 only) by symbol\n"
" Accepted symbolic names for value are:\n");
for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
printf(" (0x%02x) %2u %s\n",
symbol->value, symbol->value, symbol->name);
printf("\n");
}
static void tos_tg_help(void)
{
const struct tos_symbol_info *symbol;
printf(
"TOS target v%s options:\n"
" --set-tos value[/mask] Set Type of Service/Priority field to value\n"
" (Zero out bits in mask and XOR value into TOS)\n"
" --set-tos symbol Set TOS field (IPv4 only) by symbol\n"
" (this zeroes the 4-bit Precedence part!)\n"
" Accepted symbolic names for value are:\n",
XTABLES_VERSION);
for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol)
printf(" (0x%02x) %2u %s\n",
symbol->value, symbol->value, symbol->name);
printf(
"\n"
" --and-tos bits Binary AND the TOS value with bits\n"
" --or-tos bits Binary OR the TOS value with bits\n"
" --xor-tos bits Binary XOR the TOS value with bits\n"
);
}
static void tos_tg_parse_v0(struct xt_option_call *cb)
{
struct ipt_tos_target_info *info = cb->data;
xtables_option_parse(cb);
if (cb->val.tos_mask != 0xFF)
xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel "
"is too old to support anything besides "
"/0xFF as a mask.");
info->tos = cb->val.tos_value;
}
static void tos_tg_parse(struct xt_option_call *cb)
{
struct xt_tos_target_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SET_TOS:
info->tos_value = cb->val.tos_value;
info->tos_mask = cb->val.tos_mask;
break;
case O_AND_TOS:
info->tos_value = 0;
info->tos_mask = ~cb->val.u8;
break;
case O_OR_TOS:
info->tos_value = cb->val.u8;
info->tos_mask = cb->val.u8;
break;
case O_XOR_TOS:
info->tos_value = cb->val.u8;
info->tos_mask = 0;
break;
}
}
static void tos_tg_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_ANY))
xtables_error(PARAMETER_PROBLEM,
"TOS: An action is required");
}
static void tos_tg_print_v0(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct ipt_tos_target_info *info = (const void *)target->data;
printf(" TOS set ");
if (numeric || !tos_try_print_symbolic("", info->tos, 0xFF))
printf("0x%02x", info->tos);
}
static void tos_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tos_target_info *info = (const void *)target->data;
if (numeric)
printf(" TOS set 0x%02x/0x%02x",
info->tos_value, info->tos_mask);
else if (tos_try_print_symbolic(" TOS set",
info->tos_value, info->tos_mask))
/* already printed by call */
return;
else if (info->tos_value == 0)
printf(" TOS and 0x%02x",
(unsigned int)(uint8_t)~info->tos_mask);
else if (info->tos_value == info->tos_mask)
printf(" TOS or 0x%02x", info->tos_value);
else if (info->tos_mask == 0)
printf(" TOS xor 0x%02x", info->tos_value);
else
printf(" TOS set 0x%02x/0x%02x",
info->tos_value, info->tos_mask);
}
static void tos_tg_save_v0(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_tos_target_info *info = (const void *)target->data;
printf(" --set-tos 0x%02x", info->tos);
}
static void tos_tg_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tos_target_info *info = (const void *)target->data;
printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask);
}
static struct xtables_target tos_tg_reg[] = {
{
.version = XTABLES_VERSION,
.name = "TOS",
.revision = 0,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_tos_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
.help = tos_tg_help_v0,
.print = tos_tg_print_v0,
.save = tos_tg_save_v0,
.x6_parse = tos_tg_parse_v0,
.x6_fcheck = tos_tg_check,
.x6_options = tos_tg_opts_v0,
},
{
.version = XTABLES_VERSION,
.name = "TOS",
.revision = 1,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_tos_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)),
.help = tos_tg_help,
.print = tos_tg_print,
.save = tos_tg_save,
.x6_parse = tos_tg_parse,
.x6_fcheck = tos_tg_check,
.x6_options = tos_tg_opts,
},
};
void _init(void)
{
xtables_register_targets(tos_tg_reg, ARRAY_SIZE(tos_tg_reg));
}
This module sets the Type of Service field in the IPv4 header (including the
"precedence" bits) or the Priority field in the IPv6 header. Note that TOS
shares the same bits as DSCP and ECN. The TOS target is only valid in the
\fBmangle\fP table.
.TP
\fB\-\-set\-tos\fP \fIvalue\fP[\fB/\fP\fImask\fP]
Zeroes out the bits given by \fImask\fP (see NOTE below) and XORs \fIvalue\fP
into the TOS/Priority field. If \fImask\fP is omitted, 0xFF is assumed.
.TP
\fB\-\-set\-tos\fP \fIsymbol\fP
You can specify a symbolic name when using the TOS target for IPv4. It implies
a mask of 0xFF (see NOTE below). The list of recognized TOS names can be
obtained by calling iptables with \fB\-j TOS \-h\fP.
.PP
The following mnemonics are available:
.TP
\fB\-\-and\-tos\fP \fIbits\fP
Binary AND the TOS value with \fIbits\fP. (Mnemonic for \fB\-\-set\-tos
0/\fP\fIinvbits\fP, where \fIinvbits\fP is the binary negation of \fIbits\fP.
See NOTE below.)
.TP
\fB\-\-or\-tos\fP \fIbits\fP
Binary OR the TOS value with \fIbits\fP. (Mnemonic for \fB\-\-set\-tos\fP
\fIbits\fP\fB/\fP\fIbits\fP. See NOTE below.)
.TP
\fB\-\-xor\-tos\fP \fIbits\fP
Binary XOR the TOS value with \fIbits\fP. (Mnemonic for \fB\-\-set\-tos\fP
\fIbits\fP\fB/0\fP. See NOTE below.)
.PP
NOTE: In Linux kernels up to and including 2.6.38, with the exception of
longterm releases 2.6.32 (>=.42), 2.6.33 (>=.15), and 2.6.35 (>=.14), there is
a bug whereby IPv6 TOS mangling does not behave as documented and differs from
the IPv4 version. The TOS mask indicates the bits one wants to zero out, so it
needs to be inverted before applying it to the original TOS field. However, the
aformentioned kernels forgo the inversion which breaks --set-tos and its
mnemonics.
/*
* shared library add-on to iptables to add TPROXY target support.
*
* Copyright (C) 2002-2008 BalaBit IT Ltd.
*/
#include <stdio.h>
#include <limits.h>
#include <xtables.h>
#include <linux/netfilter/xt_TPROXY.h>
#include <arpa/inet.h>
enum {
P_PORT = 0,
P_ADDR,
P_MARK,
F_PORT = 1 << P_PORT,
F_ADDR = 1 << P_ADDR,
F_MARK = 1 << P_MARK,
};
#define s struct xt_tproxy_target_info
static const struct xt_option_entry tproxy_tg0_opts[] = {
{.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT,
.flags = XTOPT_MAND | XTOPT_NBO | XTOPT_PUT, XTOPT_POINTER(s, lport)},
{.name = "on-ip", .id = P_ADDR, .type = XTTYPE_HOST},
{.name = "tproxy-mark", .id = P_MARK, .type = XTTYPE_MARKMASK32},
XTOPT_TABLEEND,
};
#undef s
#define s struct xt_tproxy_target_info_v1
static const struct xt_option_entry tproxy_tg1_opts[] = {
{.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT,
.flags = XTOPT_MAND | XTOPT_NBO | XTOPT_PUT, XTOPT_POINTER(s, lport)},
{.name = "on-ip", .id = P_ADDR, .type = XTTYPE_HOST,
.flags = XTOPT_PUT, XTOPT_POINTER(s, laddr)},
{.name = "tproxy-mark", .id = P_MARK, .type = XTTYPE_MARKMASK32},
XTOPT_TABLEEND,
};
#undef s
static void tproxy_tg_help(void)
{
printf(
"TPROXY target options:\n"
" --on-port port Redirect connection to port, or the original port if 0\n"
" --on-ip ip Optionally redirect to the given IP\n"
" --tproxy-mark value[/mask] Mark packets with the given value/mask\n\n");
}
static void tproxy_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tproxy_target_info *info = (const void *)target->data;
printf(" TPROXY redirect %s:%u mark 0x%x/0x%x",
xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr),
ntohs(info->lport), (unsigned int)info->mark_value,
(unsigned int)info->mark_mask);
}
static void
tproxy_tg_print4(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tproxy_target_info_v1 *info =
(const void *)target->data;
printf(" TPROXY redirect %s:%u mark 0x%x/0x%x",
xtables_ipaddr_to_numeric(&info->laddr.in),
ntohs(info->lport), (unsigned int)info->mark_value,
(unsigned int)info->mark_mask);
}
static void
tproxy_tg_print6(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tproxy_target_info_v1 *info =
(const void *)target->data;
printf(" TPROXY redirect %s:%u mark 0x%x/0x%x",
xtables_ip6addr_to_numeric(&info->laddr.in6),
ntohs(info->lport), (unsigned int)info->mark_value,
(unsigned int)info->mark_mask);
}
static void tproxy_tg_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tproxy_target_info *info = (const void *)target->data;
printf(" --on-port %u", ntohs(info->lport));
printf(" --on-ip %s",
xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr));
printf(" --tproxy-mark 0x%x/0x%x",
(unsigned int)info->mark_value, (unsigned int)info->mark_mask);
}
static void
tproxy_tg_save4(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tproxy_target_info_v1 *info;
info = (const void *)target->data;
printf(" --on-port %u", ntohs(info->lport));
printf(" --on-ip %s", xtables_ipaddr_to_numeric(&info->laddr.in));
printf(" --tproxy-mark 0x%x/0x%x",
(unsigned int)info->mark_value, (unsigned int)info->mark_mask);
}
static void
tproxy_tg_save6(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tproxy_target_info_v1 *info;
info = (const void *)target->data;
printf(" --on-port %u", ntohs(info->lport));
printf(" --on-ip %s", xtables_ip6addr_to_numeric(&info->laddr.in6));
printf(" --tproxy-mark 0x%x/0x%x",
(unsigned int)info->mark_value, (unsigned int)info->mark_mask);
}
static void tproxy_tg0_parse(struct xt_option_call *cb)
{
struct xt_tproxy_target_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case P_MARK:
info->mark_value = cb->val.mark;
info->mark_mask = cb->val.mask;
break;
case P_ADDR:
info->laddr = cb->val.haddr.ip;
break;
}
}
static void tproxy_tg1_parse(struct xt_option_call *cb)
{
struct xt_tproxy_target_info_v1 *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case P_MARK:
info->mark_value = cb->val.mark;
info->mark_mask = cb->val.mask;
break;
}
}
static struct xtables_target tproxy_tg_reg[] = {
{
.name = "TPROXY",
.revision = 0,
.family = NFPROTO_IPV4,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_tproxy_target_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info)),
.help = tproxy_tg_help,
.print = tproxy_tg_print,
.save = tproxy_tg_save,
.x6_options = tproxy_tg0_opts,
.x6_parse = tproxy_tg0_parse,
},
{
.name = "TPROXY",
.revision = 1,
.family = NFPROTO_IPV4,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
.help = tproxy_tg_help,
.print = tproxy_tg_print4,
.save = tproxy_tg_save4,
.x6_options = tproxy_tg1_opts,
.x6_parse = tproxy_tg1_parse,
},
{
.name = "TPROXY",
.revision = 1,
.family = NFPROTO_IPV6,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)),
.help = tproxy_tg_help,
.print = tproxy_tg_print6,
.save = tproxy_tg_save6,
.x6_options = tproxy_tg1_opts,
.x6_parse = tproxy_tg1_parse,
},
};
void _init(void)
{
xtables_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
}
This target is only valid in the \fBmangle\fP table, in the \fBPREROUTING\fP
chain and user-defined chains which are only called from this chain. It
redirects the packet to a local socket without changing the packet header in
any way. It can also change the mark value which can then be used in advanced
routing rules.
It takes three options:
.TP
\fB\-\-on\-port\fP \fIport\fP
This specifies a destination port to use. It is a required option, 0 means the
new destination port is the same as the original. This is only valid if the
rule also specifies \fB\-p tcp\fP or \fB\-p udp\fP.
.TP
\fB\-\-on\-ip\fP \fIaddress\fP
This specifies a destination address to use. By default the address is the IP
address of the incoming interface. This is only valid if the rule also
specifies \fB\-p tcp\fP or \fB\-p udp\fP.
.TP
\fB\-\-tproxy\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP]
Marks packets with the given value/mask. The fwmark value set here can be used
by advanced routing. (Required for transparent proxying to work: otherwise
these packets will get forwarded, which is probably not what you want.)
/* Shared library add-on to iptables to add TRACE target support. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter/x_tables.h>
static struct xtables_target trace_target = {
.family = NFPROTO_UNSPEC,
.name = "TRACE",
.version = XTABLES_VERSION,
.size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0),
};
void _init(void)
{
xtables_register_target(&trace_target);
}
This target marks packets so that the kernel will log every rule which match
the packets as those traverse the tables, chains, rules.
.PP
A logging backend, such as ip(6)t_LOG or nfnetlink_log, must be loaded for this
to be visible.
The packets are logged with the string prefix:
"TRACE: tablename:chainname:type:rulenum " where type can be "rule" for
plain rule, "return" for implicit rule at the end of a user defined chain
and "policy" for the policy of the built in chains.
.br
It can only be used in the
.BR raw
table.
/* Shared library add-on to iptables to add addrtype matching support
*
* Copyright (c) 2003-2013 Patrick McHardy <kaber@trash.net>
*
* This program is released under the terms of GNU GPL */
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter/xt_addrtype.h>
enum {
O_SRC_TYPE = 0,
O_DST_TYPE,
O_LIMIT_IFACE_IN,
O_LIMIT_IFACE_OUT,
F_SRC_TYPE = 1 << O_SRC_TYPE,
F_DST_TYPE = 1 << O_DST_TYPE,
F_LIMIT_IFACE_IN = 1 << O_LIMIT_IFACE_IN,
F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
};
/* from linux/rtnetlink.h, must match order of enumeration */
static const char *const rtn_names[] = {
"UNSPEC",
"UNICAST",
"LOCAL",
"BROADCAST",
"ANYCAST",
"MULTICAST",
"BLACKHOLE",
"UNREACHABLE",
"PROHIBIT",
"THROW",
"NAT",
"XRESOLVE",
NULL
};
static void addrtype_help_types(void)
{
int i;
for (i = 0; rtn_names[i]; i++)
printf(" %s\n", rtn_names[i]);
}
static void addrtype_help_v0(void)
{
printf(
"Address type match options:\n"
" [!] --src-type type[,...] Match source address type\n"
" [!] --dst-type type[,...] Match destination address type\n"
"\n"
"Valid types: \n");
addrtype_help_types();
}
static void addrtype_help_v1(void)
{
printf(
"Address type match options:\n"
" [!] --src-type type[,...] Match source address type\n"
" [!] --dst-type type[,...] Match destination address type\n"
" --limit-iface-in Match only on the packet's incoming device\n"
" --limit-iface-out Match only on the packet's outgoing device\n"
"\n"
"Valid types: \n");
addrtype_help_types();
}
static int
parse_type(const char *name, size_t len, uint16_t *mask)
{
int i;
for (i = 0; rtn_names[i]; i++)
if (strncasecmp(name, rtn_names[i], len) == 0) {
/* build up bitmask for kernel module */
*mask |= (1 << i);
return 1;
}
return 0;
}
static void parse_types(const char *arg, uint16_t *mask)
{
const char *comma;
while ((comma = strchr(arg, ',')) != NULL) {
if (comma == arg || !parse_type(arg, comma-arg, mask))
xtables_error(PARAMETER_PROBLEM,
"addrtype: bad type `%s'", arg);
arg = comma + 1;
}
if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
}
static void addrtype_parse_v0(struct xt_option_call *cb)
{
struct xt_addrtype_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SRC_TYPE:
parse_types(cb->arg, &info->source);
if (cb->invert)
info->invert_source = 1;
break;
case O_DST_TYPE:
parse_types(cb->arg, &info->dest);
if (cb->invert)
info->invert_dest = 1;
break;
}
}
static void addrtype_parse_v1(struct xt_option_call *cb)
{
struct xt_addrtype_info_v1 *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SRC_TYPE:
parse_types(cb->arg, &info->source);
if (cb->invert)
info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
break;
case O_DST_TYPE:
parse_types(cb->arg, &info->dest);
if (cb->invert)
info->flags |= XT_ADDRTYPE_INVERT_DEST;
break;
case O_LIMIT_IFACE_IN:
info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
break;
case O_LIMIT_IFACE_OUT:
info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
break;
}
}
static void addrtype_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
xtables_error(PARAMETER_PROBLEM,
"addrtype: you must specify --src-type or --dst-type");
}
static void print_types(uint16_t mask)
{
const char *sep = "";
int i;
for (i = 0; rtn_names[i]; i++)
if (mask & (1 << i)) {
printf("%s%s", sep, rtn_names[i]);
sep = ",";
}
}
static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_addrtype_info *info = (const void *)match->data;
printf(" ADDRTYPE match");
if (info->source) {
printf(" src-type ");
if (info->invert_source)
printf("!");
print_types(info->source);
}
if (info->dest) {
printf(" dst-type");
if (info->invert_dest)
printf("!");
print_types(info->dest);
}
}
static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_addrtype_info_v1 *info = (const void *)match->data;
printf(" ADDRTYPE match");
if (info->source) {
printf(" src-type ");
if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
printf("!");
print_types(info->source);
}
if (info->dest) {
printf(" dst-type ");
if (info->flags & XT_ADDRTYPE_INVERT_DEST)
printf("!");
print_types(info->dest);
}
if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
printf(" limit-in");
if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
printf(" limit-out");
}
static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
{
const struct xt_addrtype_info *info = (const void *)match->data;
if (info->source) {
if (info->invert_source)
printf(" !");
printf(" --src-type ");
print_types(info->source);
}
if (info->dest) {
if (info->invert_dest)
printf(" !");
printf(" --dst-type ");
print_types(info->dest);
}
}
static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
{
const struct xt_addrtype_info_v1 *info = (const void *)match->data;
if (info->source) {
if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
printf(" !");
printf(" --src-type ");
print_types(info->source);
}
if (info->dest) {
if (info->flags & XT_ADDRTYPE_INVERT_DEST)
printf(" !");
printf(" --dst-type ");
print_types(info->dest);
}
if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
printf(" --limit-iface-in");
if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
printf(" --limit-iface-out");
}
static const struct xt_option_entry addrtype_opts_v0[] = {
{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
XTOPT_TABLEEND,
};
static const struct xt_option_entry addrtype_opts_v1[] = {
{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
.type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
{.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
.type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
XTOPT_TABLEEND,
};
static struct xtables_match addrtype_mt_reg[] = {
{
.name = "addrtype",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_addrtype_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
.help = addrtype_help_v0,
.print = addrtype_print_v0,
.save = addrtype_save_v0,
.x6_parse = addrtype_parse_v0,
.x6_fcheck = addrtype_check,
.x6_options = addrtype_opts_v0,
},
{
.name = "addrtype",
.revision = 1,
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
.help = addrtype_help_v1,
.print = addrtype_print_v1,
.save = addrtype_save_v1,
.x6_parse = addrtype_parse_v1,
.x6_fcheck = addrtype_check,
.x6_options = addrtype_opts_v1,
},
};
void _init(void)
{
xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment