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

Imported Upstream version 1.4.21

parents
.*.d
.*.dd
*.oo
/GNUmakefile
/initext.c
/initext?.c
/matches.man
/targets.man
# -*- Makefile -*-
top_builddir = @top_builddir@
builddir = @builddir@
top_srcdir = @top_srcdir@
srcdir = @srcdir@
ksourcedir = @ksourcedir@
prefix = @prefix@
exec_prefix = @exec_prefix@
libdir = @libdir@
libexecdir = @libexecdir@
xtlibdir = @xtlibdir@
CC = @CC@
CCLD = ${CC}
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
regular_CFLAGS = @regular_CFLAGS@
regular_CPPFLAGS = @regular_CPPFLAGS@
kinclude_CPPFLAGS = @kinclude_CPPFLAGS@
AM_CFLAGS = ${regular_CFLAGS}
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_builddir} -I${top_srcdir}/include ${kinclude_CPPFLAGS} ${CPPFLAGS}
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
AM_LDFLAGS = @noundef_LDFLAGS@
ifeq (${V},)
AM_LIBTOOL_SILENT = --silent
AM_VERBOSE_CC = @echo " CC " $@;
AM_VERBOSE_CCLD = @echo " CCLD " $@;
AM_VERBOSE_CXX = @echo " CXX " $@;
AM_VERBOSE_CXXLD = @echo " CXXLD " $@;
AM_VERBOSE_AR = @echo " AR " $@;
AM_VERBOSE_GEN = @echo " GEN " $@;
endif
#
# Wildcard module list
#
pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c)))
pfx_symlinks := NOTRACK state
@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c)))
@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c)))
pfx_build_mod := $(filter-out @blacklist_modules@,${pfx_build_mod})
pf4_build_mod := $(filter-out @blacklist_modules@,${pf4_build_mod})
pf6_build_mod := $(filter-out @blacklist_modules@,${pf6_build_mod})
pfx_objs := $(patsubst %,libxt_%.o,${pfx_build_mod})
pf4_objs := $(patsubst %,libipt_%.o,${pf4_build_mod})
pf6_objs := $(patsubst %,libip6t_%.o,${pf6_build_mod})
pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod} ${pfx_symlinks})
pf4_solibs := $(patsubst %,libipt_%.so,${pf4_build_mod})
pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod})
#
# Building blocks
#
targets := libext.a libext4.a libext6.a matches.man targets.man
targets_install :=
@ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs}
@ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs}
@ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs}
@ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
@ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs}
.SECONDARY:
.PHONY: all install clean distclean FORCE
all: ${targets}
install: ${targets_install}
@mkdir -p "${DESTDIR}${xtlibdir}";
if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi;
clean:
rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c;
rm -f .*.d .*.dd;
distclean: clean
init%.o: init%.c
${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<;
-include .*.d
#
# Shared libraries
#
lib%.so: lib%.oo
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $< -L../libxtables/.libs -lxtables ${$*_LIBADD};
lib%.oo: ${srcdir}/lib%.c
${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} ${$*_CFLAGADD} -o $@ -c $<;
libxt_NOTRACK.so: libxt_CT.so
ln -fs $< $@
libxt_state.so: libxt_conntrack.so
ln -fs $< $@
# Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD
xt_RATEEST_LIBADD = -lm
xt_statistic_LIBADD = -lm
@HAVE_LIBNETFILTER_CONNTRACK_TRUE@xt_connlabel_LIBADD = @libnetfilter_conntrack_LIBS@
@HAVE_LIBNETFILTER_CONNTRACK_TRUE@xt_connlabel_CFLAGADD = @libnetfilter_conntrack_CFLAGS@
#
# Static bits
#
# If static building is disabled, libext*.a will still be generated,
# but will be empty. This is good since we can do with less case
# handling code in the Makefiles.
#
lib%.o: ${srcdir}/lib%.c
${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<;
libext.a: initext.o ${libext_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
libext4.a: initext4.o ${libext4_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
libext6.a: initext6.o ${libext6_objs}
${AM_VERBOSE_AR} ${AR} crs $@ $^;
initext_func := $(addprefix xt_,${pfx_build_mod})
initext4_func := $(addprefix ipt_,${pf4_build_mod})
initext6_func := $(addprefix ip6t_,${pf6_build_mod})
.initext.dd: FORCE
@echo "${initext_func}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
.initext4.dd: FORCE
@echo "${initext4_func}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
.initext6.dd: FORCE
@echo "${initext6_func}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
initext.c: .initext.dd
${AM_VERBOSE_GEN}
@( \
echo "" >$@; \
for i in ${initext_func}; do \
echo "extern void lib$${i}_init(void);" >>$@; \
done; \
echo "void init_extensions(void);" >>$@; \
echo "void init_extensions(void)" >>$@; \
echo "{" >>$@; \
for i in ${initext_func}; do \
echo " ""lib$${i}_init();" >>$@; \
done; \
echo "}" >>$@; \
);
initext4.c: .initext4.dd
${AM_VERBOSE_GEN}
@( \
echo "" >$@; \
for i in ${initext4_func}; do \
echo "extern void lib$${i}_init(void);" >>$@; \
done; \
echo "void init_extensions4(void);" >>$@; \
echo "void init_extensions4(void)" >>$@; \
echo "{" >>$@; \
for i in ${initext4_func}; do \
echo " ""lib$${i}_init();" >>$@; \
done; \
echo "}" >>$@; \
);
initext6.c: .initext6.dd
${AM_VERBOSE_GEN}
@( \
echo "" >$@; \
for i in ${initext6_func}; do \
echo "extern void lib$${i}_init(void);" >>$@; \
done; \
echo "void init_extensions6(void);" >>$@; \
echo "void init_extensions6(void)" >>$@; \
echo "{" >>$@; \
for i in ${initext6_func}; do \
echo " ""lib$${i}_init();" >>$@; \
done; \
echo "}" >>$@; \
);
#
# Manual pages
#
ex_matches = $(shell echo ${1} | LC_ALL=POSIX grep -Eo '\b[[:lower:][:digit:]_]+\b')
ex_targets = $(shell echo ${1} | LC_ALL=POSIX grep -Eo '\b[[:upper:][:digit:]_]+\b')
man_run = \
${AM_VERBOSE_GEN} \
for ext in $(sort ${1}); do \
f="${srcdir}/libxt_$$ext.man"; \
if [ -f "$$f" ]; then \
echo -e "\t+ $$f" >&2; \
echo ".SS $$ext"; \
cat "$$f" || exit $$?; \
fi; \
f="${srcdir}/libip6t_$$ext.man"; \
if [ -f "$$f" ]; then \
echo -e "\t+ $$f" >&2; \
echo ".SS $$ext (IPv6-specific)"; \
cat "$$f" || exit $$?; \
fi; \
f="${srcdir}/libipt_$$ext.man"; \
if [ -f "$$f" ]; then \
echo -e "\t+ $$f" >&2; \
echo ".SS $$ext (IPv4-specific)"; \
cat "$$f" || exit $$?; \
fi; \
done >$@;
matches.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
targets.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks}))
/*
* DiffServ classname <-> DiffServ codepoint mapping functions.
*
* The latest list of the mappings can be found at:
* <http://www.iana.org/assignments/dscp-registry>
*
* This code is released under the GNU GPL v2, 1991
*
* Author: Iain Barnes
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
static const struct ds_class
{
const char *name;
unsigned int dscp;
} ds_classes[] =
{
{ "CS0", 0x00 },
{ "CS1", 0x08 },
{ "CS2", 0x10 },
{ "CS3", 0x18 },
{ "CS4", 0x20 },
{ "CS5", 0x28 },
{ "CS6", 0x30 },
{ "CS7", 0x38 },
{ "BE", 0x00 },
{ "AF11", 0x0a },
{ "AF12", 0x0c },
{ "AF13", 0x0e },
{ "AF21", 0x12 },
{ "AF22", 0x14 },
{ "AF23", 0x16 },
{ "AF31", 0x1a },
{ "AF32", 0x1c },
{ "AF33", 0x1e },
{ "AF41", 0x22 },
{ "AF42", 0x24 },
{ "AF43", 0x26 },
{ "EF", 0x2e }
};
static unsigned int
class_to_dscp(const char *name)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ds_classes); i++) {
if (!strncasecmp(name, ds_classes[i].name,
strlen(ds_classes[i].name)))
return ds_classes[i].dscp;
}
xtables_error(PARAMETER_PROBLEM,
"Invalid DSCP value `%s'\n", name);
}
#if 0
static const char *
dscp_to_name(unsigned int dscp)
{
int i;
for (i = 0; i < ARRAY_SIZE(ds_classes); ++i)
if (dscp == ds_classes[i].dscp)
return ds_classes[i].name;
xtables_error(PARAMETER_PROBLEM,
"Invalid DSCP value `%d'\n", dscp);
}
#endif
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT
* funded by Astaro.
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <iptables.h>
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/nf_nat.h>
enum {
O_TO_DEST = 0,
O_RANDOM,
O_PERSISTENT,
O_X_TO_DEST,
F_TO_DEST = 1 << O_TO_DEST,
F_RANDOM = 1 << O_RANDOM,
F_X_TO_DEST = 1 << O_X_TO_DEST,
};
static void DNAT_help(void)
{
printf(
"DNAT target options:\n"
" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map destination to.\n"
"[--random] [--persistent]\n");
}
static const struct xt_option_entry DNAT_opts[] = {
{.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
/* Ranges expected in network order. */
static void
parse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
{
char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
const struct in6_addr *ip;
arg = strdup(orig_arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
start = strchr(arg, '[');
if (start == NULL) {
start = arg;
/* Lets assume one colon is port information. Otherwise its an IPv6 address */
colon = strchr(arg, ':');
if (colon && strchr(colon+1, ':'))
colon = NULL;
}
else {
start++;
end = strchr(start, ']');
if (end == NULL)
xtables_error(PARAMETER_PROBLEM,
"Invalid address format");
*end = '\0';
colon = strchr(end + 1, ':');
}
if (colon) {
int port;
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
port = atoi(colon+1);
if (port <= 0 || port > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", colon+1);
error = strchr(colon+1, ':');
if (error)
xtables_error(PARAMETER_PROBLEM,
"Invalid port:port syntax - use dash\n");
dash = strchr(colon, '-');
if (!dash) {
range->min_proto.tcp.port
= range->max_proto.tcp.port
= htons(port);
} else {
int maxport;
maxport = atoi(dash + 1);
if (maxport <= 0 || maxport > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", dash+1);
if (maxport < port)
/* People are stupid. */
xtables_error(PARAMETER_PROBLEM,
"Port range `%s' funky\n", colon+1);
range->min_proto.tcp.port = htons(port);
range->max_proto.tcp.port = htons(maxport);
}
/* Starts with colon or [] colon? No IP info...*/
if (colon == arg || colon == arg+2) {
free(arg);
return;
}
*colon = '\0';
}
range->flags |= NF_NAT_RANGE_MAP_IPS;
dash = strchr(start, '-');
if (colon && dash && dash > colon)
dash = NULL;
if (dash)
*dash = '\0';
ip = xtables_numeric_to_ip6addr(start);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
start);
range->min_addr.in6 = *ip;
if (dash) {
ip = xtables_numeric_to_ip6addr(dash + 1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
range->max_addr.in6 = *ip;
} else
range->max_addr = range->min_addr;
free(arg);
return;
}
static void DNAT_parse(struct xt_option_call *cb)
{
const struct ip6t_entry *entry = cb->xt_entry;
struct nf_nat_range *range = cb->data;
int portok;
if (entry->ipv6.proto == IPPROTO_TCP ||
entry->ipv6.proto == IPPROTO_UDP ||
entry->ipv6.proto == IPPROTO_SCTP ||
entry->ipv6.proto == IPPROTO_DCCP ||
entry->ipv6.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_DEST:
if (cb->xflags & F_X_TO_DEST) {
if (!kernel_version)
get_kernel_version();
if (kernel_version > LINUX_VERSION(2, 6, 10))
xtables_error(PARAMETER_PROBLEM,
"DNAT: Multiple --to-destination not supported");
}
parse_to(cb->arg, portok, range);
break;
case O_PERSISTENT:
range->flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
static void DNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_DEST | F_RANDOM;
struct nf_nat_range *mr = cb->data;
if ((cb->xflags & f) == f)
mr->flags |= NF_NAT_RANGE_PROTO_RANDOM;
}
static void print_range(const struct nf_nat_range *range)
{
if (range->flags & NF_NAT_RANGE_MAP_IPS) {
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
printf("[");
printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6));
if (memcmp(&range->min_addr, &range->max_addr,
sizeof(range->min_addr)))
printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6));
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
printf("]");
}
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(":");
printf("%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port)
printf("-%hu", ntohs(range->max_proto.tcp.port));
}
}
static void DNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_range *range = (const void *)target->data;
printf(" to:");
print_range(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
static void DNAT_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_range *range = (const void *)target->data;
printf(" --to-destination ");
print_range(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
static struct xtables_target snat_tg_reg = {
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.revision = 1,
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
.help = DNAT_help,
.x6_parse = DNAT_parse,
.x6_fcheck = DNAT_fcheck,
.print = DNAT_print,
.save = DNAT_save,
.x6_options = DNAT_opts,
};
void _init(void)
{
xtables_register_target(&snat_tg_reg);
}
/*
* Copyright (c) 2012-2013 Patrick McHardy <kaber@trash.net>
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_NPT.h>
enum {
O_SRC_PFX = 1 << 0,
O_DST_PFX = 1 << 1,
};
static const struct xt_option_entry DNPT_options[] = {
{ .name = "src-pfx", .id = O_SRC_PFX, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MAND },
{ .name = "dst-pfx", .id = O_DST_PFX, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MAND },
{ }
};
static void DNPT_help(void)
{
printf("DNPT target options:"
"\n"
" --src-pfx prefix/length\n"
" --dst-pfx prefix/length\n"
"\n");
}
static void DNPT_parse(struct xt_option_call *cb)
{
struct ip6t_npt_tginfo *npt = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SRC_PFX:
npt->src_pfx = cb->val.haddr;
npt->src_pfx_len = cb->val.hlen;
break;
case O_DST_PFX:
npt->dst_pfx = cb->val.haddr;
npt->dst_pfx_len = cb->val.hlen;
break;
}
}
static void DNPT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ip6t_npt_tginfo *npt = (const void *)target->data;
printf("src-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->src_pfx.in6),
npt->src_pfx_len);
printf("dst-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6),
npt->dst_pfx_len);
}
static void DNPT_save(const void *ip, const struct xt_entry_target *target)
{
static const struct in6_addr zero_addr;
const struct ip6t_npt_tginfo *info = (const void *)target->data;
if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->src_pfx_len != 0)
printf("--src-pfx %s/%u ",
xtables_ip6addr_to_numeric(&info->src_pfx.in6),
info->src_pfx_len);
if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->dst_pfx_len != 0)
printf("--dst-pfx %s/%u ",
xtables_ip6addr_to_numeric(&info->dst_pfx.in6),
info->dst_pfx_len);
}
static struct xtables_target snpt_tg_reg = {
.name = "DNPT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_npt_tginfo)),
.userspacesize = offsetof(struct ip6t_npt_tginfo, adjustment),
.help = DNPT_help,
.x6_parse = DNPT_parse,
.print = DNPT_print,
.save = DNPT_save,
.x6_options = DNPT_options,
};
void _init(void)
{
xtables_register_target(&snpt_tg_reg);
}
Provides stateless destination IPv6-to-IPv6 Network Prefix Translation (as
described by RFC 6296).
.PP
You have to use this target in the
.B mangle
table, not in the
.B nat
table. It takes the following options:
.TP
\fB\-\-src\-pfx\fP [\fIprefix/\fP\fIlength]
Set source prefix that you want to translate and length
.TP
\fB\-\-dst\-pfx\fP [\fIprefix/\fP\fIlength]
Set destination prefix that you want to use in the translation and length
.PP
You have to use the SNPT target to undo the translation. Example:
.IP
ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 \! \-o vboxnet0
\-j SNPT \-\-src-pfx fd00::/64 \-\-dst-pfx 2001:e20:2000:40f::/64
.IP
ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst-pfx fd00::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
sysctl -w net.ipv6.conf.all.proxy_ndp=1
.PP
You also have to use the
.B NOTRACK
target to disable connection tracking for translated flows.
/*
* IPv6 Hop Limit Target module
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's ttl target
* This program is distributed under the terms of GNU GPL
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_HL.h>
enum {
O_HL_SET = 0,
O_HL_INC,
O_HL_DEC,
F_HL_SET = 1 << O_HL_SET,
F_HL_INC = 1 << O_HL_INC,
F_HL_DEC = 1 << O_HL_DEC,
F_ANY = F_HL_SET | F_HL_INC | F_HL_DEC,
};
#define s struct ip6t_HL_info
static const struct xt_option_entry HL_opts[] = {
{.name = "hl-set", .type = XTTYPE_UINT8, .id = O_HL_SET,
.excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl-dec", .type = XTTYPE_UINT8, .id = O_HL_DEC,
.excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit),
.min = 1},
{.name = "hl-inc", .type = XTTYPE_UINT8, .id = O_HL_INC,
.excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit),
.min = 1},
XTOPT_TABLEEND,
};
#undef s
static void HL_help(void)
{
printf(
"HL target options\n"
" --hl-set value Set HL to <value 0-255>\n"
" --hl-dec value Decrement HL by <value 1-255>\n"
" --hl-inc value Increment HL by <value 1-255>\n");
}
static void HL_parse(struct xt_option_call *cb)
{
struct ip6t_HL_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_HL_SET:
info->mode = IP6T_HL_SET;
break;
case O_HL_INC:
info->mode = IP6T_HL_INC;
break;
case O_HL_DEC:
info->mode = IP6T_HL_DEC;
break;
}
}
static void HL_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_ANY))
xtables_error(PARAMETER_PROBLEM,
"HL: You must specify an action");
}
static void HL_save(const void *ip, const struct xt_entry_target *target)
{
const struct ip6t_HL_info *info =
(struct ip6t_HL_info *) target->data;
switch (info->mode) {
case IP6T_HL_SET:
printf(" --hl-set");
break;
case IP6T_HL_DEC:
printf(" --hl-dec");
break;
case IP6T_HL_INC:
printf(" --hl-inc");
break;
}
printf(" %u", info->hop_limit);
}
static void HL_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ip6t_HL_info *info =
(struct ip6t_HL_info *) target->data;
printf(" HL ");
switch (info->mode) {
case IP6T_HL_SET:
printf("set to");
break;
case IP6T_HL_DEC:
printf("decrement by");
break;
case IP6T_HL_INC:
printf("increment by");
break;
}
printf(" %u", info->hop_limit);
}
static struct xtables_target hl_tg6_reg = {
.name = "HL",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_HL_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_HL_info)),
.help = HL_help,
.print = HL_print,
.save = HL_save,
.x6_parse = HL_parse,
.x6_fcheck = HL_check,
.x6_options = HL_opts,
};
void _init(void)
{
xtables_register_target(&hl_tg6_reg);
}
This is used to modify the Hop Limit field in IPv6 header. The Hop Limit field
is similar to what is known as TTL value in IPv4. Setting or incrementing the
Hop Limit field can potentially be very dangerous, so it should be avoided at
any cost. This target is only valid in
.B mangle
table.
.PP
.B Don't ever set or increment the value on packets that leave your local network!
.TP
\fB\-\-hl\-set\fP \fIvalue\fP
Set the Hop Limit to `value'.
.TP
\fB\-\-hl\-dec\fP \fIvalue\fP
Decrement the Hop Limit `value' times.
.TP
\fB\-\-hl\-inc\fP \fIvalue\fP
Increment the Hop Limit `value' times.
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_LOG.h>
#ifndef IP6T_LOG_UID /* Old kernel */
#define IP6T_LOG_UID 0x08
#undef IP6T_LOG_MASK
#define IP6T_LOG_MASK 0x0f
#endif
#define LOG_DEFAULT_LEVEL LOG_WARNING
enum {
O_LOG_LEVEL = 0,
O_LOG_PREFIX,
O_LOG_TCPSEQ,
O_LOG_TCPOPTS,
O_LOG_IPOPTS,
O_LOG_UID,
O_LOG_MAC,
};
static void LOG_help(void)
{
printf(
"LOG target options:\n"
" --log-level level Level of logging (numeric or see syslog.conf)\n"
" --log-prefix prefix Prefix log messages with this prefix.\n"
" --log-tcp-sequence Log TCP sequence numbers.\n"
" --log-tcp-options Log TCP options.\n"
" --log-ip-options Log IP options.\n"
" --log-uid Log UID owning the local socket.\n"
" --log-macdecode Decode MAC addresses and protocol.\n");
}
#define s struct ip6t_log_info
static const struct xt_option_entry LOG_opts[] = {
{.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL,
.flags = XTOPT_PUT, XTOPT_POINTER(s, level)},
{.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING,
.flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1},
{.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE},
{.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE},
{.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE},
{.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE},
{.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
#undef s
static void LOG_init(struct xt_entry_target *t)
{
struct ip6t_log_info *loginfo = (struct ip6t_log_info *)t->data;
loginfo->level = LOG_DEFAULT_LEVEL;
}
struct ip6t_log_names {
const char *name;
unsigned int level;
};
static const struct ip6t_log_names ip6t_log_names[]
= { { .name = "alert", .level = LOG_ALERT },
{ .name = "crit", .level = LOG_CRIT },
{ .name = "debug", .level = LOG_DEBUG },
{ .name = "emerg", .level = LOG_EMERG },
{ .name = "error", .level = LOG_ERR }, /* DEPRECATED */
{ .name = "info", .level = LOG_INFO },
{ .name = "notice", .level = LOG_NOTICE },
{ .name = "panic", .level = LOG_EMERG }, /* DEPRECATED */
{ .name = "warning", .level = LOG_WARNING }
};
static void LOG_parse(struct xt_option_call *cb)
{
struct ip6t_log_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_LOG_PREFIX:
if (strchr(cb->arg, '\n') != NULL)
xtables_error(PARAMETER_PROBLEM,
"Newlines not allowed in --log-prefix");
break;
case O_LOG_TCPSEQ:
info->logflags |= IP6T_LOG_TCPSEQ;
break;
case O_LOG_TCPOPTS:
info->logflags |= IP6T_LOG_TCPOPT;
break;
case O_LOG_IPOPTS:
info->logflags |= IP6T_LOG_IPOPT;
break;
case O_LOG_UID:
info->logflags |= IP6T_LOG_UID;
break;
case O_LOG_MAC:
info->logflags |= IP6T_LOG_MACDECODE;
break;
}
}
static void LOG_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ip6t_log_info *loginfo
= (const struct ip6t_log_info *)target->data;
unsigned int i = 0;
printf(" LOG");
if (numeric)
printf(" flags %u level %u",
loginfo->logflags, loginfo->level);
else {
for (i = 0; i < ARRAY_SIZE(ip6t_log_names); ++i)
if (loginfo->level == ip6t_log_names[i].level) {
printf(" level %s", ip6t_log_names[i].name);
break;
}
if (i == ARRAY_SIZE(ip6t_log_names))
printf(" UNKNOWN level %u", loginfo->level);
if (loginfo->logflags & IP6T_LOG_TCPSEQ)
printf(" tcp-sequence");
if (loginfo->logflags & IP6T_LOG_TCPOPT)
printf(" tcp-options");
if (loginfo->logflags & IP6T_LOG_IPOPT)
printf(" ip-options");
if (loginfo->logflags & IP6T_LOG_UID)
printf(" uid");
if (loginfo->logflags & IP6T_LOG_MACDECODE)
printf(" macdecode");
if (loginfo->logflags & ~(IP6T_LOG_MASK))
printf(" unknown-flags");
}
if (strcmp(loginfo->prefix, "") != 0)
printf(" prefix \"%s\"", loginfo->prefix);
}
static void LOG_save(const void *ip, const struct xt_entry_target *target)
{
const struct ip6t_log_info *loginfo
= (const struct ip6t_log_info *)target->data;
if (strcmp(loginfo->prefix, "") != 0) {
printf(" --log-prefix");
xtables_save_string(loginfo->prefix);
}
if (loginfo->level != LOG_DEFAULT_LEVEL)
printf(" --log-level %d", loginfo->level);
if (loginfo->logflags & IP6T_LOG_TCPSEQ)
printf(" --log-tcp-sequence");
if (loginfo->logflags & IP6T_LOG_TCPOPT)
printf(" --log-tcp-options");
if (loginfo->logflags & IP6T_LOG_IPOPT)
printf(" --log-ip-options");
if (loginfo->logflags & IP6T_LOG_UID)
printf(" --log-uid");
if (loginfo->logflags & IP6T_LOG_MACDECODE)
printf(" --log-macdecode");
}
static struct xtables_target log_tg6_reg = {
.name = "LOG",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_log_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)),
.help = LOG_help,
.init = LOG_init,
.print = LOG_print,
.save = LOG_save,
.x6_parse = LOG_parse,
.x6_options = LOG_opts,
};
void _init(void)
{
xtables_register_target(&log_tg6_reg);
}
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT
* funded by Astaro.
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/nf_nat.h>
enum {
O_TO_PORTS = 0,
O_RANDOM,
};
static void MASQUERADE_help(void)
{
printf(
"MASQUERADE target options:\n"
" --to-ports <port>[-<port>]\n"
" Port (range) to map to.\n"
" --random\n"
" Randomize source port.\n");
}
static const struct xt_option_entry MASQUERADE_opts[] = {
{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
/* Parses ports */
static void
parse_ports(const char *arg, struct nf_nat_range *r)
{
char *end;
unsigned int port, maxport;
r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX))
xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
switch (*end) {
case '\0':
r->min_proto.tcp.port
= r->max_proto.tcp.port
= htons(port);
return;
case '-':
if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
break;
if (maxport < port)
break;
r->min_proto.tcp.port = htons(port);
r->max_proto.tcp.port = htons(maxport);
return;
default:
break;
}
xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg);
}
static void MASQUERADE_parse(struct xt_option_call *cb)
{
const struct ip6t_entry *entry = cb->xt_entry;
struct nf_nat_range *r = cb->data;
int portok;
if (entry->ipv6.proto == IPPROTO_TCP ||
entry->ipv6.proto == IPPROTO_UDP ||
entry->ipv6.proto == IPPROTO_SCTP ||
entry->ipv6.proto == IPPROTO_DCCP ||
entry->ipv6.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_PORTS:
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
parse_ports(cb->arg, r);
break;
case O_RANDOM:
r->flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void
MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_range *r = (const void *)target->data;
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" masq ports: ");
printf("%hu", ntohs(r->min_proto.tcp.port));
if (r->max_proto.tcp.port != r->min_proto.tcp.port)
printf("-%hu", ntohs(r->max_proto.tcp.port));
}
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
}
static void
MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_range *r = (const void *)target->data;
if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port));
if (r->max_proto.tcp.port != r->min_proto.tcp.port)
printf("-%hu", ntohs(r->max_proto.tcp.port));
}
if (r->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
}
static struct xtables_target masquerade_tg_reg = {
.name = "MASQUERADE",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
.help = MASQUERADE_help,
.x6_parse = MASQUERADE_parse,
.print = MASQUERADE_print,
.save = MASQUERADE_save,
.x6_options = MASQUERADE_opts,
};
void _init(void)
{
xtables_register_target(&masquerade_tg_reg);
}
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* Based on Svenning Soerensen's IPv4 NETMAP target. Development of IPv6 NAT
* funded by Astaro.
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <libiptc/libip6tc.h>
#include <linux/netfilter/nf_nat.h>
#define MODULENAME "NETMAP"
enum {
O_TO = 0,
};
static const struct xt_option_entry NETMAP_opts[] = {
{.name = "to", .id = O_TO, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MAND},
XTOPT_TABLEEND,
};
static void NETMAP_help(void)
{
printf(MODULENAME" target options:\n"
" --%s address[/mask]\n"
" Network address to map to.\n\n",
NETMAP_opts[0].name);
}
static void NETMAP_parse(struct xt_option_call *cb)
{
struct nf_nat_range *range = cb->data;
unsigned int i;
xtables_option_parse(cb);
range->flags |= NF_NAT_RANGE_MAP_IPS;
for (i = 0; i < 4; i++) {
range->min_addr.ip6[i] = cb->val.haddr.ip6[i] &
cb->val.hmask.ip6[i];
range->max_addr.ip6[i] = range->min_addr.ip6[i] |
~cb->val.hmask.ip6[i];
}
}
static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_range *r = (const void *)target->data;
struct in6_addr a;
unsigned int i;
int bits;
a = r->min_addr.in6;
printf("%s", xtables_ip6addr_to_numeric(&a));
for (i = 0; i < 4; i++)
a.s6_addr32[i] = ~(r->min_addr.ip6[i] ^ r->max_addr.ip6[i]);
bits = xtables_ip6mask_to_cidr(&a);
if (bits < 0)
printf("/%s", xtables_ip6addr_to_numeric(&a));
else
printf("/%d", bits);
}
static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
{
printf(" --%s ", NETMAP_opts[0].name);
NETMAP_print(ip, target, 0);
}
static struct xtables_target netmap_tg_reg = {
.name = MODULENAME,
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
.help = NETMAP_help,
.x6_parse = NETMAP_parse,
.print = NETMAP_print,
.save = NETMAP_save,
.x6_options = NETMAP_opts,
};
void _init(void)
{
xtables_register_target(&netmap_tg_reg);
}
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT
* funded by Astaro.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/nf_nat.h>
enum {
O_TO_PORTS = 0,
O_RANDOM,
F_TO_PORTS = 1 << O_TO_PORTS,
F_RANDOM = 1 << O_RANDOM,
};
static void REDIRECT_help(void)
{
printf(
"REDIRECT target options:\n"
" --to-ports <port>[-<port>]\n"
" Port (range) to map to.\n"
" [--random]\n");
}
static const struct xt_option_entry REDIRECT_opts[] = {
{.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
/* Parses ports */
static void
parse_ports(const char *arg, struct nf_nat_range *range)
{
char *end = "";
unsigned int port, maxport;
range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) &&
(port = xtables_service_to_port(arg, NULL)) == (unsigned)-1)
xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
switch (*end) {
case '\0':
range->min_proto.tcp.port
= range->max_proto.tcp.port
= htons(port);
return;
case '-':
if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) &&
(maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1)
break;
if (maxport < port)
break;
range->min_proto.tcp.port = htons(port);
range->max_proto.tcp.port = htons(maxport);
return;
default:
break;
}
xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg);
}
static void REDIRECT_parse(struct xt_option_call *cb)
{
const struct ip6t_entry *entry = cb->xt_entry;
struct nf_nat_range *range = (void *)(*cb->target)->data;
int portok;
if (entry->ipv6.proto == IPPROTO_TCP
|| entry->ipv6.proto == IPPROTO_UDP
|| entry->ipv6.proto == IPPROTO_SCTP
|| entry->ipv6.proto == IPPROTO_DCCP
|| entry->ipv6.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_PORTS:
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
parse_ports(cb->arg, range);
if (cb->xflags & F_RANDOM)
range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
case O_RANDOM:
if (cb->xflags & F_TO_PORTS)
range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_range *range = (const void *)target->data;
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" redir ports ");
printf("%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port)
printf("-%hu", ntohs(range->max_proto.tcp.port));
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
}
}
static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_range *range = (const void *)target->data;
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(" --to-ports ");
printf("%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port)
printf("-%hu", ntohs(range->max_proto.tcp.port));
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
}
}
static struct xtables_target redirect_tg_reg = {
.name = "REDIRECT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
.help = REDIRECT_help,
.x6_parse = REDIRECT_parse,
.print = REDIRECT_print,
.save = REDIRECT_save,
.x6_options = REDIRECT_opts,
};
void _init(void)
{
xtables_register_target(&redirect_tg_reg);
}
/* Shared library add-on to ip6tables to add customized REJECT support.
*
* (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* ported to IPv6 by Harald Welte <laforge@gnumonks.org>
*
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_REJECT.h>
struct reject_names {
const char *name;
const char *alias;
enum ip6t_reject_with with;
const char *desc;
};
enum {
O_REJECT_WITH = 0,
};
static const struct reject_names reject_table[] = {
{"icmp6-no-route", "no-route",
IP6T_ICMP6_NO_ROUTE, "ICMPv6 no route"},
{"icmp6-adm-prohibited", "adm-prohibited",
IP6T_ICMP6_ADM_PROHIBITED, "ICMPv6 administratively prohibited"},
#if 0
{"icmp6-not-neighbor", "not-neighbor"},
IP6T_ICMP6_NOT_NEIGHBOR, "ICMPv6 not a neighbor"},
#endif
{"icmp6-addr-unreachable", "addr-unreach",
IP6T_ICMP6_ADDR_UNREACH, "ICMPv6 address unreachable"},
{"icmp6-port-unreachable", "port-unreach",
IP6T_ICMP6_PORT_UNREACH, "ICMPv6 port unreachable"},
{"tcp-reset", "tcp-reset",
IP6T_TCP_RESET, "TCP RST packet"}
};
static void
print_reject_types(void)
{
unsigned int i;
printf("Valid reject types:\n");
for (i = 0; i < ARRAY_SIZE(reject_table); ++i) {
printf(" %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
printf(" %-25s\talias\n", reject_table[i].alias);
}
printf("\n");
}
static void REJECT_help(void)
{
printf(
"REJECT target options:\n"
"--reject-with type drop input packet and send back\n"
" a reply packet according to type:\n");
print_reject_types();
}
static const struct xt_option_entry REJECT_opts[] = {
{.name = "reject-with", .id = O_REJECT_WITH, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
static void REJECT_init(struct xt_entry_target *t)
{
struct ip6t_reject_info *reject = (struct ip6t_reject_info *)t->data;
/* default */
reject->with = IP6T_ICMP6_PORT_UNREACH;
}
static void REJECT_parse(struct xt_option_call *cb)
{
struct ip6t_reject_info *reject = cb->data;
unsigned int i;
xtables_option_parse(cb);
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
if (strncasecmp(reject_table[i].name,
cb->arg, strlen(cb->arg)) == 0 ||
strncasecmp(reject_table[i].alias,
cb->arg, strlen(cb->arg)) == 0) {
reject->with = reject_table[i].with;
return;
}
xtables_error(PARAMETER_PROBLEM,
"unknown reject type \"%s\"", cb->arg);
}
static void REJECT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ip6t_reject_info *reject
= (const struct ip6t_reject_info *)target->data;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
if (reject_table[i].with == reject->with)
break;
printf(" reject-with %s", reject_table[i].name);
}
static void REJECT_save(const void *ip, const struct xt_entry_target *target)
{
const struct ip6t_reject_info *reject
= (const struct ip6t_reject_info *)target->data;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(reject_table); ++i)
if (reject_table[i].with == reject->with)
break;
printf(" --reject-with %s", reject_table[i].name);
}
static struct xtables_target reject_tg6_reg = {
.name = "REJECT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_reject_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_reject_info)),
.help = REJECT_help,
.init = REJECT_init,
.print = REJECT_print,
.save = REJECT_save,
.x6_parse = REJECT_parse,
.x6_options = REJECT_opts,
};
void _init(void)
{
xtables_register_target(&reject_tg6_reg);
}
This is used to send back an error packet in response to the matched
packet: otherwise it is equivalent to
.B DROP
so it is a terminating TARGET, ending rule traversal.
This target is only valid in the
.BR INPUT ,
.B FORWARD
and
.B OUTPUT
chains, and user-defined chains which are only called from those
chains. The following option controls the nature of the error packet
returned:
.TP
\fB\-\-reject\-with\fP \fItype\fP
The type given can be
\fBicmp6\-no\-route\fP,
\fBno\-route\fP,
\fBicmp6\-adm\-prohibited\fP,
\fBadm\-prohibited\fP,
\fBicmp6\-addr\-unreachable\fP,
\fBaddr\-unreach\fP, or
\fBicmp6\-port\-unreachable\fP,
which return the appropriate ICMPv6 error message (\fBicmp6\-port\-unreachable\fP is
the default). Finally, the option
\fBtcp\-reset\fP
can be used on rules which only match the TCP protocol: this causes a
TCP RST packet to be sent back. This is mainly useful for blocking
.I ident
(113/tcp) probes which frequently occur when sending mail to broken mail
hosts (which won't accept your mail otherwise).
\fBtcp\-reset\fP
can only be used with kernel versions 2.6.14 or later.
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* Based on Rusty Russell's IPv4 SNAT target. Development of IPv6 NAT
* funded by Astaro.
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <iptables.h>
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/nf_nat.h>
enum {
O_TO_SRC = 0,
O_RANDOM,
O_PERSISTENT,
O_X_TO_SRC,
F_TO_SRC = 1 << O_TO_SRC,
F_RANDOM = 1 << O_RANDOM,
F_X_TO_SRC = 1 << O_X_TO_SRC,
};
static void SNAT_help(void)
{
printf(
"SNAT target options:\n"
" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n"
" Address to map source to.\n"
"[--random] [--persistent]\n");
}
static const struct xt_option_entry SNAT_opts[] = {
{.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
{.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
/* Ranges expected in network order. */
static void
parse_to(const char *orig_arg, int portok, struct nf_nat_range *range)
{
char *arg, *start, *end = NULL, *colon = NULL, *dash, *error;
const struct in6_addr *ip;
arg = strdup(orig_arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
start = strchr(arg, '[');
if (start == NULL) {
start = arg;
/* Lets assume one colon is port information. Otherwise its an IPv6 address */
colon = strchr(arg, ':');
if (colon && strchr(colon+1, ':'))
colon = NULL;
}
else {
start++;
end = strchr(start, ']');
if (end == NULL)
xtables_error(PARAMETER_PROBLEM,
"Invalid address format");
*end = '\0';
colon = strchr(end + 1, ':');
}
if (colon) {
int port;
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
port = atoi(colon+1);
if (port <= 0 || port > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", colon+1);
error = strchr(colon+1, ':');
if (error)
xtables_error(PARAMETER_PROBLEM,
"Invalid port:port syntax - use dash\n");
dash = strchr(colon, '-');
if (!dash) {
range->min_proto.tcp.port
= range->max_proto.tcp.port
= htons(port);
} else {
int maxport;
maxport = atoi(dash + 1);
if (maxport <= 0 || maxport > 65535)
xtables_error(PARAMETER_PROBLEM,
"Port `%s' not valid\n", dash+1);
if (maxport < port)
/* People are stupid. */
xtables_error(PARAMETER_PROBLEM,
"Port range `%s' funky\n", colon+1);
range->min_proto.tcp.port = htons(port);
range->max_proto.tcp.port = htons(maxport);
}
/* Starts with colon or [] colon? No IP info...*/
if (colon == arg || colon == arg+2) {
free(arg);
return;
}
*colon = '\0';
}
range->flags |= NF_NAT_RANGE_MAP_IPS;
dash = strchr(start, '-');
if (colon && dash && dash > colon)
dash = NULL;
if (dash)
*dash = '\0';
ip = xtables_numeric_to_ip6addr(start);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
start);
range->min_addr.in6 = *ip;
if (dash) {
ip = xtables_numeric_to_ip6addr(dash + 1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
range->max_addr.in6 = *ip;
} else
range->max_addr = range->min_addr;
free(arg);
return;
}
static void SNAT_parse(struct xt_option_call *cb)
{
const struct ip6t_entry *entry = cb->xt_entry;
struct nf_nat_range *range = cb->data;
int portok;
if (entry->ipv6.proto == IPPROTO_TCP ||
entry->ipv6.proto == IPPROTO_UDP ||
entry->ipv6.proto == IPPROTO_SCTP ||
entry->ipv6.proto == IPPROTO_DCCP ||
entry->ipv6.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_TO_SRC:
if (cb->xflags & F_X_TO_SRC) {
if (!kernel_version)
get_kernel_version();
if (kernel_version > LINUX_VERSION(2, 6, 10))
xtables_error(PARAMETER_PROBLEM,
"SNAT: Multiple --to-source not supported");
}
parse_to(cb->arg, portok, range);
break;
case O_PERSISTENT:
range->flags |= NF_NAT_RANGE_PERSISTENT;
break;
}
}
static void SNAT_fcheck(struct xt_fcheck_call *cb)
{
static const unsigned int f = F_TO_SRC | F_RANDOM;
struct nf_nat_range *range = cb->data;
if ((cb->xflags & f) == f)
range->flags |= NF_NAT_RANGE_PROTO_RANDOM;
}
static void print_range(const struct nf_nat_range *range)
{
if (range->flags & NF_NAT_RANGE_MAP_IPS) {
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
printf("[");
printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6));
if (memcmp(&range->min_addr, &range->max_addr,
sizeof(range->min_addr)))
printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6));
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)
printf("]");
}
if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) {
printf(":");
printf("%hu", ntohs(range->min_proto.tcp.port));
if (range->max_proto.tcp.port != range->min_proto.tcp.port)
printf("-%hu", ntohs(range->max_proto.tcp.port));
}
}
static void SNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_range *range = (const void *)target->data;
printf(" to:");
print_range(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" random");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
static void SNAT_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_range *range = (const void *)target->data;
printf(" --to-source ");
print_range(range);
if (range->flags & NF_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
if (range->flags & NF_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
static struct xtables_target snat_tg_reg = {
.name = "SNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.revision = 1,
.size = XT_ALIGN(sizeof(struct nf_nat_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)),
.help = SNAT_help,
.x6_parse = SNAT_parse,
.x6_fcheck = SNAT_fcheck,
.print = SNAT_print,
.save = SNAT_save,
.x6_options = SNAT_opts,
};
void _init(void)
{
xtables_register_target(&snat_tg_reg);
}
/*
* Copyright (c) 2012-2013 Patrick McHardy <kaber@trash.net>
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_NPT.h>
enum {
O_SRC_PFX = 1 << 0,
O_DST_PFX = 1 << 1,
};
static const struct xt_option_entry SNPT_options[] = {
{ .name = "src-pfx", .id = O_SRC_PFX, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MAND },
{ .name = "dst-pfx", .id = O_DST_PFX, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_MAND },
{ }
};
static void SNPT_help(void)
{
printf("SNPT target options:"
"\n"
" --src-pfx prefix/length\n"
" --dst-pfx prefix/length\n"
"\n");
}
static void SNPT_parse(struct xt_option_call *cb)
{
struct ip6t_npt_tginfo *npt = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_SRC_PFX:
npt->src_pfx = cb->val.haddr;
npt->src_pfx_len = cb->val.hlen;
break;
case O_DST_PFX:
npt->dst_pfx = cb->val.haddr;
npt->dst_pfx_len = cb->val.hlen;
break;
}
}
static void SNPT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ip6t_npt_tginfo *npt = (const void *)target->data;
printf("src-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->src_pfx.in6),
npt->src_pfx_len);
printf("dst-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6),
npt->dst_pfx_len);
}
static void SNPT_save(const void *ip, const struct xt_entry_target *target)
{
static const struct in6_addr zero_addr;
const struct ip6t_npt_tginfo *info = (const void *)target->data;
if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->src_pfx_len != 0)
printf("--src-pfx %s/%u ",
xtables_ip6addr_to_numeric(&info->src_pfx.in6),
info->src_pfx_len);
if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 ||
info->dst_pfx_len != 0)
printf("--dst-pfx %s/%u ",
xtables_ip6addr_to_numeric(&info->dst_pfx.in6),
info->dst_pfx_len);
}
static struct xtables_target snpt_tg_reg = {
.name = "SNPT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_npt_tginfo)),
.userspacesize = offsetof(struct ip6t_npt_tginfo, adjustment),
.help = SNPT_help,
.x6_parse = SNPT_parse,
.print = SNPT_print,
.save = SNPT_save,
.x6_options = SNPT_options,
};
void _init(void)
{
xtables_register_target(&snpt_tg_reg);
}
Provides stateless source IPv6-to-IPv6 Network Prefix Translation (as described
by RFC 6296).
.PP
You have to use this target in the
.B mangle
table, not in the
.B nat
table. It takes the following options:
.TP
\fB\-\-src\-pfx\fP [\fIprefix/\fP\fIlength]
Set source prefix that you want to translate and length
.TP
\fB\-\-dst\-pfx\fP [\fIprefix/\fP\fIlength]
Set destination prefix that you want to use in the translation and length
.PP
You have to use the DNPT target to undo the translation. Example:
.IP
ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 \! \-o vboxnet0
\-j SNPT \-\-src-pfx fd00::/64 \-\-dst-pfx 2001:e20:2000:40f::/64
.IP
ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64
\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst-pfx fd00::/64
.PP
You may need to enable IPv6 neighbor proxy:
.IP
sysctl -w net.ipv6.conf.all.proxy_ndp=1
.PP
You also have to use the
.B NOTRACK
target to disable connection tracking for translated flows.
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_ah.h>
enum {
O_AHSPI = 0,
O_AHLEN,
O_AHRES,
};
static void ah_help(void)
{
printf(
"ah match options:\n"
"[!] --ahspi spi[:spi] match spi (range)\n"
"[!] --ahlen length total length of this header\n"
" --ahres check the reserved field too\n");
}
#define s struct ip6t_ah
static const struct xt_option_entry ah_opts[] = {
{.name = "ahspi", .id = O_AHSPI, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spis)},
{.name = "ahlen", .id = O_AHLEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
{.name = "ahres", .id = O_AHRES, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
#undef s
static void ah_parse(struct xt_option_call *cb)
{
struct ip6t_ah *ahinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_AHSPI:
if (cb->nvals == 1)
ahinfo->spis[1] = ahinfo->spis[0];
if (cb->invert)
ahinfo->invflags |= IP6T_AH_INV_SPI;
break;
case O_AHLEN:
if (cb->invert)
ahinfo->invflags |= IP6T_AH_INV_LEN;
break;
case O_AHRES:
ahinfo->hdrres = 1;
break;
}
}
static void
print_spis(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFFFFFFFF || invert) {
if (min == max)
printf("%s:%s%u", name, inv, min);
else
printf("%ss:%s%u:%u", name, inv, min, max);
}
}
static void
print_len(const char *name, uint32_t len, int invert)
{
const char *inv = invert ? "!" : "";
if (len != 0 || invert)
printf("%s:%s%u", name, inv, len);
}
static void ah_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_ah *ah = (struct ip6t_ah *)match->data;
printf(" ah ");
print_spis("spi", ah->spis[0], ah->spis[1],
ah->invflags & IP6T_AH_INV_SPI);
print_len("length", ah->hdrlen,
ah->invflags & IP6T_AH_INV_LEN);
if (ah->hdrres)
printf(" reserved");
if (ah->invflags & ~IP6T_AH_INV_MASK)
printf(" Unknown invflags: 0x%X",
ah->invflags & ~IP6T_AH_INV_MASK);
}
static void ah_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data;
if (!(ahinfo->spis[0] == 0
&& ahinfo->spis[1] == 0xFFFFFFFF)) {
printf("%s --ahspi ",
(ahinfo->invflags & IP6T_AH_INV_SPI) ? " !" : "");
if (ahinfo->spis[0]
!= ahinfo->spis[1])
printf("%u:%u",
ahinfo->spis[0],
ahinfo->spis[1]);
else
printf("%u",
ahinfo->spis[0]);
}
if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) {
printf("%s --ahlen %u",
(ahinfo->invflags & IP6T_AH_INV_LEN) ? " !" : "",
ahinfo->hdrlen);
}
if (ahinfo->hdrres != 0 )
printf(" --ahres");
}
static struct xtables_match ah_mt6_reg = {
.name = "ah",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_ah)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
.help = ah_help,
.print = ah_print,
.save = ah_save,
.x6_parse = ah_parse,
.x6_options = ah_opts,
};
void
_init(void)
{
xtables_register_match(&ah_mt6_reg);
}
This module matches the parameters in Authentication header of IPsec packets.
.TP
[\fB!\fP] \fB\-\-ahspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
Matches SPI.
.TP
[\fB!\fP] \fB\-\-ahlen\fP \fIlength\fP
Total length of this header in octets.
.TP
\fB\-\-ahres\fP
Matches if the reserved field is filled with zero.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
enum {
O_DSTLEN = 0,
O_DSTOPTS,
};
static void dst_help(void)
{
printf(
"dst match options:\n"
"[!] --dst-len length total length of this header\n"
" --dst-opts TYPE[:LEN][,TYPE[:LEN]...]\n"
" Options and its length (list, max: %d)\n",
IP6T_OPTS_OPTSNR);
}
static const struct xt_option_entry dst_opts[] = {
{.name = "dst-len", .id = O_DSTLEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(struct ip6t_opts, hdrlen)},
{.name = "dst-opts", .id = O_DSTOPTS, .type = XTTYPE_STRING},
XTOPT_TABLEEND,
};
static uint32_t
parse_opts_num(const char *idstr, const char *typestr)
{
unsigned long int id;
char* ep;
id = strtoul(idstr, &ep, 0);
if ( idstr == ep ) {
xtables_error(PARAMETER_PROBLEM,
"dst: no valid digits in %s `%s'", typestr, idstr);
}
if ( id == ULONG_MAX && errno == ERANGE ) {
xtables_error(PARAMETER_PROBLEM,
"%s `%s' specified too big: would overflow",
typestr, idstr);
}
if ( *idstr != '\0' && *ep != '\0' ) {
xtables_error(PARAMETER_PROBLEM,
"dst: error parsing %s `%s'", typestr, idstr);
}
return id;
}
static int
parse_options(const char *optsstr, uint16_t *opts)
{
char *buffer, *cp, *next, *range;
unsigned int i;
buffer = strdup(optsstr);
if (!buffer)
xtables_error(OTHER_PROBLEM, "strdup failed");
for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
{
next = strchr(cp, ',');
if (next)
*next++='\0';
range = strchr(cp, ':');
if (range) {
if (i == IP6T_OPTS_OPTSNR-1)
xtables_error(PARAMETER_PROBLEM,
"too many ports specified");
*range++ = '\0';
}
opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8;
if (range) {
if (opts[i] == 0)
xtables_error(PARAMETER_PROBLEM,
"PAD0 hasn't got length");
opts[i] |= parse_opts_num(range, "length") & 0xFF;
} else
opts[i] |= (0x00FF);
#ifdef DEBUG
printf("opts str: %s %s\n", cp, range);
printf("opts opt: %04X\n", opts[i]);
#endif
}
if (cp)
xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
free(buffer);
#ifdef DEBUG
printf("addr nr: %d\n", i);
#endif
return i;
}
static void dst_parse(struct xt_option_call *cb)
{
struct ip6t_opts *optinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_DSTLEN:
optinfo->flags |= IP6T_OPTS_LEN;
break;
case O_DSTOPTS:
optinfo->optsnr = parse_options(cb->arg, optinfo->opts);
optinfo->flags |= IP6T_OPTS_OPTS;
break;
}
}
static void
print_options(unsigned int optsnr, uint16_t *optsp)
{
unsigned int i;
printf(" ");
for(i = 0; i < optsnr; i++) {
printf("%d", (optsp[i] & 0xFF00) >> 8);
if ((optsp[i] & 0x00FF) != 0x00FF)
printf(":%d", (optsp[i] & 0x00FF));
printf("%c", (i != optsnr - 1) ? ',' : ' ');
}
}
static void dst_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
printf(" dst");
if (optinfo->flags & IP6T_OPTS_LEN)
printf(" length:%s%u",
optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "",
optinfo->hdrlen);
if (optinfo->flags & IP6T_OPTS_OPTS)
printf(" opts");
print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
printf(" Unknown invflags: 0x%X",
optinfo->invflags & ~IP6T_OPTS_INV_MASK);
}
static void dst_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
if (optinfo->flags & IP6T_OPTS_LEN) {
printf("%s --dst-len %u",
(optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "",
optinfo->hdrlen);
}
if (optinfo->flags & IP6T_OPTS_OPTS)
printf(" --dst-opts");
print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
}
static struct xtables_match dst_mt6_reg = {
.name = "dst",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_opts)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)),
.help = dst_help,
.print = dst_print,
.save = dst_save,
.x6_parse = dst_parse,
.x6_options = dst_opts,
};
void
_init(void)
{
xtables_register_match(&dst_mt6_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