Commit bcb46704 authored by Mygod's avatar Mygod

Update iptables

parent 9a155c2f
......@@ -5,3 +5,7 @@
path = src/main/jni/badvpn
url = https://github.com/Mygod/badvpn.git
branch = shadowsocks
[submodule "src/main/jni/iptables"]
path = src/main/jni/iptables
url = https://github.com/Mygod/iptables.git
branch = shadowsocks
Subproject commit 177a84bc6b77c53e1ccc22b97170928d54c1ce92
BUILD_IPTABLES_V14 := 1
LOCAL_PATH:= $(call my-dir)
include $(call all-subdir-makefiles)
A quick list of rules for committing stuff into netfilter git:
- Always add an appropriate description, in git format
(i.e. first line is a summary)
- Please try to include references to bugs when the description does not
include total discussion coverage or when the bug report is external to
netfilter-devel, e.g.
"Closes: netfilter bugzilla #123", or
"Reference: http://bugs.{debian,gentoo}.org/..."
- If you touch any parts of libxtables (xtables.c, include/xtables.h.in),
make sure the so-version is updated _appropriately_ (i.e. read the
libtool manual about Versioning:: first, if need be) in configure.ac.
Adding fields to a struct always entails a vcurrent bump.
- Check, whether a bump (vcurrent,vage) has already been made since the
last release (no more than one per release), e.g.:
git log v1.4.4.. configure.ac
This diff is collapsed.
INCOMPATIBILITIES:
- The REJECT target has an '--reject-with admin-prohib' option which used
with kernels that do not support it, will result in a plain DROP instead
of REJECT. Use with caution.
Kernels that do support it:
2.4 - since 2.4.22-pre9
2.6 - all
- There are some issues related to upgrading from 1.2.x to 1.3.x on a system
with dynamic ruleset changes during runtime. (Please see
https://bugzilla.netfilter.org/bugzilla/show_bug.cgi?id=334).
After upgrading from 1.2 to 1.3, it suggest go do an iptables-save, then
iptables-restore to ensure your dynamic rule changes continue to work.
Installation instructions for iptables
======================================
iptables uses the well-known configure(autotools) infrastructure.
$ ./configure
$ make
# make install
Prerequisites
=============
* no kernel-source required
* but obviously a compiler, glibc-devel and linux-kernel-headers
(/usr/include/linux)
Configuring and compiling
=========================
./configure [options]
--prefix=
The prefix to put all installed files under. It defaults to
/usr/local, so the binaries will go into /usr/local/bin, sbin,
manpages into /usr/local/share/man, etc.
--with-xtlibdir=
The path to where Xtables extensions should be installed to. It
defaults to ${prefix}/libexec/xtables.
--enable-devel (or --disable-devel)
This option causes development files to be installed to
${includedir}, which is needed for building additional packages,
such as Xtables-addons or other 3rd-party extensions.
It is enabled by default.
--enable-static
Produce additional binaries, iptables-static/ip6tables-static,
which have all shipped extensions compiled in.
--disable-shared
Produce binaries that have dynamic loading of extensions disabled.
This implies --enable-static.
(See some details below.)
--enable-libipq
This option causes libipq to be installed into ${libdir} and
${includedir}.
--with-ksource=
Xtables does not depend on kernel headers anymore, but you can
optionally specify a search path to include anyway. This is
probably only useful for development.
If you want to enable debugging, use
./configure CFLAGS="-ggdb3 -O0"
(-O0 is used to turn off instruction reordering, which makes debugging
much easier.)
Other notes
===========
The make process will automatically build multipurpose binaries.
These have the core (iptables), -save, -restore and -xml code
compiled into one binary, but extensions remain as modules.
Static and shared
=================
Basically there are three configuration modes defined:
--disable-static --enable-shared (this is the default)
Build a binary that relies upon dynamic loading of extensions.
--enable-static --enable-shared
Build a binary that has the shipped extensions built-in, but
is still capable of loading additional extensions.
--enable-static --disable-shared
Shipped extensions are built-in, and dynamic loading is
deactivated.
# -*- Makefile -*-
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = foreign subdir-objects
SUBDIRS = extensions libiptc iptables
if ENABLE_DEVEL
SUBDIRS += include
endif
if ENABLE_LIBIPQ
SUBDIRS += libipq
endif
if HAVE_LIBNFNETLINK
SUBDIRS += utils
endif
.PHONY: tarball
tarball:
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
pushd ${top_srcdir} && git archive --prefix=${PACKAGE_TARNAME}-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd;
pushd /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION} && ./autogen.sh && popd;
tar -C /tmp -cjf ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root ${PACKAGE_TARNAME}-${PACKAGE_VERSION}/;
rm -Rf /tmp/${PACKAGE_TARNAME}-${PACKAGE_VERSION};
config.status: extensions/GNUmakefile.in \
include/xtables.h.in include/iptables/internal.h.in
#!/bin/bash
autoreconf -fi;
rm -Rf autom4te*.cache;
AC_INIT([iptables], [1.4.11.1])
# See libtool.info "Libtool's versioning system"
libxtables_vcurrent=6
libxtables_vage=0
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_INSTALL
AM_INIT_AUTOMAKE([-Wall])
AC_PROG_CC
AM_PROG_CC_C_O
AC_DISABLE_STATIC
AM_PROG_LIBTOOL
AC_ARG_WITH([kernel],
AS_HELP_STRING([--with-kernel=PATH],
[Path to kernel source/build directory]),
[kbuilddir="$withval"; ksourcedir="$withval";])
AC_ARG_WITH([kbuild],
AS_HELP_STRING([--with-kbuild=PATH],
[Path to kernel build directory [[/lib/modules/CURRENT/build]]]),
[kbuilddir="$withval"])
AC_ARG_WITH([ksource],
AS_HELP_STRING([--with-ksource=PATH],
[Path to kernel source directory [[/lib/modules/CURRENT/source]]]),
[ksourcedir="$withval"])
AC_ARG_WITH([xtlibdir],
AS_HELP_STRING([--with-xtlibdir=PATH],
[Path where to install Xtables extensions [[LIBEXECDIR/xtables]]]),
[xtlibdir="$withval"],
[xtlibdir="${libexecdir}/xtables"])
AC_ARG_ENABLE([ipv4],
AS_HELP_STRING([--disable-ipv4], [Do not build iptables]),
[enable_ipv4="$enableval"], [enable_ipv4="yes"])
AC_ARG_ENABLE([ipv6],
AS_HELP_STRING([--disable-ipv6], [Do not build ip6tables]),
[enable_ipv6="$enableval"], [enable_ipv6="yes"])
AC_ARG_ENABLE([largefile],
AS_HELP_STRING([--disable-largefile], [Do not build largefile support]),
[enable_largefile="$enableval"],
[enable_largefile="yes";
largefile_cppflags='-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64'])
AC_ARG_ENABLE([devel],
AS_HELP_STRING([--enable-devel],
[Install Xtables development headers]),
[enable_devel="$enableval"], [enable_devel="yes"])
AC_ARG_ENABLE([libipq],
AS_HELP_STRING([--enable-libipq], [Build and install libipq]))
AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
[Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),
[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
libiptc_LDFLAGS2="";
AX_CHECK_LINKER_FLAGS([-Wl,--no-as-needed],
[libiptc_LDFLAGS2="-Wl,--no-as-needed"])
AC_SUBST([libiptc_LDFLAGS2])
blacklist_modules="";
AC_CHECK_HEADER([linux/dccp.h])
if test "$ac_cv_header_linux_dccp_h" != "yes"; then
blacklist_modules="$blacklist_modules dccp";
fi;
AC_CHECK_HEADER([linux/ip_vs.h])
if test "$ac_cv_header_linux_ip_vs_h" != "yes"; then
blacklist_modules="$blacklist_modules ipvs";
fi;
AC_SUBST([blacklist_modules])
AM_CONDITIONAL([ENABLE_STATIC], [test "$enable_static" = "yes"])
AM_CONDITIONAL([ENABLE_SHARED], [test "$enable_shared" = "yes"])
AM_CONDITIONAL([ENABLE_IPV4], [test "$enable_ipv4" = "yes"])
AM_CONDITIONAL([ENABLE_IPV6], [test "$enable_ipv6" = "yes"])
AM_CONDITIONAL([ENABLE_LARGEFILE], [test "$enable_largefile" = "yes"])
AM_CONDITIONAL([ENABLE_DEVEL], [test "$enable_devel" = "yes"])
AM_CONDITIONAL([ENABLE_LIBIPQ], [test "$enable_libipq" = "yes"])
PKG_CHECK_MODULES([libnfnetlink], [libnfnetlink >= 1.0],
[nfnetlink=1], [nfnetlink=0])
AM_CONDITIONAL([HAVE_LIBNFNETLINK], [test "$nfnetlink" = 1])
regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
-Winline -pipe";
regular_CPPFLAGS="${largefile_cppflags} -D_REENTRANT \
-DXTABLES_LIBDIR=\\\"\${xtlibdir}\\\" -DXTABLES_INTERNAL";
kinclude_CPPFLAGS="";
if [[ -n "$kbuilddir" ]]; then
kinclude_CPPFLAGS="$kinclude_CPPFLAGS -I$kbuilddir/include";
fi;
if [[ -n "$ksourcedir" ]]; then
kinclude_CPPFLAGS="$kinclude_CPPFLAGS -I$ksourcedir/include";
fi;
pkgdatadir='${datadir}/xtables';
AC_SUBST([regular_CFLAGS])
AC_SUBST([regular_CPPFLAGS])
AC_SUBST([kinclude_CPPFLAGS])
AC_SUBST([kbuilddir])
AC_SUBST([ksourcedir])
AC_SUBST([xtlibdir])
AC_SUBST([pkgconfigdir])
AC_SUBST([pkgdatadir])
AC_SUBST([libxtables_vcurrent])
AC_SUBST([libxtables_vage])
libxtables_vmajor=$(($libxtables_vcurrent - $libxtables_vage));
AC_SUBST([libxtables_vmajor])
AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile
iptables/Makefile iptables/xtables.pc
libipq/Makefile libiptc/Makefile libiptc/libiptc.pc utils/Makefile
include/xtables.h include/iptables/internal.h])
AC_OUTPUT
LOCAL_PATH:= $(call my-dir)
#----------------------------------------------------------------
## extension
MY_srcdir:=$(LOCAL_PATH)
# Exclude some modules that are problematic to compile (types/header).
MY_excluded_modules:=TCPOPTSTRIP
MY_pfx_build_mod := $(patsubst ${MY_srcdir}/libxt_%.c,%,$(wildcard ${MY_srcdir}/libxt_*.c))
MY_pf4_build_mod := $(patsubst ${MY_srcdir}/libipt_%.c,%,$(wildcard ${MY_srcdir}/libipt_*.c))
MY_pf6_build_mod := $(patsubst ${MY_srcdir}/libip6t_%.c,%,$(wildcard ${MY_srcdir}/libip6t_*.c))
MY_pfx_build_mod := $(filter-out ${MY_excluded_modules} dccp ipvs,${MY_pfx_build_mod})
MY_pf4_build_mod := $(filter-out ${MY_excluded_modules} dccp ipvs,${MY_pf4_build_mod})
MY_pf6_build_mod := $(filter-out ${MY_excluded_modules} dccp ipvs,${MY_pf6_build_mod})
MY_pfx_objs := $(patsubst %,libxt_%.o,${MY_pfx_build_mod})
MY_pf4_objs := $(patsubst %,libipt_%.o,${MY_pf4_build_mod})
MY_pf6_objs := $(patsubst %,libip6t_%.o,${MY_pf6_build_mod})
#----------------------------------------------------------------
# libext
# TODO(jpa): Trun this into a function/macro as libext{,4,6} are all the same.
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS:=
LOCAL_MODULE:=libext
# LOCAL_MODULE_CLASS must be defined before calling $(local-intermediates-dir)
#
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
# LOCAL_PATH needed because of dirty #include "blabla.c"
LOCAL_C_INCLUDES:= \
$(LOCAL_PATH)/../include/ \
$(KERNEL_HEADERS) \
$(LOCAL_PATH)
LOCAL_CFLAGS:=-DNO_SHARED_LIBS=1
# The $* does not work as expected. It ends up empty. Even with SECONDEXPANSION.
# LOCAL_CFLAGS+=-D_INIT=lib$*_init
LOCAL_CFLAGS+=-DXTABLES_INTERNAL
# Accommodate arm-eabi-4.4.3 tools that don't set __ANDROID__
LOCAL_CFLAGS+=-D__ANDROID__
MY_initext_func := $(addprefix xt_,${MY_pfx_build_mod})
MY_GEN_INITEXT:= $(LOCAL_PATH)/gen_initext.c
$(info $(shell \
if [ ! -e $(MY_GEN_INITEXT) ]; then \
echo "GEN initext.c"; \
echo "" >$(MY_GEN_INITEXT); \
for i in $(MY_initext_func); do \
echo "extern void lib$${i}_init(void);" >>$(MY_GEN_INITEXT); \
done; \
echo "void init_extensions(void);" >>$(MY_GEN_INITEXT); \
echo "void init_extensions(void)" >>$(MY_GEN_INITEXT); \
echo "{" >>$(MY_GEN_INITEXT); \
for i in $(MY_initext_func); do \
echo " ""lib$${i}_init();" >>$(MY_GEN_INITEXT); \
sed "s/_init(void)/lib$${i}_init(void)/" $(LOCAL_PATH)/lib$${i}.c > $(LOCAL_PATH)/gen_lib$${i}.c; \
done; \
echo "}" >>$(MY_GEN_INITEXT); \
fi; ))
MY_lib_sources:= \
$(patsubst %,gen_libxt_%.c,${MY_pfx_build_mod})
LOCAL_SRC_FILES := \
gen_initext.c \
$(MY_lib_sources)
include $(BUILD_STATIC_LIBRARY)
#----------------------------------------------------------------
# libext4
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS:=
LOCAL_MODULE:=libext4
# LOCAL_MODULE_CLASS must be defined before calling $(local-intermediates-dir)
#
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
# LOCAL_PATH needed because of dirty #include "blabla.c"
LOCAL_C_INCLUDES:= \
$(LOCAL_PATH)/../include/ \
$(KERNEL_HEADERS) \
$(LOCAL_PATH)/
LOCAL_CFLAGS:=-DNO_SHARED_LIBS=1
# The $* does not work as expected. It ends up empty. Even with SECONDEXPANSION.
# LOCAL_CFLAGS+=-D_INIT=lib$*_init
LOCAL_CFLAGS+=-DXTABLES_INTERNAL
# Accommodate arm-eabi-4.4.3 tools that don't set __ANDROID__
LOCAL_CFLAGS+=-D__ANDROID__
MY_initext4_func := $(addprefix ipt_,${MY_pf4_build_mod})
MY_GEN_INITEXT4:= $(LOCAL_PATH)/gen_initext4.c
$(info $(shell \
if [ ! -e $(MY_GEN_INITEXT4) ]; then \
echo "GEN initext4.c"; \
echo "" >$(MY_GEN_INITEXT4); \
for i in $(MY_initext4_func); do \
echo "extern void lib$${i}_init(void);" >>$(MY_GEN_INITEXT4); \
done; \
echo "void init_extensions4(void);" >>$(MY_GEN_INITEXT4); \
echo "void init_extensions4(void)" >>$(MY_GEN_INITEXT4); \
echo "{" >>$(MY_GEN_INITEXT4); \
for i in $(MY_initext4_func); do \
echo " ""lib$${i}_init();" >>$(MY_GEN_INITEXT4); \
sed "s/_init(void)/lib$${i}_init(void)/" $(LOCAL_PATH)/lib$${i}.c > $(LOCAL_PATH)/gen_lib$${i}.c; \
done; \
echo "}" >>$(MY_GEN_INITEXT4); \
fi; ))
MY_lib_sources:= \
$(patsubst %,gen_libipt_%.c,${MY_pf4_build_mod})
LOCAL_SRC_FILES := \
gen_initext4.c \
$(MY_lib_sources)
include $(BUILD_STATIC_LIBRARY)
#----------------------------------------------------------------
# libext6
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS:=
LOCAL_MODULE:=libext6
# LOCAL_MODULE_CLASS must be defined before calling $(local-intermediates-dir)
#
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
# LOCAL_PATH needed because of dirty #include "blabla.c"
LOCAL_C_INCLUDES:= \
$(LOCAL_PATH)/../include/ \
$(KERNEL_HEADERS) \
$(LOCAL_PATH)
LOCAL_CFLAGS:=-DNO_SHARED_LIBS=1
# The $* does not work as expected. It ends up empty. Even with SECONDEXPANSION.
# LOCAL_CFLAGS+=-D_INIT=lib$*_init
LOCAL_CFLAGS+=-DXTABLES_INTERNAL
# Accommodate arm-eabi-4.4.3 tools that don't set __ANDROID__
LOCAL_CFLAGS+=-D__ANDROID__
MY_initext6_func := $(addprefix ip6t_,${MY_pf6_build_mod})
MY_GEN_INITEXT6:= $(LOCAL_PATH)/gen_initext6.c
$(info $(shell \
if [ ! -e $(MY_GEN_INITEXT6) ]; then \
echo "GEN initext6.c"; \
echo "" >$(MY_GEN_INITEXT6); \
for i in $(MY_initext6_func); do \
echo "extern void lib$${i}_init(void);" >>$(MY_GEN_INITEXT6); \
done; \
echo "void init_extensions6(void);" >>$(MY_GEN_INITEXT6); \
echo "void init_extensions6(void)" >>$(MY_GEN_INITEXT6); \
echo "{" >>$(MY_GEN_INITEXT6); \
for i in $(MY_initext6_func); do \
echo " ""lib$${i}_init();" >>$(MY_GEN_INITEXT6); \
sed "s/_init(void)/lib$${i}_init(void)/" $(LOCAL_PATH)/lib$${i}.c > $(LOCAL_PATH)/gen_lib$${i}.c; \
done; \
echo "}" >>$(MY_GEN_INITEXT6); \
fi; ))
MY_lib_sources:= \
$(patsubst %,gen_libip6t_%.c,${MY_pf6_build_mod})
LOCAL_SRC_FILES := \
gen_initext6.c \
$(MY_lib_sources)
include $(BUILD_STATIC_LIBRARY)
#----------------------------------------------------------------
# -*- 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_srcdir}/include ${kinclude_CPPFLAGS}
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
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,%,$(wildcard ${srcdir}/libxt_*.c))
@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(wildcard ${srcdir}/libipt_*.c))
@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(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})
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 \
matches4.man matches6.man \
targets4.man targets6.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}[46].man initext.c initext4.c initext6.c;
distclean: clean
rm -f .*.d .*.dd;
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 $@ $<;
lib%.oo: ${srcdir}/lib%.c
${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
#
# 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 = $(sort $(shell echo $(1) | LC_ALL=POSIX grep -Eo '\b[[:lower:][:digit:]_]+\b'))
ex_targets = $(sort $(shell echo $(1) | LC_ALL=POSIX grep -Eo '\b[[:upper:][:digit:]_]+\b'))
man_run = \
${AM_VERBOSE_GEN} \
for ext in $(1); do \
f="${srcdir}/libxt_$$ext.man"; \
cf="${srcdir}/libxt_$$ext.c"; \
if [ -f "$$f" ] && grep -Eq "$(3)|NFPROTO_UNSPEC" "$$cf"; then \
echo -e "\t+ $$f" >&2; \
echo ".SS $$ext"; \
cat "$$f" || exit $$?; \
continue; \
fi; \
f="${srcdir}/lib$(2)t_$$ext.man"; \
if [ -f "$$f" ]; then \
echo -e "\t+ $$f" >&2; \
echo ".SS $$ext"; \
cat "$$f" || exit $$?; \
continue; \
fi; \
done >$@;
matches4.man: .initext.dd .initext4.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod}),ip,NFPROTO_IPV4)
matches6.man: .initext.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_matches,${pfx_build_mod} ${pf6_build_mod}),ip6,NFPROTO_IPV6)
targets4.man: .initext.dd .initext4.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod}),ip,NFPROTO_IPV4)
targets6.man: .initext.dd .initext6.dd $(wildcard ${srcdir}/lib*.man)
$(call man_run,$(call ex_targets,${pfx_build_mod} ${pf6_build_mod}),ip6,NFPROTO_IPV6)
/*
* 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
#!/bin/sh
# This is for working around Android.mk's incapability to handle $* in CFLAGS,
# even with SECONDEXPNASION.
# LOCAL_CFLAGS:=-D_INIT=$*_init
f=${1##*/}
f=${f%%.*}
sed "s/\([ ]*\)\(_init\)\(([ ]*void\)/\1${f}_init\3/" $1
#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 \"%s\"", 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);
}
Turn on kernel logging of matching packets. When this option is set
for a rule, the Linux kernel will print some information on all
matching packets (like most IPv6 IPv6-header fields) via the kernel log
(where it can be read with
.I dmesg
or
.IR syslogd (8)).
This is a "non-terminating target", i.e. rule traversal continues at
the next rule. So if you want to LOG the packets you refuse, use two
separate rules with the same matching criteria, first using target LOG
then DROP (or REJECT).
.TP
\fB\-\-log\-level\fP \fIlevel\fP
Level of logging (numeric or see \fIsyslog.conf\fP(5)).
.TP
\fB\-\-log\-prefix\fP \fIprefix\fP
Prefix log messages with the specified prefix; up to 29 letters long,
and useful for distinguishing messages in the logs.
.TP
\fB\-\-log\-tcp\-sequence\fP
Log TCP sequence numbers. This is a security risk if the log is
readable by users.
.TP
\fB\-\-log\-tcp\-options\fP
Log options from the TCP packet header.
.TP
\fB\-\-log\-ip\-options\fP
Log options from the IPv6 packet header.
.TP
\fB\-\-log\-uid\fP
Log the userid of the process which generated the packet.
/* 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,
\fBicmp6\-port\-unreachable\fP or
\fBport\-unreach\fP
which return the appropriate ICMPv6 error message (\fBport\-unreach\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.
#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_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);
}
This module matches the parameters in Destination Options header
.TP
[\fB!\fP] \fB\-\-dst\-len\fP \fIlength\fP
Total length of this header in octets.
.TP
\fB\-\-dst\-opts\fP \fItype\fP[\fB:\fP\fIlength\fP][\fB,\fP\fItype\fP[\fB:\fP\fIlength\fP]...]
numeric type of option and the length of the option data in octets.
/* Shared library add-on to ip6tables to add EUI64 address checking support. */
#include <xtables.h>
static struct xtables_match eui64_mt6_reg = {
.name = "eui64",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(int)),
.userspacesize = XT_ALIGN(sizeof(int)),
};
void _init(void)
{
xtables_register_match(&eui64_mt6_reg);
}
This module matches the EUI-64 part of a stateless autoconfigured IPv6 address.
It compares the EUI-64 derived from the source MAC address in Ethernet frame
with the lower 64 bits of the IPv6 source address. But "Universal/Local"
bit is not compared. This module doesn't match other link layer frame, and
is only valid in the
.BR PREROUTING ,
.BR INPUT
and
.BR FORWARD
chains.
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_frag.h>
enum {
O_FRAGID = 0,
O_FRAGLEN,
O_FRAGRES,
O_FRAGFIRST,
O_FRAGMORE,
O_FRAGLAST,
F_FRAGMORE = 1 << O_FRAGMORE,
F_FRAGLAST = 1 << O_FRAGLAST,
};
static void frag_help(void)
{
printf(
"frag match options:\n"
"[!] --fragid id[:id] match the id (range)\n"
"[!] --fraglen length total length of this header\n"
" --fragres check the reserved field too\n"
" --fragfirst matches on the first fragment\n"
" [--fragmore|--fraglast] there are more fragments or this\n"
" is the last one\n");
}
#define s struct ip6t_frag
static const struct xt_option_entry frag_opts[] = {
{.name = "fragid", .id = O_FRAGID, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, ids)},
{.name = "fraglen", .id = O_FRAGLEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
{.name = "fragres", .id = O_FRAGRES, .type = XTTYPE_NONE},
{.name = "fragfirst", .id = O_FRAGFIRST, .type = XTTYPE_NONE},
{.name = "fragmore", .id = O_FRAGMORE, .type = XTTYPE_NONE,
.excl = F_FRAGLAST},
{.name = "fraglast", .id = O_FRAGLAST, .type = XTTYPE_NONE,
.excl = F_FRAGMORE},
XTOPT_TABLEEND,
};
#undef s
static void frag_parse(struct xt_option_call *cb)
{
struct ip6t_frag *fraginfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_FRAGID:
if (cb->nvals == 1)
fraginfo->ids[1] = fraginfo->ids[0];
break;
case O_FRAGRES:
fraginfo->flags |= IP6T_FRAG_RES;
break;
case O_FRAGFIRST:
fraginfo->flags |= IP6T_FRAG_FST;
break;
case O_FRAGMORE:
fraginfo->flags |= IP6T_FRAG_MF;
break;
case O_FRAGLAST:
fraginfo->flags |= IP6T_FRAG_NMF;
break;
}
}
static void
print_ids(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFFFFFFFF || invert) {
printf("%s", name);
if (min == max)
printf(":%s%u", inv, min);
else
printf("s:%s%u:%u", inv, min, max);
}
}
static void frag_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_frag *frag = (struct ip6t_frag *)match->data;
printf(" frag ");
print_ids("id", frag->ids[0], frag->ids[1],
frag->invflags & IP6T_FRAG_INV_IDS);
if (frag->flags & IP6T_FRAG_LEN) {
printf(" length:%s%u",
frag->invflags & IP6T_FRAG_INV_LEN ? "!" : "",
frag->hdrlen);
}
if (frag->flags & IP6T_FRAG_RES)
printf(" reserved");
if (frag->flags & IP6T_FRAG_FST)
printf(" first");
if (frag->flags & IP6T_FRAG_MF)
printf(" more");
if (frag->flags & IP6T_FRAG_NMF)
printf(" last");
if (frag->invflags & ~IP6T_FRAG_INV_MASK)
printf(" Unknown invflags: 0x%X",
frag->invflags & ~IP6T_FRAG_INV_MASK);
}
static void frag_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data;
if (!(fraginfo->ids[0] == 0
&& fraginfo->ids[1] == 0xFFFFFFFF)) {
printf("%s --fragid ",
(fraginfo->invflags & IP6T_FRAG_INV_IDS) ? " !" : "");
if (fraginfo->ids[0]
!= fraginfo->ids[1])
printf("%u:%u",
fraginfo->ids[0],
fraginfo->ids[1]);
else
printf("%u",
fraginfo->ids[0]);
}
if (fraginfo->flags & IP6T_FRAG_LEN) {
printf("%s --fraglen %u",
(fraginfo->invflags & IP6T_FRAG_INV_LEN) ? " !" : "",
fraginfo->hdrlen);
}
if (fraginfo->flags & IP6T_FRAG_RES)
printf(" --fragres");
if (fraginfo->flags & IP6T_FRAG_FST)
printf(" --fragfirst");
if (fraginfo->flags & IP6T_FRAG_MF)
printf(" --fragmore");
if (fraginfo->flags & IP6T_FRAG_NMF)
printf(" --fraglast");
}
static struct xtables_match frag_mt6_reg = {
.name = "frag",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_frag)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_frag)),
.help = frag_help,
.print = frag_print,
.save = frag_save,
.x6_parse = frag_parse,
.x6_options = frag_opts,
};
void
_init(void)
{
xtables_register_match(&frag_mt6_reg);
}
This module matches the parameters in Fragment header.
.TP
[\fB!\fP] \fB\-\-fragid\fP \fIid\fP[\fB:\fP\fIid\fP]
Matches the given Identification or range of it.
.TP
[\fB!\fP] \fB\-\-fraglen\fP \fIlength\fP
This option cannot be used with kernel version 2.6.10 or later. The length of
Fragment header is static and this option doesn't make sense.
.TP
\fB\-\-fragres\fP
Matches if the reserved fields are filled with zero.
.TP
\fB\-\-fragfirst\fP
Matches on the first fragment.
.TP
\fB\-\-fragmore\fP
Matches if there are more fragments.
.TP
\fB\-\-fraglast\fP
Matches if this is the last fragment.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
#define DEBUG 0
enum {
O_HBH_LEN = 0,
O_HBH_OPTS,
};
static void hbh_help(void)
{
printf(
"hbh match options:\n"
"[!] --hbh-len length total length of this header\n"
" --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
" Options and its length (list, max: %d)\n",
IP6T_OPTS_OPTSNR);
}
static const struct xt_option_entry hbh_opts[] = {
{.name = "hbh-len", .id = O_HBH_LEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(struct ip6t_opts, hdrlen)},
{.name = "hbh-opts", .id = O_HBH_OPTS, .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,
"hbh: 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,
"hbh: 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 has not got length");
opts[i] |= parse_opts_num(range, "length") & 0xFF;
} else {
opts[i] |= (0x00FF);
}
#if 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);
#if DEBUG
printf("addr nr: %d\n", i);
#endif
return i;
}
static void hbh_parse(struct xt_option_call *cb)
{
struct ip6t_opts *optinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_HBH_LEN:
if (cb->invert)
optinfo->invflags |= IP6T_OPTS_INV_LEN;
break;
case O_HBH_OPTS:
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;
for(i=0; i<optsnr; i++){
printf("%c", (i==0)?' ':',');
printf("%d", (optsp[i] & 0xFF00)>>8);
if ((optsp[i] & 0x00FF) != 0x00FF){
printf(":%d", (optsp[i] & 0x00FF));
}
}
}
static void hbh_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
printf(" hbh");
if (optinfo->flags & IP6T_OPTS_LEN) {
printf(" length");
printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "");
printf("%u", 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 hbh_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 --hbh-len %u",
(optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "",
optinfo->hdrlen);
}
if (optinfo->flags & IP6T_OPTS_OPTS)
printf(" --hbh-opts");
print_options(optinfo->optsnr, (uint16_t *)optinfo->opts);
}
static struct xtables_match hbh_mt6_reg = {
.name = "hbh",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_opts)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)),
.help = hbh_help,
.print = hbh_print,
.save = hbh_save,
.x6_parse = hbh_parse,
.x6_options = hbh_opts,
};
void
_init(void)
{
xtables_register_match(&hbh_mt6_reg);
}
This module matches the parameters in Hop-by-Hop Options header
.TP
[\fB!\fP] \fB\-\-hbh\-len\fP \fIlength\fP
Total length of this header in octets.
.TP
\fB\-\-hbh\-opts\fP \fItype\fP[\fB:\fP\fIlength\fP][\fB,\fP\fItype\fP[\fB:\fP\fIlength\fP]...]
numeric type of option and the length of the option data in octets.
/*
* IPv6 Hop Limit matching module
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's ttl match
* This program is released under the terms of GNU GPL
* Cleanups by Stephane Ouellette <ouellettes@videotron.ca>
*/
#include <stdio.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_hl.h>
enum {
O_HL_EQ = 0,
O_HL_LT,
O_HL_GT,
F_HL_EQ = 1 << O_HL_EQ,
F_HL_LT = 1 << O_HL_LT,
F_HL_GT = 1 << O_HL_GT,
F_ANY = F_HL_EQ | F_HL_LT | F_HL_GT,
};
static void hl_help(void)
{
printf(
"hl match options:\n"
"[!] --hl-eq value Match hop limit value\n"
" --hl-lt value Match HL < value\n"
" --hl-gt value Match HL > value\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_EQ:
info->mode = cb->invert ? IP6T_HL_NE : IP6T_HL_EQ;
break;
case O_HL_LT:
info->mode = IP6T_HL_LT;
break;
case O_HL_GT:
info->mode = IP6T_HL_GT;
break;
}
}
static void hl_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_ANY))
xtables_error(PARAMETER_PROBLEM,
"HL match: You must specify one of "
"`--hl-eq', `--hl-lt', `--hl-gt'");
}
static void hl_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
static const char *const op[] = {
[IP6T_HL_EQ] = "==",
[IP6T_HL_NE] = "!=",
[IP6T_HL_LT] = "<",
[IP6T_HL_GT] = ">" };
const struct ip6t_hl_info *info =
(struct ip6t_hl_info *) match->data;
printf(" HL match HL %s %u", op[info->mode], info->hop_limit);
}
static void hl_save(const void *ip, const struct xt_entry_match *match)
{
static const char *const op[] = {
[IP6T_HL_EQ] = "--hl-eq",
[IP6T_HL_NE] = "! --hl-eq",
[IP6T_HL_LT] = "--hl-lt",
[IP6T_HL_GT] = "--hl-gt" };
const struct ip6t_hl_info *info =
(struct ip6t_hl_info *) match->data;
printf(" %s %u", op[info->mode], info->hop_limit);
}
#define s struct ip6t_hl_info
static const struct xt_option_entry hl_opts[] = {
{.name = "hl-lt", .id = O_HL_LT, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl-gt", .id = O_HL_GT, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl-eq", .id = O_HL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
{.name = "hl", .id = O_HL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)},
XTOPT_TABLEEND,
};
#undef s
static struct xtables_match hl_mt6_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_match(&hl_mt6_reg);
}
This module matches the Hop Limit field in the IPv6 header.
.TP
[\fB!\fP] \fB\-\-hl\-eq\fP \fIvalue\fP
Matches if Hop Limit equals \fIvalue\fP.
.TP
\fB\-\-hl\-lt\fP \fIvalue\fP
Matches if Hop Limit is less than \fIvalue\fP.
.TP
\fB\-\-hl\-gt\fP \fIvalue\fP
Matches if Hop Limit is greater than \fIvalue\fP.
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip6_tables.h */
#include <linux/netfilter_ipv6/ip6_tables.h>
enum {
O_ICMPV6_TYPE = 0,
};
struct icmpv6_names {
const char *name;
uint8_t type;
uint8_t code_min, code_max;
};
static const struct icmpv6_names icmpv6_codes[] = {
{ "destination-unreachable", 1, 0, 0xFF },
{ "no-route", 1, 0, 0 },
{ "communication-prohibited", 1, 1, 1 },
{ "address-unreachable", 1, 3, 3 },
{ "port-unreachable", 1, 4, 4 },
{ "packet-too-big", 2, 0, 0xFF },
{ "time-exceeded", 3, 0, 0xFF },
/* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
{ "ttl-zero-during-transit", 3, 0, 0 },
{ "ttl-zero-during-reassembly", 3, 1, 1 },
{ "parameter-problem", 4, 0, 0xFF },
{ "bad-header", 4, 0, 0 },
{ "unknown-header-type", 4, 1, 1 },
{ "unknown-option", 4, 2, 2 },
{ "echo-request", 128, 0, 0xFF },
/* Alias */ { "ping", 128, 0, 0xFF },
{ "echo-reply", 129, 0, 0xFF },
/* Alias */ { "pong", 129, 0, 0xFF },
{ "router-solicitation", 133, 0, 0xFF },
{ "router-advertisement", 134, 0, 0xFF },
{ "neighbour-solicitation", 135, 0, 0xFF },
/* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
{ "neighbour-advertisement", 136, 0, 0xFF },
/* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
{ "redirect", 137, 0, 0xFF },
};
static void
print_icmpv6types(void)
{
unsigned int i;
printf("Valid ICMPv6 Types:");
for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i) {
if (i && icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
&& (icmpv6_codes[i].code_max
== icmpv6_codes[i-1].code_max))
printf(" (%s)", icmpv6_codes[i].name);
else
printf("\n %s", icmpv6_codes[i].name);
}
else
printf("\n%s", icmpv6_codes[i].name);
}
printf("\n");
}
static void icmp6_help(void)
{
printf(
"icmpv6 match options:\n"
"[!] --icmpv6-type typename match icmpv6 type\n"
" (or numeric type or type/code)\n");
print_icmpv6types();
}
static const struct xt_option_entry icmp6_opts[] = {
{.name = "icmpv6-type", .id = O_ICMPV6_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT},
XTOPT_TABLEEND,
};
static void
parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[])
{
static const unsigned int limit = ARRAY_SIZE(icmpv6_codes);
unsigned int match = limit;
unsigned int i;
for (i = 0; i < limit; i++) {
if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))
== 0) {
if (match != limit)
xtables_error(PARAMETER_PROBLEM,
"Ambiguous ICMPv6 type `%s':"
" `%s' or `%s'?",
icmpv6type,
icmpv6_codes[match].name,
icmpv6_codes[i].name);
match = i;
}
}
if (match != limit) {
*type = icmpv6_codes[match].type;
code[0] = icmpv6_codes[match].code_min;
code[1] = icmpv6_codes[match].code_max;
} else {
char *slash;
char buffer[strlen(icmpv6type) + 1];
unsigned int number;
strcpy(buffer, icmpv6type);
slash = strchr(buffer, '/');
if (slash)
*slash = '\0';
if (!xtables_strtoui(buffer, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid ICMPv6 type `%s'\n", buffer);
*type = number;
if (slash) {
if (!xtables_strtoui(slash+1, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid ICMPv6 code `%s'\n",
slash+1);
code[0] = code[1] = number;
} else {
code[0] = 0;
code[1] = 0xFF;
}
}
}
static void icmp6_init(struct xt_entry_match *m)
{
struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)m->data;
icmpv6info->code[1] = 0xFF;
}
static void icmp6_parse(struct xt_option_call *cb)
{
struct ip6t_icmp *icmpv6info = cb->data;
xtables_option_parse(cb);
parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code);
if (cb->invert)
icmpv6info->invflags |= IP6T_ICMP_INV;
}
static void print_icmpv6type(uint8_t type,
uint8_t code_min, uint8_t code_max,
int invert,
int numeric)
{
if (!numeric) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(icmpv6_codes); ++i)
if (icmpv6_codes[i].type == type
&& icmpv6_codes[i].code_min == code_min
&& icmpv6_codes[i].code_max == code_max)
break;
if (i != ARRAY_SIZE(icmpv6_codes)) {
printf(" %s%s",
invert ? "!" : "",
icmpv6_codes[i].name);
return;
}
}
if (invert)
printf(" !");
printf("type %u", type);
if (code_min == code_max)
printf(" code %u", code_min);
else if (code_min != 0 || code_max != 0xFF)
printf(" codes %u-%u", code_min, code_max);
}
static void icmp6_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
printf(" ipv6-icmp");
print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1],
icmpv6->invflags & IP6T_ICMP_INV,
numeric);
if (icmpv6->invflags & ~IP6T_ICMP_INV)
printf(" Unknown invflags: 0x%X",
icmpv6->invflags & ~IP6T_ICMP_INV);
}
static void icmp6_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data;
if (icmpv6->invflags & IP6T_ICMP_INV)
printf(" !");
printf(" --icmpv6-type %u", icmpv6->type);
if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF)
printf("/%u", icmpv6->code[0]);
}
static struct xtables_match icmp6_mt6_reg = {
.name = "icmp6",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_icmp)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_icmp)),
.help = icmp6_help,
.init = icmp6_init,
.print = icmp6_print,
.save = icmp6_save,
.x6_parse = icmp6_parse,
.x6_options = icmp6_opts,
};
void _init(void)
{
xtables_register_match(&icmp6_mt6_reg);
}
This extension can be used if `\-\-protocol ipv6\-icmp' or `\-\-protocol icmpv6' is
specified. It provides the following option:
.TP
[\fB!\fP] \fB\-\-icmpv6\-type\fP \fItype\fP[\fB/\fP\fIcode\fP]|\fItypename\fP
This allows specification of the ICMPv6 type, which can be a numeric
ICMPv6
.IR type ,
.IR type
and
.IR code ,
or one of the ICMPv6 type names shown by the command
.nf
ip6tables \-p ipv6\-icmp \-h
.fi
/* ipv6header match - matches IPv6 packets based
on whether they contain certain headers */
/* Original idea: Brad Chapman
* Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
enum {
O_HEADER = 0,
O_SOFT,
};
/* A few hardcoded protocols for 'all' and in case the user has no
* /etc/protocols */
struct pprot {
char *name;
uint8_t num;
};
struct numflag {
uint8_t proto;
uint8_t flag;
};
static const struct pprot chain_protos[] = {
{ "hop-by-hop", IPPROTO_HOPOPTS },
{ "protocol", IPPROTO_RAW },
{ "hop", IPPROTO_HOPOPTS },
{ "dst", IPPROTO_DSTOPTS },
{ "route", IPPROTO_ROUTING },
{ "frag", IPPROTO_FRAGMENT },
{ "auth", IPPROTO_AH },
{ "esp", IPPROTO_ESP },
{ "none", IPPROTO_NONE },
{ "prot", IPPROTO_RAW },
{ "0", IPPROTO_HOPOPTS },
{ "60", IPPROTO_DSTOPTS },
{ "43", IPPROTO_ROUTING },
{ "44", IPPROTO_FRAGMENT },
{ "51", IPPROTO_AH },
{ "50", IPPROTO_ESP },
{ "59", IPPROTO_NONE },
{ "255", IPPROTO_RAW },
/* { "all", 0 }, */
};
static const struct numflag chain_flags[] = {
{ IPPROTO_HOPOPTS, MASK_HOPOPTS },
{ IPPROTO_DSTOPTS, MASK_DSTOPTS },
{ IPPROTO_ROUTING, MASK_ROUTING },
{ IPPROTO_FRAGMENT, MASK_FRAGMENT },
{ IPPROTO_AH, MASK_AH },
{ IPPROTO_ESP, MASK_ESP },
{ IPPROTO_NONE, MASK_NONE },
{ IPPROTO_RAW, MASK_PROTO },
};
static const char *
proto_to_name(uint8_t proto, int nolookup)
{
unsigned int i;
if (proto && !nolookup) {
const struct protoent *pent = getprotobynumber(proto);
if (pent)
return pent->p_name;
}
for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
if (chain_protos[i].num == proto)
return chain_protos[i].name;
return NULL;
}
static uint16_t
name_to_proto(const char *s)
{
unsigned int proto=0;
const struct protoent *pent;
if ((pent = getprotobyname(s)))
proto = pent->p_proto;
else {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(chain_protos); ++i)
if (strcmp(s, chain_protos[i].name) == 0) {
proto = chain_protos[i].num;
break;
}
if (i == ARRAY_SIZE(chain_protos))
xtables_error(PARAMETER_PROBLEM,
"unknown header `%s' specified",
s);
}
return proto;
}
static unsigned int
add_proto_to_mask(int proto){
unsigned int i=0, flag=0;
for (i = 0; i < ARRAY_SIZE(chain_flags); ++i)
if (proto == chain_flags[i].proto){
flag = chain_flags[i].flag;
break;
}
if (i == ARRAY_SIZE(chain_flags))
xtables_error(PARAMETER_PROBLEM,
"unknown header `%d' specified",
proto);
return flag;
}
static void ipv6header_help(void)
{
printf(
"ipv6header match options:\n"
"[!] --header headers Type of header to match, by name\n"
" names: hop,dst,route,frag,auth,esp,none,proto\n"
" long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
" ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
" numbers: 0,60,43,44,51,50,59\n"
"--soft The header CONTAINS the specified extensions\n");
}
static const struct xt_option_entry ipv6header_opts[] = {
{.name = "header", .id = O_HEADER, .type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_INVERT},
{.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
static unsigned int
parse_header(const char *flags) {
unsigned int ret = 0;
char *ptr;
char *buffer;
buffer = strdup(flags);
for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ","))
ret |= add_proto_to_mask(name_to_proto(ptr));
free(buffer);
return ret;
}
static void ipv6header_parse(struct xt_option_call *cb)
{
struct ip6t_ipv6header_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_HEADER:
if (!(info->matchflags = parse_header(cb->arg)))
xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
if (cb->invert)
info->invflags |= 0xFF;
break;
case O_SOFT:
info->modeflag |= 0xFF;
break;
}
}
static void
print_header(uint8_t flags){
int have_flag = 0;
while (flags) {
unsigned int i;
for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
if (have_flag)
printf(",");
printf("%s", proto_to_name(chain_flags[i].proto,0));
have_flag = 1;
flags &= ~chain_flags[i].flag;
}
if (!have_flag)
printf("NONE");
}
static void ipv6header_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
printf(" ipv6header");
if (info->matchflags || info->invflags) {
printf(" flags:%s", info->invflags ? "!" : "");
if (numeric)
printf("0x%02X", info->matchflags);
else {
print_header(info->matchflags);
}
}
if (info->modeflag)
printf(" soft");
}
static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
printf("%s --header ", info->invflags ? " !" : "");
print_header(info->matchflags);
if (info->modeflag)
printf(" --soft");
}
static struct xtables_match ipv6header_mt6_reg = {
.name = "ipv6header",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
.help = ipv6header_help,
.print = ipv6header_print,
.save = ipv6header_save,
.x6_parse = ipv6header_parse,
.x6_options = ipv6header_opts,
};
void _init(void)
{
xtables_register_match(&ipv6header_mt6_reg);
}
This module matches IPv6 extension headers and/or upper layer header.
.TP
\fB\-\-soft\fP
Matches if the packet includes \fBany\fP of the headers specified with
\fB\-\-header\fP.
.TP
[\fB!\fP] \fB\-\-header\fP \fIheader\fP[\fB,\fP\fIheader\fP...]
Matches the packet which EXACTLY includes all specified headers. The headers
encapsulated with ESP header are out of scope.
Possible \fIheader\fP types can be:
.TP
\fBhop\fP|\fBhop\-by\-hop\fP
Hop-by-Hop Options header
.TP
\fBdst\fP
Destination Options header
.TP
\fBroute\fP
Routing header
.TP
\fBfrag\fP
Fragment header
.TP
\fBauth\fP
Authentication header
.TP
\fBesp\fP
Encapsulating Security Payload header
.TP
\fBnone\fP
No Next header which matches 59 in the 'Next Header field' of IPv6 header or
any IPv6 extension headers
.TP
\fBproto\fP
which matches any upper layer protocol header. A protocol name from
/etc/protocols and numeric value also allowed. The number 255 is equivalent to
\fBproto\fP.
/* Shared library add-on to ip6tables to add mobility header support. */
/*
* Copyright (C)2006 USAGI/WIDE Project
*
* 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.
*
* Author:
* Masahide NAKAMURA @USAGI <masahide.nakamura.cz@hitachi.com>
*
* Based on libip6t_{icmpv6,udp}.c
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_mh.h>
enum {
O_MH_TYPE = 0,
};
struct mh_name {
const char *name;
uint8_t type;
};
static const struct mh_name mh_names[] = {
{ "binding-refresh-request", 0, },
/* Alias */ { "brr", 0, },
{ "home-test-init", 1, },
/* Alias */ { "hoti", 1, },
{ "careof-test-init", 2, },
/* Alias */ { "coti", 2, },
{ "home-test", 3, },
/* Alias */ { "hot", 3, },
{ "careof-test", 4, },
/* Alias */ { "cot", 4, },
{ "binding-update", 5, },
/* Alias */ { "bu", 5, },
{ "binding-acknowledgement", 6, },
/* Alias */ { "ba", 6, },
{ "binding-error", 7, },
/* Alias */ { "be", 7, },
};
static void print_types_all(void)
{
unsigned int i;
printf("Valid MH types:");
for (i = 0; i < ARRAY_SIZE(mh_names); ++i) {
if (i && mh_names[i].type == mh_names[i-1].type)
printf(" (%s)", mh_names[i].name);
else
printf("\n%s", mh_names[i].name);
}
printf("\n");
}
static void mh_help(void)
{
printf(
"mh match options:\n"
"[!] --mh-type type[:type] match mh type\n");
print_types_all();
}
static void mh_init(struct xt_entry_match *m)
{
struct ip6t_mh *mhinfo = (struct ip6t_mh *)m->data;
mhinfo->types[1] = 0xFF;
}
static unsigned int name_to_type(const char *name)
{
int namelen = strlen(name);
static const unsigned int limit = ARRAY_SIZE(mh_names);
unsigned int match = limit;
unsigned int i;
for (i = 0; i < limit; i++) {
if (strncasecmp(mh_names[i].name, name, namelen) == 0) {
int len = strlen(mh_names[i].name);
if (match == limit || len == namelen)
match = i;
}
}
if (match != limit) {
return mh_names[match].type;
} else {
unsigned int number;
if (!xtables_strtoui(name, NULL, &number, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"Invalid MH type `%s'\n", name);
return number;
}
}
static void parse_mh_types(const char *mhtype, uint8_t *types)
{
char *buffer;
char *cp;
buffer = strdup(mhtype);
if ((cp = strchr(buffer, ':')) == NULL)
types[0] = types[1] = name_to_type(buffer);
else {
*cp = '\0';
cp++;
types[0] = buffer[0] ? name_to_type(buffer) : 0;
types[1] = cp[0] ? name_to_type(cp) : 0xFF;
if (types[0] > types[1])
xtables_error(PARAMETER_PROBLEM,
"Invalid MH type range (min > max)");
}
free(buffer);
}
static void mh_parse(struct xt_option_call *cb)
{
struct ip6t_mh *mhinfo = cb->data;
xtables_option_parse(cb);
parse_mh_types(cb->arg, mhinfo->types);
if (cb->invert)
mhinfo->invflags |= IP6T_MH_INV_TYPE;
}
static const char *type_to_name(uint8_t type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(mh_names); ++i)
if (mh_names[i].type == type)
return mh_names[i].name;
return NULL;
}
static void print_type(uint8_t type, int numeric)
{
const char *name;
if (numeric || !(name = type_to_name(type)))
printf("%u", type);
else
printf("%s", name);
}
static void print_types(uint8_t min, uint8_t max, int invert, int numeric)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFF || invert) {
printf(" ");
if (min == max) {
printf("%s", inv);
print_type(min, numeric);
} else {
printf("%s", inv);
print_type(min, numeric);
printf(":");
print_type(max, numeric);
}
}
}
static void mh_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
printf(" mh");
print_types(mhinfo->types[0], mhinfo->types[1],
mhinfo->invflags & IP6T_MH_INV_TYPE,
numeric);
if (mhinfo->invflags & ~IP6T_MH_INV_MASK)
printf(" Unknown invflags: 0x%X",
mhinfo->invflags & ~IP6T_MH_INV_MASK);
}
static void mh_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data;
if (mhinfo->types[0] == 0 && mhinfo->types[1] == 0xFF)
return;
if (mhinfo->invflags & IP6T_MH_INV_TYPE)
printf(" !");
if (mhinfo->types[0] != mhinfo->types[1])
printf(" --mh-type %u:%u", mhinfo->types[0], mhinfo->types[1]);
else
printf(" --mh-type %u", mhinfo->types[0]);
}
static const struct xt_option_entry mh_opts[] = {
{.name = "mh-type", .id = O_MH_TYPE, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
XTOPT_TABLEEND,
};
static struct xtables_match mh_mt6_reg = {
.name = "mh",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_mh)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_mh)),
.help = mh_help,
.init = mh_init,
.x6_parse = mh_parse,
.print = mh_print,
.save = mh_save,
.x6_options = mh_opts,
};
void _init(void)
{
xtables_register_match(&mh_mt6_reg);
}
This extension is loaded if `\-\-protocol ipv6\-mh' or `\-\-protocol mh' is
specified. It provides the following option:
.TP
[\fB!\fP] \fB\-\-mh\-type\fP \fItype\fP[\fB:\fP\fItype\fP]
This allows specification of the Mobility Header(MH) type, which can be
a numeric MH
.IR type ,
.IR type
or one of the MH type names shown by the command
.nf
ip6tables \-p ipv6\-mh \-h
.fi
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv6/ip6t_rt.h>
#include <arpa/inet.h>
enum {
O_RT_TYPE = 0,
O_RT_SEGSLEFT,
O_RT_LEN,
O_RT0RES,
O_RT0ADDRS,
O_RT0NSTRICT,
F_RT_TYPE = 1 << O_RT_TYPE,
F_RT0ADDRS = 1 << O_RT0ADDRS,
};
static void rt_help(void)
{
printf(
"rt match options:\n"
"[!] --rt-type type match the type\n"
"[!] --rt-segsleft num[:num] match the Segments Left field (range)\n"
"[!] --rt-len length total length of this header\n"
" --rt-0-res check the reserved field too (type 0)\n"
" --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n"
" --rt-0-not-strict List of Type=0 addresses not a strict list\n",
IP6T_RT_HOPS);
}
#define s struct ip6t_rt
static const struct xt_option_entry rt_opts[] = {
{.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)},
{.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)},
{.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
{.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE},
{.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING},
{.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
#undef s
static const char *
addr_to_numeric(const struct in6_addr *addrp)
{
static char buf[50+1];
return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
}
static struct in6_addr *
numeric_to_addr(const char *num)
{
static struct in6_addr ap;
int err;
if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
return &ap;
#ifdef DEBUG
fprintf(stderr, "\nnumeric2addr: %d\n", err);
#endif
xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
return (struct in6_addr *)NULL;
}
static int
parse_addresses(const char *addrstr, struct in6_addr *addrp)
{
char *buffer, *cp, *next;
unsigned int i;
buffer = strdup(addrstr);
if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
{
next=strchr(cp, ',');
if (next) *next++='\0';
memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
#if DEBUG
printf("addr str: %s\n", cp);
printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
#endif
}
if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
free(buffer);
#if DEBUG
printf("addr nr: %d\n", i);
#endif
return i;
}
static void rt_parse(struct xt_option_call *cb)
{
struct ip6t_rt *rtinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_RT_TYPE:
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_TYP;
rtinfo->flags |= IP6T_RT_TYP;
break;
case O_RT_SEGSLEFT:
if (cb->nvals == 1)
rtinfo->segsleft[1] = rtinfo->segsleft[0];
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_SGS;
rtinfo->flags |= IP6T_RT_SGS;
break;
case O_RT_LEN:
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_LEN;
rtinfo->flags |= IP6T_RT_LEN;
break;
case O_RT0RES:
if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
rtinfo->invflags & IP6T_RT_INV_TYP)
xtables_error(PARAMETER_PROBLEM,
"`--rt-type 0' required before `--rt-0-res'");
rtinfo->flags |= IP6T_RT_RES;
break;
case O_RT0ADDRS:
if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
rtinfo->invflags & IP6T_RT_INV_TYP)
xtables_error(PARAMETER_PROBLEM,
"`--rt-type 0' required before `--rt-0-addrs'");
rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs);
rtinfo->flags |= IP6T_RT_FST;
break;
case O_RT0NSTRICT:
if (!(cb->xflags & F_RT0ADDRS))
xtables_error(PARAMETER_PROBLEM,
"`--rt-0-addr ...' required before `--rt-0-not-strict'");
rtinfo->flags |= IP6T_RT_FST_NSTRICT;
break;
}
}
static void
print_nums(const char *name, uint32_t min, uint32_t max,
int invert)
{
const char *inv = invert ? "!" : "";
if (min != 0 || max != 0xFFFFFFFF || invert) {
printf(" %s", name);
if (min == max) {
printf(":%s", inv);
printf("%u", min);
} else {
printf("s:%s", inv);
printf("%u",min);
printf(":");
printf("%u",max);
}
}
}
static void
print_addresses(unsigned int addrnr, struct in6_addr *addrp)
{
unsigned int i;
for(i=0; i<addrnr; i++){
printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i])));
}
}
static void rt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
printf(" rt");
if (rtinfo->flags & IP6T_RT_TYP)
printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
rtinfo->rt_type);
print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
rtinfo->invflags & IP6T_RT_INV_SGS);
if (rtinfo->flags & IP6T_RT_LEN) {
printf(" length");
printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
printf("%u", rtinfo->hdrlen);
}
if (rtinfo->flags & IP6T_RT_RES) printf(" reserved");
if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs");
print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict");
if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
printf(" Unknown invflags: 0x%X",
rtinfo->invflags & ~IP6T_RT_INV_MASK);
}
static void rt_save(const void *ip, const struct xt_entry_match *match)
{
const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
if (rtinfo->flags & IP6T_RT_TYP) {
printf("%s --rt-type %u",
(rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "",
rtinfo->rt_type);
}
if (!(rtinfo->segsleft[0] == 0
&& rtinfo->segsleft[1] == 0xFFFFFFFF)) {
printf("%s --rt-segsleft ",
(rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
if (rtinfo->segsleft[0]
!= rtinfo->segsleft[1])
printf("%u:%u",
rtinfo->segsleft[0],
rtinfo->segsleft[1]);
else
printf("%u",
rtinfo->segsleft[0]);
}
if (rtinfo->flags & IP6T_RT_LEN) {
printf("%s --rt-len %u",
(rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "",
rtinfo->hdrlen);
}
if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res");
if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs");
print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict");
}
static struct xtables_match rt_mt6_reg = {
.name = "rt",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct ip6t_rt)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
.help = rt_help,
.x6_parse = rt_parse,
.print = rt_print,
.save = rt_save,
.x6_options = rt_opts,
};
void
_init(void)
{
xtables_register_match(&rt_mt6_reg);
}
Match on IPv6 routing header
.TP
[\fB!\fP] \fB\-\-rt\-type\fP \fItype\fP
Match the type (numeric).
.TP
[\fB!\fP] \fB\-\-rt\-segsleft\fP \fInum\fP[\fB:\fP\fInum\fP]
Match the `segments left' field (range).
.TP
[\fB!\fP] \fB\-\-rt\-len\fP \fIlength\fP
Match the length of this header.
.TP
\fB\-\-rt\-0\-res\fP
Match the reserved field, too (type=0)
.TP
\fB\-\-rt\-0\-addrs\fP \fIaddr\fP[\fB,\fP\fIaddr\fP...]
Match type=0 addresses (list).
.TP
\fB\-\-rt\-0\-not\-strict\fP
List of type=0 addresses is not a strict list.
/* Shared library add-on to iptables to add CLUSTERIP target support.
* (C) 2003 by Harald Welte <laforge@gnumonks.org>
*
* Development of this code was funded by SuSE AG, http://www.suse.com/
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <stddef.h>
#if defined(__GLIBC__) && __GLIBC__ == 2
#include <net/ethernet.h>
#else
#include <linux/if_ether.h>
#endif
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
enum {
O_NEW = 0,
O_HASHMODE,
O_CLUSTERMAC,
O_TOTAL_NODES,
O_LOCAL_NODE,
O_HASH_INIT,
F_NEW = 1 << O_NEW,
F_HASHMODE = 1 << O_HASHMODE,
F_CLUSTERMAC = 1 << O_CLUSTERMAC,
F_TOTAL_NODES = 1 << O_TOTAL_NODES,
F_LOCAL_NODE = 1 << O_LOCAL_NODE,
F_FULL = F_NEW | F_HASHMODE | F_CLUSTERMAC |
F_TOTAL_NODES | F_LOCAL_NODE,
};
static void CLUSTERIP_help(void)
{
printf(
"CLUSTERIP target options:\n"
" --new Create a new ClusterIP\n"
" --hashmode <mode> Specify hashing mode\n"
" sourceip\n"
" sourceip-sourceport\n"
" sourceip-sourceport-destport\n"
" --clustermac <mac> Set clusterIP MAC address\n"
" --total-nodes <num> Set number of total nodes in cluster\n"
" --local-node <num> Set the local node number\n"
" --hash-init <num> Set init value of the Jenkins hash\n");
}
#define s struct ipt_clusterip_tgt_info
static const struct xt_option_entry CLUSTERIP_opts[] = {
{.name = "new", .id = O_NEW, .type = XTTYPE_NONE},
{.name = "hashmode", .id = O_HASHMODE, .type = XTTYPE_STRING,
.also = O_NEW},
{.name = "clustermac", .id = O_CLUSTERMAC, .type = XTTYPE_ETHERMAC,
.also = O_NEW, .flags = XTOPT_PUT, XTOPT_POINTER(s, clustermac)},
{.name = "total-nodes", .id = O_TOTAL_NODES, .type = XTTYPE_UINT16,
.flags = XTOPT_PUT, XTOPT_POINTER(s, num_total_nodes),
.also = O_NEW, .max = CLUSTERIP_MAX_NODES},
{.name = "local-node", .id = O_LOCAL_NODE, .type = XTTYPE_UINT16,
.flags = XTOPT_PUT, XTOPT_POINTER(s, local_nodes[0]),
.also = O_NEW, .max = CLUSTERIP_MAX_NODES},
{.name = "hash-init", .id = O_HASH_INIT, .type = XTTYPE_UINT32,
.flags = XTOPT_PUT, XTOPT_POINTER(s, hash_initval),
.also = O_NEW, .max = UINT_MAX},
XTOPT_TABLEEND,
};
#undef s
static void CLUSTERIP_parse(struct xt_option_call *cb)
{
struct ipt_clusterip_tgt_info *cipinfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_NEW:
cipinfo->flags |= CLUSTERIP_FLAG_NEW;
break;
case O_HASHMODE:
if (strcmp(cb->arg, "sourceip") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP;
else if (strcmp(cb->arg, "sourceip-sourceport") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT;
else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0)
cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT;
else
xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n",
cb->arg);
break;
case O_CLUSTERMAC:
if (!(cipinfo->clustermac[0] & 0x01))
xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
break;
case O_LOCAL_NODE:
cipinfo->num_local_nodes = 1;
break;
}
}
static void CLUSTERIP_check(struct xt_fcheck_call *cb)
{
if (cb->xflags == 0)
return;
if ((cb->xflags & F_FULL) == F_FULL)
return;
xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
}
static const char *hashmode2str(enum clusterip_hashmode mode)
{
const char *retstr;
switch (mode) {
case CLUSTERIP_HASHMODE_SIP:
retstr = "sourceip";
break;
case CLUSTERIP_HASHMODE_SIP_SPT:
retstr = "sourceip-sourceport";
break;
case CLUSTERIP_HASHMODE_SIP_SPT_DPT:
retstr = "sourceip-sourceport-destport";
break;
default:
retstr = "unknown-error";
break;
}
return retstr;
}
static const char *mac2str(const uint8_t mac[ETH_ALEN])
{
static char buf[ETH_ALEN*3];
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return buf;
}
static void CLUSTERIP_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct ipt_clusterip_tgt_info *cipinfo =
(const struct ipt_clusterip_tgt_info *)target->data;
if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) {
printf(" CLUSTERIP");
return;
}
printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u",
hashmode2str(cipinfo->hash_mode),
mac2str(cipinfo->clustermac),
cipinfo->num_total_nodes,
cipinfo->local_nodes[0],
cipinfo->hash_initval);
}
static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_clusterip_tgt_info *cipinfo =
(const struct ipt_clusterip_tgt_info *)target->data;
/* if this is not a new entry, we don't need to save target
* parameters */
if (!cipinfo->flags & CLUSTERIP_FLAG_NEW)
return;
printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u",
hashmode2str(cipinfo->hash_mode),
mac2str(cipinfo->clustermac),
cipinfo->num_total_nodes,
cipinfo->local_nodes[0],
cipinfo->hash_initval);
}
static struct xtables_target clusterip_tg_reg = {
.name = "CLUSTERIP",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)),
.userspacesize = offsetof(struct ipt_clusterip_tgt_info, config),
.help = CLUSTERIP_help,
.x6_parse = CLUSTERIP_parse,
.x6_fcheck = CLUSTERIP_check,
.print = CLUSTERIP_print,
.save = CLUSTERIP_save,
.x6_options = CLUSTERIP_opts,
};
void _init(void)
{
xtables_register_target(&clusterip_tg_reg);
}
This module allows you to configure a simple cluster of nodes that share
a certain IP and MAC address without an explicit load balancer in front of
them. Connections are statically distributed between the nodes in this
cluster.
.TP
\fB\-\-new\fP
Create a new ClusterIP. You always have to set this on the first rule
for a given ClusterIP.
.TP
\fB\-\-hashmode\fP \fImode\fP
Specify the hashing mode. Has to be one of
\fBsourceip\fP, \fBsourceip\-sourceport\fP, \fBsourceip\-sourceport\-destport\fP.
.TP
\fB\-\-clustermac\fP \fImac\fP
Specify the ClusterIP MAC address. Has to be a link\-layer multicast address
.TP
\fB\-\-total\-nodes\fP \fInum\fP
Number of total nodes within this cluster.
.TP
\fB\-\-local\-node\fP \fInum\fP
Local node number within this cluster.
.TP
\fB\-\-hash\-init\fP \fIrnd\fP
Specify the random seed used for hash initialization.
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <iptables.h> /* get_kernel_version */
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/netfilter/nf_nat.h>
enum {
O_TO_DEST = 0,
O_RANDOM,
O_PERSISTENT,
O_X_TO_DEST, /* hidden flag */
F_TO_DEST = 1 << O_TO_DEST,
F_RANDOM = 1 << O_RANDOM,
F_X_TO_DEST = 1 << O_X_TO_DEST,
};
/* Dest NAT data consists of a multi-range, indicating where to map
to. */
struct ipt_natinfo
{
struct xt_entry_target t;
struct nf_nat_multi_range mr;
};
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,
};
static struct ipt_natinfo *
append_range(struct ipt_natinfo *info, const struct nf_nat_range *range)
{
unsigned int size;
/* One rangesize already in struct ipt_natinfo */
size = XT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
info = realloc(info, size);
if (!info)
xtables_error(OTHER_PROBLEM, "Out of memory\n");
info->t.u.target_size = size;
info->mr.range[info->mr.rangesize] = *range;
info->mr.rangesize++;
return info;
}
/* Ranges expected in network order. */
static struct xt_entry_target *
parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info)
{
struct nf_nat_range range;
char *arg, *colon, *dash, *error;
const struct in_addr *ip;
arg = strdup(orig_arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
memset(&range, 0, sizeof(range));
colon = strchr(arg, ':');
if (colon) {
int port;
if (!portok)
xtables_error(PARAMETER_PROBLEM,
"Need TCP, UDP, SCTP or DCCP with port specification");
range.flags |= IP_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.tcp.port
= range.max.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.tcp.port = htons(port);
range.max.tcp.port = htons(maxport);
}
/* Starts with a colon? No IP info...*/
if (colon == arg) {
free(arg);
return &(append_range(info, &range)->t);
}
*colon = '\0';
}
range.flags |= IP_NAT_RANGE_MAP_IPS;
dash = strchr(arg, '-');
if (colon && dash && dash > colon)
dash = NULL;
if (dash)
*dash = '\0';
ip = xtables_numeric_to_ipaddr(arg);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
arg);
range.min_ip = ip->s_addr;
if (dash) {
ip = xtables_numeric_to_ipaddr(dash+1);
if (!ip)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
dash+1);
range.max_ip = ip->s_addr;
} else
range.max_ip = range.min_ip;
free(arg);
return &(append_range(info, &range)->t);
}
static void DNAT_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
struct ipt_natinfo *info = (void *)(*cb->target);
int portok;
if (entry->ip.proto == IPPROTO_TCP
|| entry->ip.proto == IPPROTO_UDP
|| entry->ip.proto == IPPROTO_SCTP
|| entry->ip.proto == IPPROTO_DCCP
|| entry->ip.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");
}
*cb->target = parse_to(cb->arg, portok, info);
/* WTF do we need this for?? */
if (cb->xflags & F_RANDOM)
info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
cb->xflags |= F_X_TO_DEST;
break;
case O_RANDOM:
if (cb->xflags & F_TO_DEST)
info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
break;
case O_PERSISTENT:
info->mr.range[0].flags |= IP_NAT_RANGE_PERSISTENT;
break;
}
}
static void print_range(const struct nf_nat_range *r)
{
if (r->flags & IP_NAT_RANGE_MAP_IPS) {
struct in_addr a;
a.s_addr = r->min_ip;
printf("%s", xtables_ipaddr_to_numeric(&a));
if (r->max_ip != r->min_ip) {
a.s_addr = r->max_ip;
printf("-%s", xtables_ipaddr_to_numeric(&a));
}
}
if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
printf(":");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
}
}
static void DNAT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_natinfo *info = (const void *)target;
unsigned int i = 0;
printf(" to:");
for (i = 0; i < info->mr.rangesize; i++) {
print_range(&info->mr.range[i]);
if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
printf(" random");
if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT)
printf(" persistent");
}
}
static void DNAT_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_natinfo *info = (const void *)target;
unsigned int i = 0;
for (i = 0; i < info->mr.rangesize; i++) {
printf(" --to-destination ");
print_range(&info->mr.range[i]);
if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT)
printf(" --persistent");
}
}
static struct xtables_target dnat_tg_reg = {
.name = "DNAT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.help = DNAT_help,
.x6_parse = DNAT_parse,
.print = DNAT_print,
.save = DNAT_save,
.x6_options = DNAT_opts,
};
void _init(void)
{
xtables_register_target(&dnat_tg_reg);
}
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 specifies that the destination 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 one
type of option:
.TP
\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]]
which can specify a single new destination IP address, an inclusive
range of IP addresses, and optionally, a port range (which is only
valid if the rule also specifies
\fB\-p tcp\fP
or
\fB\-p udp\fP).
If no port range is specified, then the destination port will never be
modified. If no IP address is specified then only the destination port
will be modified.
In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For
those kernels, if you specify more than one destination address, either via an
address range or multiple \-\-to\-destination options, a simple round-robin (one
after another in cycle) load balancing 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.22).
.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.
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
#define LOG_DEFAULT_LEVEL LOG_WARNING
#ifndef IPT_LOG_UID /* Old kernel */
#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
#undef IPT_LOG_MASK
#define IPT_LOG_MASK 0x0f
#endif
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\n"
" --log-tcp-sequence Log TCP sequence numbers.\n\n"
" --log-tcp-options Log TCP options.\n\n"
" --log-ip-options Log IP options.\n\n"
" --log-uid Log UID owning the local socket.\n\n"
" --log-macdecode Decode MAC addresses and protocol.\n\n");
}
#define s struct ipt_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 ipt_log_info *loginfo = (struct ipt_log_info *)t->data;
loginfo->level = LOG_DEFAULT_LEVEL;
}
struct ipt_log_names {
const char *name;
unsigned int level;
};
static const struct ipt_log_names ipt_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 ipt_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 = IPT_LOG_TCPSEQ;
break;
case O_LOG_TCPOPTS:
info->logflags = IPT_LOG_TCPOPT;
break;
case O_LOG_IPOPTS:
info->logflags = IPT_LOG_IPOPT;
break;
case O_LOG_UID:
info->logflags = IPT_LOG_UID;
break;
case O_LOG_MAC:
info->logflags = IPT_LOG_MACDECODE;
break;
}
}
static void LOG_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct ipt_log_info *loginfo
= (const struct ipt_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(ipt_log_names); ++i)
if (loginfo->level == ipt_log_names[i].level) {
printf(" level %s", ipt_log_names[i].name);
break;
}
if (i == ARRAY_SIZE(ipt_log_names))
printf(" UNKNOWN level %u", loginfo->level);
if (loginfo->logflags & IPT_LOG_TCPSEQ)
printf(" tcp-sequence");
if (loginfo->logflags & IPT_LOG_TCPOPT)
printf(" tcp-options");
if (loginfo->logflags & IPT_LOG_IPOPT)
printf(" ip-options");
if (loginfo->logflags & IPT_LOG_UID)
printf(" uid");
if (loginfo->logflags & IPT_LOG_MACDECODE)
printf(" macdecode");
if (loginfo->logflags & ~(IPT_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 ipt_log_info *loginfo
= (const struct ipt_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 & IPT_LOG_TCPSEQ)
printf(" --log-tcp-sequence");
if (loginfo->logflags & IPT_LOG_TCPOPT)
printf(" --log-tcp-options");
if (loginfo->logflags & IPT_LOG_IPOPT)
printf(" --log-ip-options");
if (loginfo->logflags & IPT_LOG_UID)
printf(" --log-uid");
if (loginfo->logflags & IPT_LOG_MACDECODE)
printf(" --log-macdecode");
}
static struct xtables_target log_tg_reg = {
.name = "LOG",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_log_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_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_tg_reg);
}
Turn on kernel logging of matching packets. When this option is set
for a rule, the Linux kernel will print some information on all
matching packets (like most IP header fields) via the kernel log
(where it can be read with
.I dmesg
or
.IR syslogd (8)).
This is a "non-terminating target", i.e. rule traversal continues at
the next rule. So if you want to LOG the packets you refuse, use two
separate rules with the same matching criteria, first using target LOG
then DROP (or REJECT).
.TP
\fB\-\-log\-level\fP \fIlevel\fP
Level of logging (numeric or see \fIsyslog.conf\fP(5)).
.TP
\fB\-\-log\-prefix\fP \fIprefix\fP
Prefix log messages with the specified prefix; up to 29 letters long,
and useful for distinguishing messages in the logs.
.TP
\fB\-\-log\-tcp\-sequence\fP
Log TCP sequence numbers. This is a security risk if the log is
readable by users.
.TP
\fB\-\-log\-tcp\-options\fP
Log options from the TCP packet header.
.TP
\fB\-\-log\-ip\-options\fP
Log options from the IP packet header.
.TP
\fB\-\-log\-uid\fP
Log the userid of the process which generated the packet.
#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_ipv4/ip_tables.h>
#include <net/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,
};
static void MASQUERADE_init(struct xt_entry_target *t)
{
struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
}
/* Parses ports */
static void
parse_ports(const char *arg, struct nf_nat_multi_range *mr)
{
char *end;
unsigned int port, maxport;
mr->range[0].flags |= IP_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':
mr->range[0].min.tcp.port
= mr->range[0].max.tcp.port
= htons(port);
return;
case '-':
if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX))
break;
if (maxport < port)
break;
mr->range[0].min.tcp.port = htons(port);
mr->range[0].max.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 ipt_entry *entry = cb->xt_entry;
int portok;
struct nf_nat_multi_range *mr = cb->data;
if (entry->ip.proto == IPPROTO_TCP
|| entry->ip.proto == IPPROTO_UDP
|| entry->ip.proto == IPPROTO_SCTP
|| entry->ip.proto == IPPROTO_DCCP
|| entry->ip.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, mr);
break;
case O_RANDOM:
mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void
MASQUERADE_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_multi_range *mr = (const void *)target->data;
const struct nf_nat_range *r = &mr->range[0];
if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
printf(" masq ports: ");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
}
if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
printf(" random");
}
static void
MASQUERADE_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_multi_range *mr = (const void *)target->data;
const struct nf_nat_range *r = &mr->range[0];
if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
printf(" --to-ports %hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
}
if (r->flags & IP_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
}
static struct xtables_target masquerade_tg_reg = {
.name = "MASQUERADE",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.help = MASQUERADE_help,
.init = MASQUERADE_init,
.x6_parse = MASQUERADE_parse,
.print = MASQUERADE_print,
.save = MASQUERADE_save,
.x6_options = MASQUERADE_opts,
};
void _init(void)
{
xtables_register_target(&masquerade_tg_reg);
}
This target is only valid in the
.B nat
table, in the
.B POSTROUTING
chain. It should only be used with dynamically assigned IP (dialup)
connections: if you have a static IP address, you should use the SNAT
target. Masquerading is equivalent to specifying a mapping to the IP
address of the interface the packet is going out, but also has the
effect that connections are
.I forgotten
when the interface goes down. This is the correct behavior when the
next dialup is unlikely to have the same interface address (and hence
any established connections are lost anyway).
.TP
\fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP]
This specifies a range of source ports to use, overriding the default
.B SNAT
source port-selection heuristics (see above). This is only valid
if the rule also specifies
\fB\-p tcp\fP
or
\fB\-p udp\fP.
.TP
\fB\-\-random\fP
Randomize source port mapping
If option
\fB\-\-random\fP
is used then port mapping will be randomized (kernel >= 2.6.21).
.RS
.PP
/* Shared library add-on to iptables to add MIRROR target support. */
#include <xtables.h>
static struct xtables_target mirror_tg_reg = {
.name = "MIRROR",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0),
};
void _init(void)
{
xtables_register_target(&mirror_tg_reg);
}
This is an experimental demonstration target which inverts the source
and destination fields in the IP header and retransmits the packet.
It is only valid in the
.BR INPUT ,
.B FORWARD
and
.B PREROUTING
chains, and user-defined chains which are only called from those
chains. Note that the outgoing packets are
.B NOT
seen by any packet filtering chains, connection tracking or NAT, to
avoid loops and other problems.
/* Shared library add-on to iptables to add static NAT support.
Author: Svenning Soerensen <svenning@post5.tele.dk>
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <net/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 int
netmask2bits(uint32_t netmask)
{
uint32_t bm;
int bits;
netmask = ntohl(netmask);
for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
bits++;
if (netmask)
return -1; /* holes in netmask */
return bits;
}
static void NETMAP_init(struct xt_entry_target *t)
{
struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
}
static void NETMAP_parse(struct xt_option_call *cb)
{
struct nf_nat_multi_range *mr = cb->data;
struct nf_nat_range *range = &mr->range[0];
xtables_option_parse(cb);
range->flags |= IP_NAT_RANGE_MAP_IPS;
range->min_ip = cb->val.haddr.ip & cb->val.hmask.ip;
range->max_ip = range->min_ip | ~cb->val.hmask.ip;
}
static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_multi_range *mr = (const void *)target->data;
const struct nf_nat_range *r = &mr->range[0];
struct in_addr a;
int bits;
a.s_addr = r->min_ip;
printf("%s", xtables_ipaddr_to_numeric(&a));
a.s_addr = ~(r->min_ip ^ r->max_ip);
bits = netmask2bits(a.s_addr);
if (bits < 0)
printf("/%s", xtables_ipaddr_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_IPV4,
.size = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.help = NETMAP_help,
.init = NETMAP_init,
.x6_parse = NETMAP_parse,
.print = NETMAP_print,
.save = NETMAP_save,
.x6_options = NETMAP_opts,
};
void _init(void)
{
xtables_register_target(&netmap_tg_reg);
}
This target allows you to statically map a whole network of addresses onto
another network of addresses. It can only be used from rules in the
.B nat
table.
.TP
\fB\-\-to\fP \fIaddress\fP[\fB/\fP\fImask\fP]
Network address to map to. The resulting address will be constructed in the
following way: All 'one' bits in the mask are filled in from the new `address'.
All bits that are zero in the mask are filled in from the original address.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <limits.h> /* INT_MAX in ip_tables.h */
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/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,
};
static void REDIRECT_init(struct xt_entry_target *t)
{
struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
}
/* Parses ports */
static void
parse_ports(const char *arg, struct nf_nat_multi_range *mr)
{
char *end = "";
unsigned int port, maxport;
mr->range[0].flags |= IP_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':
mr->range[0].min.tcp.port
= mr->range[0].max.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;
mr->range[0].min.tcp.port = htons(port);
mr->range[0].max.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 ipt_entry *entry = cb->xt_entry;
struct nf_nat_multi_range *mr = (void *)(*cb->target)->data;
int portok;
if (entry->ip.proto == IPPROTO_TCP
|| entry->ip.proto == IPPROTO_UDP
|| entry->ip.proto == IPPROTO_SCTP
|| entry->ip.proto == IPPROTO_DCCP
|| entry->ip.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, mr);
if (cb->xflags & F_RANDOM)
mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
break;
case O_RANDOM:
if (cb->xflags & F_TO_PORTS)
mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM;
break;
}
}
static void REDIRECT_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct nf_nat_multi_range *mr = (const void *)target->data;
const struct nf_nat_range *r = &mr->range[0];
if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
printf(" redir ports ");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
printf(" random");
}
}
static void REDIRECT_save(const void *ip, const struct xt_entry_target *target)
{
const struct nf_nat_multi_range *mr = (const void *)target->data;
const struct nf_nat_range *r = &mr->range[0];
if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
printf(" --to-ports ");
printf("%hu", ntohs(r->min.tcp.port));
if (r->max.tcp.port != r->min.tcp.port)
printf("-%hu", ntohs(r->max.tcp.port));
if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM)
printf(" --random");
}
}
static struct xtables_target redirect_tg_reg = {
.name = "REDIRECT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)),
.help = REDIRECT_help,
.init = REDIRECT_init,
.x6_parse = REDIRECT_parse,
.print = REDIRECT_print,
.save = REDIRECT_save,
.x6_options = REDIRECT_opts,
};
void _init(void)
{
xtables_register_target(&redirect_tg_reg);
}
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 127.0.0.1 address).
.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
\fB\-p tcp\fP
or
\fB\-p udp\fP.
.TP
\fB\-\-random\fP
If option
\fB\-\-random\fP
is used then port mapping will be randomized (kernel >= 2.6.22).
.RS
.PP
/* Shared library add-on to iptables to add customized REJECT support.
*
* (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*/
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
#include <linux/version.h>
/* If we are compiling against a kernel that does not support
* IPT_ICMP_ADMIN_PROHIBITED, we are emulating it.
* The result will be a plain DROP of the packet instead of
* reject. -- Maciej Soltysiak <solt@dns.toxicfilms.tv>
*/
#ifndef IPT_ICMP_ADMIN_PROHIBITED
#define IPT_ICMP_ADMIN_PROHIBITED IPT_TCP_RESET + 1
#endif
struct reject_names {
const char *name;
const char *alias;
enum ipt_reject_with with;
const char *desc;
};
enum {
O_REJECT_WITH = 0,
};
static const struct reject_names reject_table[] = {
{"icmp-net-unreachable", "net-unreach",
IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
{"icmp-host-unreachable", "host-unreach",
IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
{"icmp-proto-unreachable", "proto-unreach",
IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
{"icmp-port-unreachable", "port-unreach",
IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
#if 0
{"echo-reply", "echoreply",
IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
#endif
{"icmp-net-prohibited", "net-prohib",
IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
{"icmp-host-prohibited", "host-prohib",
IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
{"tcp-reset", "tcp-rst",
IPT_TCP_RESET, "TCP RST packet"},
{"icmp-admin-prohibited", "admin-prohib",
IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
};
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();
printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n");
}
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 ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
/* default */
reject->with = IPT_ICMP_PORT_UNREACHABLE;
}
static void REJECT_parse(struct xt_option_call *cb)
{
struct ipt_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;
}
/* This due to be dropped late in 2.4 pre-release cycle --RR */
if (strncasecmp("echo-reply", cb->arg, strlen(cb->arg)) == 0 ||
strncasecmp("echoreply", cb->arg, strlen(cb->arg)) == 0)
fprintf(stderr, "--reject-with echo-reply no longer"
" supported\n");
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 ipt_reject_info *reject
= (const struct ipt_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 ipt_reject_info *reject
= (const struct ipt_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_tg_reg = {
.name = "REJECT",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ipt_reject_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_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_tg_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
\fBicmp\-net\-unreachable\fP,
\fBicmp\-host\-unreachable\fP,
\fBicmp\-port\-unreachable\fP,
\fBicmp\-proto\-unreachable\fP,
\fBicmp\-net\-prohibited\fP,
\fBicmp\-host\-prohibited\fP or
\fBicmp\-admin\-prohibited\fP (*)
which return the appropriate ICMP error message (\fBport\-unreachable\fP is
the default). 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).
.PP
(*) Using icmp\-admin\-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT
This diff is collapsed.
Similar to SNAT/DNAT depending on chain: it takes a range of addresses
(`\-\-to 1.2.3.4\-1.2.3.7') and gives a client the same
source-/destination-address for each connection.
.PP
N.B.: The DNAT target's \fB\-\-persistent\fP option replaced the SAME target.
.TP
\fB\-\-to\fP \fIipaddr\fP[\fB\-\fP\fIipaddr\fP]
Addresses to map source to. May be specified more than once for
multiple ranges.
.TP
\fB\-\-nodst\fP
Don't use the destination-ip in the calculations when selecting the
new source-ip
.TP
\fB\-\-random\fP
Port mapping will be forcibly randomized to avoid attacks based on
port prediction (kernel >= 2.6.21).
This diff is collapsed.
This target is only valid in the
.B nat
table, in the
.B POSTROUTING
chain. 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 one type
of option:
.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, and optionally, a port range (which is only valid if
the rule also specifies
\fB\-p tcp\fP
or
\fB\-p udp\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.
This diff is collapsed.
This target provides userspace logging of matching packets. When this
target is set for a rule, the Linux kernel will multicast this packet
through a
.IR netlink
socket. One or more userspace processes may then subscribe to various
multicast groups and receive the packets.
Like LOG, this is a "non-terminating target", i.e. rule traversal
continues at the next rule.
.TP
\fB\-\-ulog\-nlgroup\fP \fInlgroup\fP
This specifies the netlink group (1-32) to which the packet is sent.
Default value is 1.
.TP
\fB\-\-ulog\-prefix\fP \fIprefix\fP
Prefix log messages with the specified prefix; up to 32 characters
long, and useful for distinguishing messages in the logs.
.TP
\fB\-\-ulog\-cprange\fP \fIsize\fP
Number of bytes to be copied to userspace. A value of 0 always copies
the entire packet, regardless of its size. Default is 0.
.TP
\fB\-\-ulog\-qthreshold\fP \fIsize\fP
Number of packet to queue inside kernel. Setting this value to, e.g. 10
accumulates ten packets inside the kernel and transmits them as one
netlink multipart message to userspace. Default is 1 (for backwards
compatibility).
.br
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This module matches the SPIs in Authentication header of IPsec packets.
.TP
[\fB!\fP] \fB\-\-ahspi\fP \fIspi\fP[\fB:\fP\fIspi\fP]
This diff is collapsed.
This allows you to match the ECN bits of the IPv4 and TCP header. ECN is the Explicit Congestion Notification mechanism as specified in RFC3168
.TP
[\fB!\fP] \fB\-\-ecn\-tcp\-cwr\fP
This matches if the TCP ECN CWR (Congestion Window Received) bit is set.
.TP
[\fB!\fP] \fB\-\-ecn\-tcp\-ece\fP
This matches if the TCP ECN ECE (ECN Echo) bit is set.
.TP
[\fB!\fP] \fB\-\-ecn\-ip\-ect\fP \fInum\fP
This matches a particular IPv4 ECT (ECN-Capable Transport). You have to specify
a number between `0' and `3'.
This diff is collapsed.
This extension can be used if `\-\-protocol icmp' is specified. It
provides the following option:
.TP
[\fB!\fP] \fB\-\-icmp\-type\fP {\fItype\fP[\fB/\fP\fIcode\fP]|\fItypename\fP}
This allows specification of the ICMP type, which can be a numeric
ICMP type, type/code pair, or one of the ICMP type names shown by the command
.nf
iptables \-p icmp \-h
.fi
This diff is collapsed.
This matches the routing realm. Routing realms are used in complex routing
setups involving dynamic routing protocols like BGP.
.TP
[\fB!\fP] \fB\-\-realm\fP \fIvalue\fP[\fB/\fP\fImask\fP]
Matches a given realm number (and optionally mask). If not a number, value
can be a named realm from /etc/iproute2/rt_realms (mask can not be used in
that case).
This diff is collapsed.
This module matches the time to live field in the IP header.
.TP
\fB\-\-ttl\-eq\fP \fIttl\fP
Matches the given TTL value.
.TP
\fB\-\-ttl\-gt\fP \fIttl\fP
Matches if TTL is greater than the given TTL value.
.TP
\fB\-\-ttl\-lt\fP \fIttl\fP
Matches if TTL is less than the given TTL value.
This diff is collapsed.
This module takes no options, but attempts to match packets which seem
malformed or unusual. This is regarded as experimental.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This target allows to selectively work around broken/old applications.
It can only be used in the mangle table.
.TP
\fB\-\-checksum\-fill\fP
Compute and fill in the checksum in a packet that lacks a checksum.
This is particularly useful, if you need to work around old applications
such as dhcp clients, that do not work well with checksum offloads,
but don't want to disable checksum offload in your device.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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