diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2020-01-23 18:45:42 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2020-01-23 18:45:42 +0000 |
commit | 1c8a667d69c01c38bbd20877da9ae003f358e7df (patch) | |
tree | 362b9c3f4002a826623c6e1c5aed22117f71a838 | |
parent | c70f7ac0238cbe801ba4ce7148a1bb2d8d9ade36 (diff) | |
parent | 1197ed225c226c6d735af09d2cbd119e41610d69 (diff) | |
download | iptables-1c8a667d69c01c38bbd20877da9ae003f358e7df.tar.gz |
Merge changes from topic "b143044679"
* changes:
iptables 1.6.2 - make it build
Merge tag 'v1.6.2' of git://git.netfilter.org/iptables
139 files changed, 2439 insertions, 221 deletions
@@ -22,3 +22,7 @@ Makefile.in /configure /libtool /stamp-h1 +/iptables/iptables-apply.8 + +/iptables/xtables-multi +/iptables/xtables-compat-multi diff --git a/README.version b/README.version index 74c158a5..f8bff18b 100644 --- a/README.version +++ b/README.version @@ -1,3 +1,3 @@ URL: git://git.netfilter.org/iptables -Version: 1.6.1 +Version: 1.6.2 BugComponent: 31808 @@ -63,7 +63,7 @@ #define PACKAGE_NAME "iptables" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "iptables 1.6.1" +#define PACKAGE_STRING "iptables 1.6.2" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "iptables" @@ -72,7 +72,7 @@ #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "1.6.1" +#define PACKAGE_VERSION "1.6.2" /* The size of `struct ip6_hdr', as computed by sizeof. */ #define SIZEOF_STRUCT_IP6_HDR 40 @@ -81,7 +81,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "1.6.1" +#define VERSION "1.6.2" /* Location of the iptables lock file */ #define XT_LOCK_NAME "/system/etc/xtables.lock" diff --git a/configure.ac b/configure.ac index 221812a8..b814ef08 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT([iptables], [1.6.1]) +AC_INIT([iptables], [1.6.2]) # See libtool.info "Libtool's versioning system" libxtables_vcurrent=12 @@ -42,8 +42,9 @@ AC_ARG_ENABLE([ipv6], 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']) + [enable_largefile="yes"]) +AS_IF([test "$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]), @@ -248,7 +249,8 @@ AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile libiptc/Makefile libiptc/libiptc.pc libiptc/libip4tc.pc libiptc/libip6tc.pc libxtables/Makefile utils/Makefile - include/xtables-version.h include/iptables/internal.h]) + include/xtables-version.h include/iptables/internal.h + utils/nfnl_osf.8]) AC_OUTPUT diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index b7a8a836..bee666e8 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -101,7 +101,7 @@ init%.o: init%.c # Shared libraries # lib%.so: lib%.oo - ${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $< -L../libxtables/.libs -lxtables ${$*_LIBADD}; + ${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -shared -o $@ $< -L../libxtables/.libs -lxtables ${$*_LIBADD}; lib%.oo: ${srcdir}/lib%.c ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<; diff --git a/extensions/generic.txlate b/extensions/generic.txlate new file mode 100644 index 00000000..1140bb89 --- /dev/null +++ b/extensions/generic.txlate @@ -0,0 +1,5 @@ +iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT +nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept + +iptables-translate -F -t nat +nft flush table ip nat diff --git a/extensions/libebt_limit.c b/extensions/libebt_limit.c index 6b9bb16f..988f678a 100644 --- a/extensions/libebt_limit.c +++ b/extensions/libebt_limit.c @@ -29,7 +29,7 @@ #define ARG_LIMIT '1' #define ARG_LIMIT_BURST '2' -static struct option brlimit_opts[] = +static const struct option brlimit_opts[] = { { .name = "limit", .has_arg = true, .val = ARG_LIMIT }, { .name = "limit-burst",.has_arg = true, .val = ARG_LIMIT_BURST }, diff --git a/extensions/libebt_log.c b/extensions/libebt_log.c index 0799185d..f170af03 100644 --- a/extensions/libebt_log.c +++ b/extensions/libebt_log.c @@ -27,12 +27,12 @@ #define LOG_LOG '5' #define LOG_IP6 '6' -typedef struct _code { +struct code { char *c_name; int c_val; -} CODE; +}; -static CODE eight_priority[] = { +static struct code eight_priority[] = { { "emerg", LOG_EMERG }, { "alert", LOG_ALERT }, { "crit", LOG_CRIT }, diff --git a/extensions/libebt_mark.c b/extensions/libebt_mark.c index a1a208c3..7b80b22e 100644 --- a/extensions/libebt_mark.c +++ b/extensions/libebt_mark.c @@ -25,7 +25,7 @@ static int mark_supplied; #define MARK_ORMARK '3' #define MARK_ANDMARK '4' #define MARK_XORMARK '5' -static struct option brmark_opts[] = { +static const struct option brmark_opts[] = { { .name = "mark-target",.has_arg = true, .val = MARK_TARGET }, /* an oldtime messup, we should have always used the scheme * <extension-name>-<option> */ diff --git a/extensions/libebt_mark_m.c b/extensions/libebt_mark_m.c index ab9d2344..eb08dbab 100644 --- a/extensions/libebt_mark_m.c +++ b/extensions/libebt_mark_m.c @@ -18,7 +18,7 @@ #define MARK '1' -static struct option brmark_m_opts[] = { +static const struct option brmark_m_opts[] = { { .name = "mark", .has_arg = true, .val = MARK }, XT_GETOPT_TABLEEND, }; diff --git a/extensions/libebt_nflog.c b/extensions/libebt_nflog.c index fef71960..5f1d13b1 100644 --- a/extensions/libebt_nflog.c +++ b/extensions/libebt_nflog.c @@ -30,7 +30,7 @@ enum { NFLOG_NFLOG = 0x16, }; -static struct option brnflog_opts[] = { +static const struct option brnflog_opts[] = { { .name = "nflog-group", .has_arg = true, .val = NFLOG_GROUP}, { .name = "nflog-prefix", .has_arg = true, .val = NFLOG_PREFIX}, { .name = "nflog-range", .has_arg = true, .val = NFLOG_RANGE}, diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c index 08d920db..8e478b21 100644 --- a/extensions/libip6t_DNAT.c +++ b/extensions/libip6t_DNAT.c @@ -163,13 +163,11 @@ static void DNAT_parse(struct xt_option_call *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"); + xtables_error(PARAMETER_PROBLEM, + "DNAT: Multiple --to-destination not supported"); } parse_to(cb->arg, portok, range); + cb->xflags |= F_X_TO_DEST; break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; @@ -281,7 +279,7 @@ static int DNAT_xlate(struct xt_xlate *xl, return 1; } -static struct xtables_target snat_tg_reg = { +static struct xtables_target dnat_tg_reg = { .name = "DNAT", .version = XTABLES_VERSION, .family = NFPROTO_IPV6, @@ -299,5 +297,5 @@ static struct xtables_target snat_tg_reg = { void _init(void) { - xtables_register_target(&snat_tg_reg); + xtables_register_target(&dnat_tg_reg); } diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t index 3141c299..6d8f1dab 100644 --- a/extensions/libip6t_DNAT.t +++ b/extensions/libip6t_DNAT.t @@ -2,7 +2,10 @@ *nat -j DNAT --to-destination dead::beef;=;OK -j DNAT --to-destination dead::beef-dead::fee7;=;OK +-j DNAT --to-destination [dead::beef]:1025-65535;;FAIL +-j DNAT --to-destination [dead::beef] --to-destination [dead::fee7];;FAIL -p tcp -j DNAT --to-destination [dead::beef]:1025-65535;=;OK -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65535;=;OK -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65536;;FAIL +-p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1025-65535 --to-destination [dead::beef-dead::fee8]:1025-65535;;FAIL -j DNAT;;FAIL diff --git a/extensions/libip6t_DNAT.txlate b/extensions/libip6t_DNAT.txlate new file mode 100644 index 00000000..fe26075d --- /dev/null +++ b/extensions/libip6t_DNAT.txlate @@ -0,0 +1,11 @@ +ip6tables-translate -t nat -A prerouting -i eth1 -p tcp --dport 8080 -j DNAT --to-destination [fec0::1234]:80 +nft add rule ip6 nat prerouting iifname eth1 tcp dport 8080 counter dnat to [fec0::1234]:80 + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:1-20 +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:1-20 + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --persistent +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 persistent + +ip6tables-translate -t nat -A prerouting -p tcp -j DNAT --to-destination [fec0::1234]:80 --random --persistent +nft add rule ip6 nat prerouting meta l4proto tcp counter dnat to [fec0::1234]:80 random,persistent diff --git a/extensions/libip6t_LOG.txlate b/extensions/libip6t_LOG.txlate new file mode 100644 index 00000000..2820a82c --- /dev/null +++ b/extensions/libip6t_LOG.txlate @@ -0,0 +1,8 @@ +iptables-translate -I INPUT -j LOG +nft insert rule ip filter INPUT counter log + +ip6tables-translate -A FORWARD -p tcp -j LOG --log-level debug +nft add rule ip6 filter FORWARD meta l4proto tcp counter log level debug + +ip6tables-translate -A FORWARD -p tcp -j LOG --log-prefix "Checking log" +nft add rule ip6 filter FORWARD meta l4proto tcp counter log prefix \"Checking log\" diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c index 3b59e43e..f92760fa 100644 --- a/extensions/libip6t_MASQUERADE.c +++ b/extensions/libip6t_MASQUERADE.c @@ -18,6 +18,7 @@ enum { O_TO_PORTS = 0, O_RANDOM, + O_RANDOM_FULLY, }; static void MASQUERADE_help(void) @@ -27,12 +28,15 @@ static void MASQUERADE_help(void) " --to-ports <port>[-<port>]\n" " Port (range) to map to.\n" " --random\n" -" Randomize source port.\n"); +" Randomize source port.\n" +" --random-fully\n" +" Fully 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}, + {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, XTOPT_TABLEEND, }; @@ -96,6 +100,9 @@ static void MASQUERADE_parse(struct xt_option_call *cb) case O_RANDOM: r->flags |= NF_NAT_RANGE_PROTO_RANDOM; break; + case O_RANDOM_FULLY: + r->flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + break; } } @@ -114,6 +121,9 @@ MASQUERADE_print(const void *ip, const struct xt_entry_target *target, if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) printf(" random"); + + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" random-fully"); } static void @@ -129,6 +139,9 @@ MASQUERADE_save(const void *ip, const struct xt_entry_target *target) if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) printf(" --random"); + + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" --random-fully"); } static int MASQUERADE_xlate(struct xt_xlate *xl, @@ -148,6 +161,10 @@ static int MASQUERADE_xlate(struct xt_xlate *xl, if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) xt_xlate_add(xl, "random "); + xt_xlate_add(xl, " "); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + xt_xlate_add(xl, "random-fully "); + return 1; } diff --git a/extensions/libip6t_MASQUERADE.t b/extensions/libip6t_MASQUERADE.t index 46502040..e25d2a04 100644 --- a/extensions/libip6t_MASQUERADE.t +++ b/extensions/libip6t_MASQUERADE.t @@ -2,6 +2,7 @@ *nat -j MASQUERADE;=;OK -j MASQUERADE --random;=;OK +-j MASQUERADE --random-fully;=;OK -p tcp -j MASQUERADE --to-ports 1024;=;OK -p udp -j MASQUERADE --to-ports 1024-65535;=;OK -p udp -j MASQUERADE --to-ports 1024-65536;;FAIL diff --git a/extensions/libip6t_MASQUERADE.txlate b/extensions/libip6t_MASQUERADE.txlate new file mode 100644 index 00000000..6c289c2b --- /dev/null +++ b/extensions/libip6t_MASQUERADE.txlate @@ -0,0 +1,8 @@ +ip6tables-translate -t nat -A POSTROUTING -j MASQUERADE +nft add rule ip6 nat POSTROUTING counter masquerade + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10 +nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10 + +ip6tables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random +nft add rule ip6 nat POSTROUTING meta l4proto tcp counter masquerade to :10-20 random diff --git a/extensions/libip6t_REDIRECT.txlate b/extensions/libip6t_REDIRECT.txlate new file mode 100644 index 00000000..209f67a4 --- /dev/null +++ b/extensions/libip6t_REDIRECT.txlate @@ -0,0 +1,5 @@ +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 +nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random +nft add rule ip6 nat prerouting tcp dport 80 counter redirect to :8080 random diff --git a/extensions/libip6t_REJECT.txlate b/extensions/libip6t_REJECT.txlate new file mode 100644 index 00000000..cfa35ebf --- /dev/null +++ b/extensions/libip6t_REJECT.txlate @@ -0,0 +1,8 @@ +ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT +nft add rule ip6 filter FORWARD tcp dport 22 counter reject + +ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp6-reject-route +nft add rule ip6 filter FORWARD tcp dport 22 counter reject with icmpv6 type reject-route + +ip6tables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset +nft add rule ip6 filter FORWARD tcp dport 22 counter reject with tcp reset diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c index 671ac61a..7d74b3d7 100644 --- a/extensions/libip6t_SNAT.c +++ b/extensions/libip6t_SNAT.c @@ -166,13 +166,11 @@ static void SNAT_parse(struct xt_option_call *cb) switch (cb->entry->id) { case O_TO_SRC: if (cb->xflags & F_X_TO_SRC) { - if (!kernel_version) - get_kernel_version(); - if (kernel_version > LINUX_VERSION(2, 6, 10)) - xtables_error(PARAMETER_PROBLEM, - "SNAT: Multiple --to-source not supported"); + xtables_error(PARAMETER_PROBLEM, + "SNAT: Multiple --to-source not supported"); } parse_to(cb->arg, portok, range); + cb->xflags |= F_X_TO_SRC; break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; diff --git a/extensions/libip6t_SNAT.t b/extensions/libip6t_SNAT.t index bb080497..d188a6bb 100644 --- a/extensions/libip6t_SNAT.t +++ b/extensions/libip6t_SNAT.t @@ -2,7 +2,10 @@ *nat -j SNAT --to-source dead::beef;=;OK -j SNAT --to-source dead::beef-dead::fee7;=;OK +-j SNAT --to-source [dead::beef]:1025-65535;;FAIL +-j SNAT --to-source [dead::beef] --to-source [dead::fee7];;FAIL -p tcp -j SNAT --to-source [dead::beef]:1025-65535;=;OK -p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65535;=;OK -p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65536;;FAIL +-p tcp -j SNAT --to-source [dead::beef-dead::fee7]:1025-65535 --to-source [dead::beef-dead::fee8]:1025-65535;;FAIL -j SNAT;;FAIL diff --git a/extensions/libip6t_SNAT.txlate b/extensions/libip6t_SNAT.txlate new file mode 100644 index 00000000..9793f8d5 --- /dev/null +++ b/extensions/libip6t_SNAT.txlate @@ -0,0 +1,11 @@ +ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:80 +nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:80 + +ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:1-20 +nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:1-20 + +ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random +nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:123 random + +ip6tables-translate -t nat -A postrouting -o eth0 -p tcp -j SNAT --to [fec0::1234]:123 --random-fully --persistent +nft add rule ip6 nat postrouting oifname eth0 meta l4proto tcp counter snat to [fec0::1234]:123 fully-random,persistent diff --git a/extensions/libip6t_ah.txlate b/extensions/libip6t_ah.txlate new file mode 100644 index 00000000..c6b09a2e --- /dev/null +++ b/extensions/libip6t_ah.txlate @@ -0,0 +1,17 @@ +ip6tables-translate -A INPUT -m ah --ahspi 500 -j DROP +nft add rule ip6 filter INPUT ah spi 500 counter drop + +ip6tables-translate -A INPUT -m ah --ahspi 500:550 -j DROP +nft add rule ip6 filter INPUT ah spi 500-550 counter drop + +ip6tables-translate -A INPUT -m ah ! --ahlen 120 +nft add rule ip6 filter INPUT ah hdrlength != 120 counter + +ip6tables-translate -A INPUT -m ah --ahres +nft add rule ip6 filter INPUT ah reserved 1 counter + +ip6tables-translate -A INPUT -m ah --ahspi 500 ! --ahlen 120 -j DROP +nft add rule ip6 filter INPUT ah spi 500 ah hdrlength != 120 counter drop + +ip6tables-translate -A INPUT -m ah --ahspi 500 --ahlen 120 --ahres -j ACCEPT +nft add rule ip6 filter INPUT ah spi 500 ah hdrlength 120 ah reserved 1 counter accept diff --git a/extensions/libip6t_frag.txlate b/extensions/libip6t_frag.txlate new file mode 100644 index 00000000..e8bd9d4b --- /dev/null +++ b/extensions/libip6t_frag.txlate @@ -0,0 +1,17 @@ +ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 -j ACCEPT +nft add rule ip6 filter INPUT frag id 100-200 counter accept + +ip6tables-translate -t filter -A INPUT -m frag --fragid 100 --fragres --fragmore -j ACCEPT +nft add rule ip6 filter INPUT frag id 100 frag reserved 1 frag more-fragments 1 counter accept + +ip6tables-translate -t filter -A INPUT -m frag ! --fragid 100:200 -j ACCEPT +nft add rule ip6 filter INPUT frag id != 100-200 counter accept + +ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fraglast -j ACCEPT +nft add rule ip6 filter INPUT frag id 100-200 frag more-fragments 0 counter accept + +ip6tables-translate -t filter -A INPUT -m frag --fragid 100:200 --fragfirst -j ACCEPT +nft add rule ip6 filter INPUT frag id 100-200 frag frag-off 0 counter accept + +ip6tables-translate -t filter -A INPUT -m frag --fraglast -j ACCEPT +nft add rule ip6 filter INPUT frag more-fragments 0 counter accept diff --git a/extensions/libip6t_hbh.txlate b/extensions/libip6t_hbh.txlate new file mode 100644 index 00000000..28101fd7 --- /dev/null +++ b/extensions/libip6t_hbh.txlate @@ -0,0 +1,5 @@ +ip6tables-translate -t filter -A INPUT -m hbh --hbh-len 22 +nft add rule ip6 filter INPUT hbh hdrlength 22 counter + +ip6tables-translate -t filter -A INPUT -m hbh ! --hbh-len 22 +nft add rule ip6 filter INPUT hbh hdrlength != 22 counter diff --git a/extensions/libip6t_hl.txlate b/extensions/libip6t_hl.txlate new file mode 100644 index 00000000..17563938 --- /dev/null +++ b/extensions/libip6t_hl.txlate @@ -0,0 +1,5 @@ +ip6tables-translate -t nat -A postrouting -m hl --hl-gt 3 +nft add rule ip6 nat postrouting ip6 hoplimit gt 3 counter + +ip6tables-translate -t nat -A postrouting -m hl ! --hl-eq 3 +nft add rule ip6 nat postrouting ip6 hoplimit != 3 counter diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c index b49a241d..37c2bcb8 100644 --- a/extensions/libip6t_icmp6.c +++ b/extensions/libip6t_icmp6.c @@ -282,8 +282,6 @@ static int icmp6_xlate(struct xt_xlate *xl, if (!type_xlate_print(xl, info->type, info->code[0], info->code[1])) return 0; - xt_xlate_add(xl, " "); - return 1; } diff --git a/extensions/libip6t_icmp6.txlate b/extensions/libip6t_icmp6.txlate new file mode 100644 index 00000000..15481ad6 --- /dev/null +++ b/extensions/libip6t_icmp6.txlate @@ -0,0 +1,8 @@ +ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type 1 -j LOG +nft add rule ip6 filter INPUT icmpv6 type destination-unreachable counter log + +ip6tables-translate -t filter -A INPUT -m icmp6 --icmpv6-type neighbour-advertisement -j LOG +nft add rule ip6 filter INPUT icmpv6 type nd-neighbor-advert counter log + +ip6tables-translate -t filter -A INPUT -m icmp6 ! --icmpv6-type packet-too-big -j LOG +nft add rule ip6 filter INPUT icmpv6 type != packet-too-big counter log diff --git a/extensions/libip6t_mh.txlate b/extensions/libip6t_mh.txlate new file mode 100644 index 00000000..f5d638c0 --- /dev/null +++ b/extensions/libip6t_mh.txlate @@ -0,0 +1,5 @@ +ip6tables-translate -A INPUT -p mh --mh-type 1 -j ACCEPT +nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1 counter accept + +ip6tables-translate -A INPUT -p mh --mh-type 1:3 -j ACCEPT +nft add rule ip6 filter INPUT meta l4proto mobility-header mh type 1-3 counter accept diff --git a/extensions/libip6t_rt.txlate b/extensions/libip6t_rt.txlate new file mode 100644 index 00000000..6464cf9e --- /dev/null +++ b/extensions/libip6t_rt.txlate @@ -0,0 +1,14 @@ +ip6tables-translate -A INPUT -m rt --rt-type 0 -j DROP +nft add rule ip6 filter INPUT rt type 0 counter drop + +ip6tables-translate -A INPUT -m rt ! --rt-len 22 -j DROP +nft add rule ip6 filter INPUT rt hdrlength != 22 counter drop + +ip6tables-translate -A INPUT -m rt --rt-segsleft 26 -j ACCEPT +nft add rule ip6 filter INPUT rt seg-left 26 counter accept + +ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 -j DROP +nft add rule ip6 filter INPUT rt type 0 rt hdrlength 22 counter drop + +ip6tables-translate -A INPUT -m rt --rt-type 0 --rt-len 22 ! --rt-segsleft 26 -j ACCEPT +nft add rule ip6 filter INPUT rt type 0 rt seg-left != 26 rt hdrlength 22 counter accept diff --git a/extensions/libip6t_srh.c b/extensions/libip6t_srh.c new file mode 100644 index 00000000..ac0ae084 --- /dev/null +++ b/extensions/libip6t_srh.c @@ -0,0 +1,242 @@ +/* Shared library to add Segment Routing Header (SRH) matching support. + * + * Author: + * Ahmed Abdelsalam <amsalam20@gmail.com> + */ + +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter_ipv6/ip6t_srh.h> +#include <string.h> + +/* srh command-line options */ +enum { + O_SRH_NEXTHDR, + O_SRH_LEN_EQ, + O_SRH_LEN_GT, + O_SRH_LEN_LT, + O_SRH_SEGS_EQ, + O_SRH_SEGS_GT, + O_SRH_SEGS_LT, + O_SRH_LAST_EQ, + O_SRH_LAST_GT, + O_SRH_LAST_LT, + O_SRH_TAG, +}; + +static void srh_help(void) +{ + printf( +"srh match options:\n" +"[!] --srh-next-hdr next-hdr Next Header value of SRH\n" +"[!] --srh-hdr-len-eq hdr_len Hdr Ext Len value of SRH\n" +"[!] --srh-hdr-len-gt hdr_len Hdr Ext Len value of SRH\n" +"[!] --srh-hdr-len-lt hdr_len Hdr Ext Len value of SRH\n" +"[!] --srh-segs-left-eq segs_left Segments Left value of SRH\n" +"[!] --srh-segs-left-gt segs_left Segments Left value of SRH\n" +"[!] --srh-segs-left-lt segs_left Segments Left value of SRH\n" +"[!] --srh-last-entry-eq last_entry Last Entry value of SRH\n" +"[!] --srh-last-entry-gt last_entry Last Entry value of SRH\n" +"[!] --srh-last-entry-lt last_entry Last Entry value of SRH\n" +"[!] --srh-tag tag Tag value of SRH\n"); +} + +#define s struct ip6t_srh +static const struct xt_option_entry srh_opts[] = { + { .name = "srh-next-hdr", .id = O_SRH_NEXTHDR, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, next_hdr)}, + { .name = "srh-hdr-len-eq", .id = O_SRH_LEN_EQ, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)}, + { .name = "srh-hdr-len-gt", .id = O_SRH_LEN_GT, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)}, + { .name = "srh-hdr-len-lt", .id = O_SRH_LEN_LT, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdr_len)}, + { .name = "srh-segs-left-eq", .id = O_SRH_SEGS_EQ, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)}, + { .name = "srh-segs-left-gt", .id = O_SRH_SEGS_GT, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)}, + { .name = "srh-segs-left-lt", .id = O_SRH_SEGS_LT, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segs_left)}, + { .name = "srh-last-entry-eq", .id = O_SRH_LAST_EQ, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)}, + { .name = "srh-last-entry-gt", .id = O_SRH_LAST_GT, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)}, + { .name = "srh-last-entry-lt", .id = O_SRH_LAST_LT, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, last_entry)}, + { .name = "srh-tag", .id = O_SRH_TAG, .type = XTTYPE_UINT16, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, tag)}, + { } +}; +#undef s + +static void srh_init(struct xt_entry_match *m) +{ + struct ip6t_srh *srhinfo = (void *)m->data; + + srhinfo->mt_flags = 0; + srhinfo->mt_invflags = 0; +} + +static void srh_parse(struct xt_option_call *cb) +{ + struct ip6t_srh *srhinfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRH_NEXTHDR: + srhinfo->mt_flags |= IP6T_SRH_NEXTHDR; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_NEXTHDR; + break; + case O_SRH_LEN_EQ: + srhinfo->mt_flags |= IP6T_SRH_LEN_EQ; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_EQ; + break; + case O_SRH_LEN_GT: + srhinfo->mt_flags |= IP6T_SRH_LEN_GT; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_GT; + break; + case O_SRH_LEN_LT: + srhinfo->mt_flags |= IP6T_SRH_LEN_LT; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_LEN_LT; + break; + case O_SRH_SEGS_EQ: + srhinfo->mt_flags |= IP6T_SRH_SEGS_EQ; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_EQ; + break; + case O_SRH_SEGS_GT: + srhinfo->mt_flags |= IP6T_SRH_SEGS_GT; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_GT; + break; + case O_SRH_SEGS_LT: + srhinfo->mt_flags |= IP6T_SRH_SEGS_LT; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_SEGS_LT; + break; + case O_SRH_LAST_EQ: + srhinfo->mt_flags |= IP6T_SRH_LAST_EQ; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_EQ; + break; + case O_SRH_LAST_GT: + srhinfo->mt_flags |= IP6T_SRH_LAST_GT; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_GT; + break; + case O_SRH_LAST_LT: + srhinfo->mt_flags |= IP6T_SRH_LAST_LT; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_LAST_LT; + break; + case O_SRH_TAG: + srhinfo->mt_flags |= IP6T_SRH_TAG; + if (cb->invert) + srhinfo->mt_invflags |= IP6T_SRH_INV_TAG; + break; + } +} + +static void srh_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct ip6t_srh *srhinfo = (struct ip6t_srh *)match->data; + + printf(" srh"); + if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR) + printf(" next-hdr:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_NEXTHDR ? "!" : "", + srhinfo->next_hdr); + if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ) + printf(" hdr-len-eq:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LEN_EQ ? "!" : "", + srhinfo->hdr_len); + if (srhinfo->mt_flags & IP6T_SRH_LEN_GT) + printf(" hdr-len-gt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LEN_GT ? "!" : "", + srhinfo->hdr_len); + if (srhinfo->mt_flags & IP6T_SRH_LEN_LT) + printf(" hdr-len-lt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LEN_LT ? "!" : "", + srhinfo->hdr_len); + if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ) + printf(" segs-left-eq:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_EQ ? "!" : "", + srhinfo->segs_left); + if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT) + printf(" segs-left-gt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_GT ? "!" : "", + srhinfo->segs_left); + if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT) + printf(" segs-left-lt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_LT ? "!" : "", + srhinfo->segs_left); + if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ) + printf(" last-entry-eq:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LAST_EQ ? "!" : "", + srhinfo->last_entry); + if (srhinfo->mt_flags & IP6T_SRH_LAST_GT) + printf(" last-entry-gt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LAST_GT ? "!" : "", + srhinfo->last_entry); + if (srhinfo->mt_flags & IP6T_SRH_LAST_LT) + printf(" last-entry-lt:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_LAST_LT ? "!" : "", + srhinfo->last_entry); + if (srhinfo->mt_flags & IP6T_SRH_TAG) + printf(" tag:%s%d", srhinfo->mt_invflags & IP6T_SRH_INV_TAG ? "!" : "", + srhinfo->tag); +} + +static void srh_save(const void *ip, const struct xt_entry_match *match) +{ + const struct ip6t_srh *srhinfo = (struct ip6t_srh *)match->data; + + if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR) + printf("%s --srh-next-hdr %u", (srhinfo->mt_invflags & IP6T_SRH_INV_NEXTHDR) ? " !" : "", + srhinfo->next_hdr); + if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ) + printf("%s --srh-hdr-len-eq %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LEN_EQ) ? " !" : "", + srhinfo->hdr_len); + if (srhinfo->mt_flags & IP6T_SRH_LEN_GT) + printf("%s --srh-hdr-len-gt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LEN_GT) ? " !" : "", + srhinfo->hdr_len); + if (srhinfo->mt_flags & IP6T_SRH_LEN_LT) + printf("%s --srh-hdr-len-lt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LEN_LT) ? " !" : "", + srhinfo->hdr_len); + if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ) + printf("%s --srh-segs-left-eq %u", (srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_EQ) ? " !" : "", + srhinfo->segs_left); + if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT) + printf("%s --srh-segs-left-gt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_GT) ? " !" : "", + srhinfo->segs_left); + if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT) + printf("%s --srh-segs-left-lt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_SEGS_LT) ? " !" : "", + srhinfo->segs_left); + if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ) + printf("%s --srh-last-entry-eq %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LAST_EQ) ? " !" : "", + srhinfo->last_entry); + if (srhinfo->mt_flags & IP6T_SRH_LAST_GT) + printf("%s --srh-last-entry-gt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LAST_GT) ? " !" : "", + srhinfo->last_entry); + if (srhinfo->mt_flags & IP6T_SRH_LAST_LT) + printf("%s --srh-last-entry-lt %u", (srhinfo->mt_invflags & IP6T_SRH_INV_LAST_LT) ? " !" : "", + srhinfo->last_entry); + if (srhinfo->mt_flags & IP6T_SRH_TAG) + printf("%s --srh-tag %u", (srhinfo->mt_invflags & IP6T_SRH_INV_TAG) ? " !" : "", + srhinfo->tag); +} + +static struct xtables_match srh_mt6_reg = { + .name = "srh", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_srh)), + .userspacesize = XT_ALIGN(sizeof(struct ip6t_srh)), + .help = srh_help, + .init = srh_init, + .print = srh_print, + .save = srh_save, + .x6_parse = srh_parse, + .x6_options = srh_opts, +}; + +void +_init(void) +{ + xtables_register_match(&srh_mt6_reg); +} diff --git a/extensions/libip6t_srh.t b/extensions/libip6t_srh.t new file mode 100644 index 00000000..08897d5c --- /dev/null +++ b/extensions/libip6t_srh.t @@ -0,0 +1,26 @@ +:INPUT,FORWARD,OUTPUT +-m srh --srh-next-hdr 17;=;OK +-m srh --srh-hdr-len-eq 8;=;OK +-m srh --srh-hdr-len-gt 8;=;OK +-m srh --srh-hdr-len-lt 8;=;OK +-m srh --srh-segs-left-eq 1;=;OK +-m srh --srh-segs-left-gt 1;=;OK +-m srh --srh-segs-left-lt 1;=;OK +-m srh --srh-last-entry-eq 4;=;OK +-m srh --srh-last-entry-gt 4;=;OK +-m srh --srh-last-entry-lt 4;=;OK +-m srh --srh-tag 0;=;OK +-m srh ! --srh-next-hdr 17;=;OK +-m srh ! --srh-hdr-len-eq 8;=;OK +-m srh ! --srh-hdr-len-gt 8;=;OK +-m srh ! --srh-hdr-len-lt 8;=;OK +-m srh ! --srh-segs-left-eq 1;=;OK +-m srh ! --srh-segs-left-gt 1;=;OK +-m srh ! --srh-segs-left-lt 1;=;OK +-m srh ! --srh-last-entry-eq 4;=;OK +-m srh ! --srh-last-entry-gt 4;=;OK +-m srh ! --srh-last-entry-lt 4;=;OK +-m srh ! --srh-tag 0;=;OK +-m srh --srh-next-hdr 17 --srh-segs-left-eq 1 --srh-last-entry-eq 4 --srh-tag 0;=;OK +-m srh ! --srh-next-hdr 17 ! --srh-segs-left-eq 0 --srh-tag 0;=;OK +-m srh;=;OK diff --git a/extensions/libipt_DNAT.t b/extensions/libipt_DNAT.t index e3fd5632..1959801d 100644 --- a/extensions/libipt_DNAT.t +++ b/extensions/libipt_DNAT.t @@ -2,7 +2,10 @@ *nat -j DNAT --to-destination 1.1.1.1;=;OK -j DNAT --to-destination 1.1.1.1-1.1.1.10;=;OK +-j DNAT --to-destination 1.1.1.1:1025-65535;;FAIL +-j DNAT --to-destination 1.1.1.1 --to-destination 2.2.2.2;;FAIL -p tcp -j DNAT --to-destination 1.1.1.1:1025-65535;=;OK -p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65535;=;OK -p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65536;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1-1.1.1.10:1025-65535 --to-destination 2.2.2.2-2.2.2.20:1025-65535;;FAIL -j DNAT;;FAIL diff --git a/extensions/libipt_DNAT.txlate b/extensions/libipt_DNAT.txlate new file mode 100644 index 00000000..692358e2 --- /dev/null +++ b/extensions/libipt_DNAT.txlate @@ -0,0 +1,14 @@ +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 +nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4 + +iptables-translate -t nat -A prerouting -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10 +nft add rule ip nat prerouting ip daddr 15.45.23.67 tcp dport 80 counter dnat to 192.168.1.1-192.168.1.10 + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4:1-1023 +nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4:1-1023 + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random +nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4 random + +iptables-translate -t nat -A prerouting -p tcp -o eth0 -j DNAT --to-destination 1.2.3.4 --random --persistent +nft add rule ip nat prerouting oifname eth0 ip protocol tcp counter dnat to 1.2.3.4 random,persistent diff --git a/extensions/libipt_LOG.txlate b/extensions/libipt_LOG.txlate new file mode 100644 index 00000000..81f64fb2 --- /dev/null +++ b/extensions/libipt_LOG.txlate @@ -0,0 +1,5 @@ +iptables-translate -A FORWARD -p tcp -j LOG --log-level error +nft add rule ip filter FORWARD ip protocol tcp counter log level err + +iptables-translate -A FORWARD -p tcp -j LOG --log-prefix "Random prefix" +nft add rule ip filter FORWARD ip protocol tcp counter log prefix \"Random prefix\" diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c index b7b5fc74..90bf6065 100644 --- a/extensions/libipt_MASQUERADE.c +++ b/extensions/libipt_MASQUERADE.c @@ -11,6 +11,7 @@ enum { O_TO_PORTS = 0, O_RANDOM, + O_RANDOM_FULLY, }; static void MASQUERADE_help(void) @@ -20,12 +21,15 @@ static void MASQUERADE_help(void) " --to-ports <port>[-<port>]\n" " Port (range) to map to.\n" " --random\n" -" Randomize source port.\n"); +" Randomize source port.\n" +" --random-fully\n" +" Fully 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}, + {.name = "random-fully", .id = O_RANDOM_FULLY, .type = XTTYPE_NONE}, XTOPT_TABLEEND, }; @@ -97,6 +101,9 @@ static void MASQUERADE_parse(struct xt_option_call *cb) case O_RANDOM: mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; break; + case O_RANDOM_FULLY: + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM_FULLY; + break; } } @@ -116,6 +123,9 @@ MASQUERADE_print(const void *ip, const struct xt_entry_target *target, if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) printf(" random"); + + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" random-fully"); } static void @@ -132,6 +142,9 @@ MASQUERADE_save(const void *ip, const struct xt_entry_target *target) if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) printf(" --random"); + + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) + printf(" --random-fully"); } static int MASQUERADE_xlate(struct xt_xlate *xl, diff --git a/extensions/libipt_MASQUERADE.t b/extensions/libipt_MASQUERADE.t index 46502040..e25d2a04 100644 --- a/extensions/libipt_MASQUERADE.t +++ b/extensions/libipt_MASQUERADE.t @@ -2,6 +2,7 @@ *nat -j MASQUERADE;=;OK -j MASQUERADE --random;=;OK +-j MASQUERADE --random-fully;=;OK -p tcp -j MASQUERADE --to-ports 1024;=;OK -p udp -j MASQUERADE --to-ports 1024-65535;=;OK -p udp -j MASQUERADE --to-ports 1024-65536;;FAIL diff --git a/extensions/libipt_MASQUERADE.txlate b/extensions/libipt_MASQUERADE.txlate new file mode 100644 index 00000000..40b6958a --- /dev/null +++ b/extensions/libipt_MASQUERADE.txlate @@ -0,0 +1,8 @@ +iptables-translate -t nat -A POSTROUTING -j MASQUERADE +nft add rule ip nat POSTROUTING counter masquerade + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10 +nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10 + +iptables-translate -t nat -A POSTROUTING -p tcp -j MASQUERADE --to-ports 10-20 --random +nft add rule ip nat POSTROUTING ip protocol tcp counter masquerade to :10-20 random diff --git a/extensions/libipt_REDIRECT.txlate b/extensions/libipt_REDIRECT.txlate new file mode 100644 index 00000000..815bb771 --- /dev/null +++ b/extensions/libipt_REDIRECT.txlate @@ -0,0 +1,5 @@ +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 8080 --random +nft add rule ip nat prerouting tcp dport 80 counter redirect to :8080 random diff --git a/extensions/libipt_REJECT.txlate b/extensions/libipt_REJECT.txlate new file mode 100644 index 00000000..a1bfb5f4 --- /dev/null +++ b/extensions/libipt_REJECT.txlate @@ -0,0 +1,8 @@ +iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT +nft add rule ip filter FORWARD tcp dport 22 counter reject + +iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with icmp-net-unreachable +nft add rule ip filter FORWARD tcp dport 22 counter reject with icmp type net-unreachable + +iptables-translate -A FORWARD -p TCP --dport 22 -j REJECT --reject-with tcp-reset +nft add rule ip filter FORWARD tcp dport 22 counter reject with tcp reset diff --git a/extensions/libipt_SNAT.t b/extensions/libipt_SNAT.t index 73071bb0..186e1cb8 100644 --- a/extensions/libipt_SNAT.t +++ b/extensions/libipt_SNAT.t @@ -2,7 +2,10 @@ *nat -j SNAT --to-source 1.1.1.1;=;OK -j SNAT --to-source 1.1.1.1-1.1.1.10;=;OK +-j SNAT --to-source 1.1.1.1:1025-65535;;FAIL +-j SNAT --to-source 1.1.1.1 --to-source 2.2.2.2;;FAIL -p tcp -j SNAT --to-source 1.1.1.1:1025-65535;=;OK -p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535;=;OK -p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65536;;FAIL +-p tcp -j SNAT --to-source 1.1.1.1-1.1.1.10:1025-65535 --to-source 2.2.2.2-2.2.2.20:1025-65535;;FAIL -j SNAT;;FAIL diff --git a/extensions/libipt_SNAT.txlate b/extensions/libipt_SNAT.txlate new file mode 100644 index 00000000..4efd3ad0 --- /dev/null +++ b/extensions/libipt_SNAT.txlate @@ -0,0 +1,14 @@ +iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 +nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4 + +iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6 +nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4-1.2.3.6 + +iptables-translate -t nat -A postrouting -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023 +nft add rule ip nat postrouting oifname eth0 ip protocol tcp counter snat to 1.2.3.4:1-1023 + +iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random +nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4 random + +iptables-translate -t nat -A postrouting -o eth0 -j SNAT --to 1.2.3.4 --random --persistent +nft add rule ip nat postrouting oifname eth0 counter snat to 1.2.3.4 random,persistent diff --git a/extensions/libipt_ah.txlate b/extensions/libipt_ah.txlate new file mode 100644 index 00000000..ea3ef3e9 --- /dev/null +++ b/extensions/libipt_ah.txlate @@ -0,0 +1,8 @@ +iptables-translate -A INPUT -p 51 -m ah --ahspi 500 -j DROP +nft add rule ip filter INPUT ah spi 500 counter drop + +iptables-translate -A INPUT -p 51 -m ah --ahspi 500:600 -j DROP +nft add rule ip filter INPUT ah spi 500-600 counter drop + +iptables-translate -A INPUT -p 51 -m ah ! --ahspi 50 -j DROP +nft add rule ip filter INPUT ah spi != 50 counter drop diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate new file mode 100644 index 00000000..434f8cc4 --- /dev/null +++ b/extensions/libipt_icmp.txlate @@ -0,0 +1,8 @@ +iptables-translate -t filter -A INPUT -m icmp --icmp-type echo-reply -j ACCEPT +nft add rule ip filter INPUT icmp type echo-reply counter accept + +iptables-translate -t filter -A INPUT -m icmp --icmp-type 3 -j ACCEPT +nft add rule ip filter INPUT icmp type destination-unreachable counter accept + +iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT +nft add rule ip filter INPUT icmp type != destination-unreachable counter accept diff --git a/extensions/libipt_realm.txlate b/extensions/libipt_realm.txlate new file mode 100644 index 00000000..7d710294 --- /dev/null +++ b/extensions/libipt_realm.txlate @@ -0,0 +1,11 @@ +iptables-translate -A PREROUTING -m realm --realm 4 +nft add rule ip filter PREROUTING rtclassid 0x4 counter + +iptables-translate -A PREROUTING -m realm --realm 5/5 +nft add rule ip filter PREROUTING rtclassid and 0x5 == 0x5 counter + +iptables-translate -A PREROUTING -m realm ! --realm 50 +nft add rule ip filter PREROUTING rtclassid != 0x32 counter + +iptables-translate -A INPUT -m realm --realm 1/0xf +nft add rule ip filter INPUT rtclassid and 0xf == 0x1 counter diff --git a/extensions/libipt_ttl.txlate b/extensions/libipt_ttl.txlate new file mode 100644 index 00000000..3d5d6a70 --- /dev/null +++ b/extensions/libipt_ttl.txlate @@ -0,0 +1,5 @@ +iptables-translate -A INPUT -m ttl --ttl-eq 3 -j ACCEPT +nft add rule ip filter INPUT ip ttl 3 counter accept + +iptables-translate -A INPUT -m ttl --ttl-gt 5 -j ACCEPT +nft add rule ip filter INPUT ip ttl gt 5 counter accept diff --git a/extensions/libxt_CLASSIFY.txlate b/extensions/libxt_CLASSIFY.txlate new file mode 100644 index 00000000..3b349237 --- /dev/null +++ b/extensions/libxt_CLASSIFY.txlate @@ -0,0 +1,8 @@ +iptables-translate -A OUTPUT -j CLASSIFY --set-class 0:0 +nft add rule ip filter OUTPUT counter meta priority set none + +iptables-translate -A OUTPUT -j CLASSIFY --set-class ffff:ffff +nft add rule ip filter OUTPUT counter meta priority set root + +iptables-translate -A OUTPUT -j CLASSIFY --set-class 1:234 +nft add rule ip filter OUTPUT counter meta priority set 1:234 diff --git a/extensions/libxt_CONNMARK.txlate b/extensions/libxt_CONNMARK.txlate new file mode 100644 index 00000000..62321be1 --- /dev/null +++ b/extensions/libxt_CONNMARK.txlate @@ -0,0 +1,23 @@ +iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x16 +nft add rule ip mangle PREROUTING counter ct mark set 0x16 + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-xmark 0x16/0x12 +nft add rule ip mangle PREROUTING counter ct mark set ct mark xor 0x16 and 0xffffffed + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --and-mark 0x16 +nft add rule ip mangle PREROUTING counter ct mark set ct mark and 0x16 + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --or-mark 0x16 +nft add rule ip mangle PREROUTING counter ct mark set ct mark or 0x16 + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --save-mark +nft add rule ip mangle PREROUTING counter ct mark set mark + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --save-mark --mask 0x12 +nft add rule ip mangle PREROUTING counter ct mark set mark and 0x12 + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark +nft add rule ip mangle PREROUTING counter meta mark set ct mark + +iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark --mask 0x12 +nft add rule ip mangle PREROUTING counter meta mark set ct mark and 0x12 diff --git a/extensions/libxt_DSCP.txlate b/extensions/libxt_DSCP.txlate new file mode 100644 index 00000000..442742ef --- /dev/null +++ b/extensions/libxt_DSCP.txlate @@ -0,0 +1,5 @@ +iptables-translate -A OUTPUT -j DSCP --set-dscp 1 +nft add rule ip filter OUTPUT counter ip dscp set 0x01 + +ip6tables-translate -A OUTPUT -j DSCP --set-dscp 6 +nft add rule ip6 filter OUTPUT counter ip6 dscp set 0x06 diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c index c2f15e3b..12b1695e 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -76,7 +76,7 @@ static void mark_tg_help(void) " --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n" " --and-mark bits Binary AND the nfmark with bits\n" " --or-mark bits Binary OR the nfmark with bits\n" -" --xor-mask bits Binary XOR the nfmark with bits\n" +" --xor-mark bits Binary XOR the nfmark with bits\n" "\n"); } diff --git a/extensions/libxt_MARK.txlate b/extensions/libxt_MARK.txlate new file mode 100644 index 00000000..ab5977e9 --- /dev/null +++ b/extensions/libxt_MARK.txlate @@ -0,0 +1,23 @@ +iptables-translate -t mangle -A OUTPUT -j MARK --set-mark 64 +nft add rule ip mangle OUTPUT counter meta mark set 0x40 + +iptables-translate -t mangle -A OUTPUT -j MARK --set-xmark 0x40/0x32 +nft add rule ip mangle OUTPUT counter meta mark set mark and 0xffffffcd xor 0x40 + +iptables-translate -t mangle -A OUTPUT -j MARK --or-mark 64 +nft add rule ip mangle OUTPUT counter meta mark set mark or 0x40 + +iptables-translate -t mangle -A OUTPUT -j MARK --and-mark 64 +nft add rule ip mangle OUTPUT counter meta mark set mark and 0x40 + +iptables-translate -t mangle -A OUTPUT -j MARK --xor-mark 64 +nft add rule ip mangle OUTPUT counter meta mark set mark xor 0x40 + +iptables-translate -t mangle -A PREROUTING -j MARK --set-mark 0x64 +nft add rule ip mangle PREROUTING counter meta mark set 0x64 + +iptables-translate -t mangle -A PREROUTING -j MARK --and-mark 0x64 +nft add rule ip mangle PREROUTING counter meta mark set mark and 0x64 + +iptables-translate -t mangle -A PREROUTING -j MARK --or-mark 0x64 +nft add rule ip mangle PREROUTING counter meta mark set mark or 0x64 diff --git a/extensions/libxt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man index c9e39501..cc1e7690 100644 --- a/extensions/libxt_MASQUERADE.man +++ b/extensions/libxt_MASQUERADE.man @@ -25,4 +25,10 @@ If option \fB\-\-random\fP is used then port mapping will be randomized (kernel >= 2.6.21). .TP +\fB\-\-random-fully\fP +Full randomize source port mapping +If option +\fB\-\-random-fully\fP +is used then port mapping will be fully randomized (kernel >= 3.13). +.TP IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libxt_NFLOG.txlate b/extensions/libxt_NFLOG.txlate new file mode 100644 index 00000000..a0872c9e --- /dev/null +++ b/extensions/libxt_NFLOG.txlate @@ -0,0 +1,14 @@ +iptables-translate -A FORWARD -j NFLOG --nflog-group 32 --nflog-prefix "Prefix 1.0" +nft add rule ip filter FORWARD counter log prefix \"Prefix 1.0\" group 32 + +iptables-translate -A OUTPUT -j NFLOG --nflog-group 30 +nft add rule ip filter OUTPUT counter log group 30 + +iptables-translate -I INPUT -j NFLOG --nflog-threshold 2 +nft insert rule ip filter INPUT counter log queue-threshold 2 group 0 + +iptables-translate -I INPUT -j NFLOG --nflog-size 256 +nft insert rule ip filter INPUT counter log snaplen 256 group 0 + +iptables-translate -I INPUT -j NFLOG --nflog-threshold 25 +nft insert rule ip filter INPUT counter log queue-threshold 25 group 0 diff --git a/extensions/libxt_NFQUEUE.txlate b/extensions/libxt_NFQUEUE.txlate new file mode 100644 index 00000000..3d188a7a --- /dev/null +++ b/extensions/libxt_NFQUEUE.txlate @@ -0,0 +1,8 @@ +iptables-translate -t nat -A PREROUTING -p tcp --dport 80 -j NFQUEUE --queue-num 30 +nft add rule ip nat PREROUTING tcp dport 80 counter queue num 30 + +iptables-translate -A FORWARD -j NFQUEUE --queue-num 0 --queue-bypass -p TCP --sport 80 +nft add rule ip filter FORWARD tcp sport 80 counter queue num 0 bypass + +iptables-translate -A FORWARD -j NFQUEUE --queue-bypass -p TCP --sport 80 --queue-balance 0:3 --queue-cpu-fanout +nft add rule ip filter FORWARD tcp sport 80 counter queue num 0-3 bypass,fanout diff --git a/extensions/libxt_TCPMSS.c b/extensions/libxt_TCPMSS.c index 4b71e44a..0d9b200e 100644 --- a/extensions/libxt_TCPMSS.c +++ b/extensions/libxt_TCPMSS.c @@ -91,6 +91,19 @@ static void TCPMSS_save(const void *ip, const struct xt_entry_target *target) printf(" --set-mss %u", mssinfo->mss); } +static int TCPMSS_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + const struct xt_tcpmss_info *mssinfo = + (const struct xt_tcpmss_info *)params->target->data; + if (mssinfo->mss == XT_TCPMSS_CLAMP_PMTU) + xt_xlate_add(xl, "tcp option maxseg size set rt mtu"); + else + xt_xlate_add(xl, "tcp option maxseg size set %d", mssinfo->mss); + + return 1; +} + static struct xtables_target tcpmss_tg_reg[] = { { .family = NFPROTO_IPV4, @@ -104,6 +117,7 @@ static struct xtables_target tcpmss_tg_reg[] = { .x6_parse = TCPMSS_parse, .x6_fcheck = TCPMSS_check, .x6_options = TCPMSS4_opts, + .xlate = TCPMSS_xlate, }, { .family = NFPROTO_IPV6, diff --git a/extensions/libxt_TCPMSS.txlate b/extensions/libxt_TCPMSS.txlate new file mode 100644 index 00000000..6a64d2ce --- /dev/null +++ b/extensions/libxt_TCPMSS.txlate @@ -0,0 +1,5 @@ +iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu +nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set rt mtu + +iptables-translate -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 90 +nft add rule ip filter FORWARD tcp flags & (syn|rst) == syn counter tcp option maxseg size set 90 diff --git a/extensions/libxt_TEE.txlate b/extensions/libxt_TEE.txlate new file mode 100644 index 00000000..9fcee254 --- /dev/null +++ b/extensions/libxt_TEE.txlate @@ -0,0 +1,11 @@ +# iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 --oif eth0 +# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 device eth0 +# +# iptables-translate -t mangle -A PREROUTING -j TEE --gateway 192.168.0.2 +# nft add rule ip mangle PREROUTING counter dup to 192.168.0.2 + +ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: +nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: + +ip6tables-translate -t mangle -A PREROUTING -j TEE --gateway ab12:00a1:1112:acba:: --oif eth0 +nft add rule ip6 mangle PREROUTING counter dup to ab12:a1:1112:acba:: device eth0 diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c index cef58765..b66fa329 100644 --- a/extensions/libxt_TOS.c +++ b/extensions/libxt_TOS.c @@ -183,6 +183,30 @@ static void tos_tg_save(const void *ip, const struct xt_entry_target *target) printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask); } +static int tos_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + const struct ipt_tos_target_info *info = + (struct ipt_tos_target_info *) params->target->data; + uint8_t dscp = info->tos >> 2; + + xt_xlate_add(xl, "ip dscp set 0x%02x", dscp); + + return 1; +} + +static int tos_xlate6(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + const struct ipt_tos_target_info *info = + (struct ipt_tos_target_info *) params->target->data; + uint8_t dscp = info->tos >> 2; + + xt_xlate_add(xl, "ip6 dscp set 0x%02x", dscp); + + return 1; +} + static struct xtables_target tos_tg_reg[] = { { .version = XTABLES_VERSION, @@ -197,6 +221,7 @@ static struct xtables_target tos_tg_reg[] = { .x6_parse = tos_tg_parse_v0, .x6_fcheck = tos_tg_check, .x6_options = tos_tg_opts_v0, + .xlate = tos_xlate, }, { .version = XTABLES_VERSION, @@ -211,6 +236,7 @@ static struct xtables_target tos_tg_reg[] = { .x6_parse = tos_tg_parse, .x6_fcheck = tos_tg_check, .x6_options = tos_tg_opts, + .xlate = tos_xlate6, }, }; diff --git a/extensions/libxt_TOS.txlate b/extensions/libxt_TOS.txlate new file mode 100644 index 00000000..0952310e --- /dev/null +++ b/extensions/libxt_TOS.txlate @@ -0,0 +1,23 @@ +ip6tables-translate -A INPUT -j TOS --set-tos 0x1f +nft add rule ip6 filter INPUT counter ip6 dscp set 0x07 + +ip6tables-translate -A INPUT -j TOS --set-tos 0xff +nft add rule ip6 filter INPUT counter ip6 dscp set 0x3f + +ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Delay +nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 + +ip6tables-translate -A INPUT -j TOS --set-tos Minimize-Cost +nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 + +ip6tables-translate -A INPUT -j TOS --set-tos Normal-Service +nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 + +ip6tables-translate -A INPUT -j TOS --and-tos 0x12 +nft add rule ip6 filter INPUT counter ip6 dscp set 0x00 + +ip6tables-translate -A INPUT -j TOS --or-tos 0x12 +nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 + +ip6tables-translate -A INPUT -j TOS --xor-tos 0x12 +nft add rule ip6 filter INPUT counter ip6 dscp set 0x04 diff --git a/extensions/libxt_TRACE.txlate b/extensions/libxt_TRACE.txlate new file mode 100644 index 00000000..8e3d2a7a --- /dev/null +++ b/extensions/libxt_TRACE.txlate @@ -0,0 +1,2 @@ +iptables-translate -t raw -A PREROUTING -j TRACE +nft add rule ip raw PREROUTING counter nftrace set 1 diff --git a/extensions/libxt_addrtype.c b/extensions/libxt_addrtype.c index e5d3033c..5cafa219 100644 --- a/extensions/libxt_addrtype.c +++ b/extensions/libxt_addrtype.c @@ -5,6 +5,7 @@ * This program is released under the terms of GNU GPL */ #include <stdio.h> #include <string.h> +#include <strings.h> #include <xtables.h> #include <linux/netfilter/xt_addrtype.h> @@ -245,6 +246,74 @@ static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match) printf(" --limit-iface-out"); } +static const char *const rtn_lnames[] = { + "unspec", + "unicast", + "local", + "broadcast", + "anycast", + "multicast", + "blackhole", + "unreachable", + "prohibit", + NULL, +}; + +static bool multiple_bits_set(uint16_t val) +{ + int first = ffs(val); + + return first && (val >> first) > 0; +} + +static int addrtype_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_addrtype_info_v1 *info = + (const void *)params->match->data; + const char *sep = ""; + bool need_braces; + uint16_t val; + int i; + + xt_xlate_add(xl, "fib "); + + if (info->source) { + xt_xlate_add(xl, "saddr "); + val = info->source; + } else { + xt_xlate_add(xl, "daddr "); + val = info->dest; + } + + if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) + xt_xlate_add(xl, ". iif "); + else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) + xt_xlate_add(xl, ". oif "); + + xt_xlate_add(xl, "type "); + + if (info->flags & (XT_ADDRTYPE_INVERT_SOURCE | XT_ADDRTYPE_INVERT_DEST)) + xt_xlate_add(xl, "!= "); + + need_braces = multiple_bits_set(val); + + if (need_braces) + xt_xlate_add(xl, "{ "); + + for (i = 0; rtn_lnames[i]; i++) { + if (val & (1 << i)) { + xt_xlate_add(xl, "%s%s", sep, rtn_lnames[i]); + sep = ", "; + } + } + + if (need_braces) + xt_xlate_add(xl, " }"); + + return 1; +} + static const struct xt_option_entry addrtype_opts_v0[] = { {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, @@ -292,6 +361,7 @@ static struct xtables_match addrtype_mt_reg[] = { .x6_parse = addrtype_parse_v1, .x6_fcheck = addrtype_check, .x6_options = addrtype_opts_v1, + .xlate = addrtype_xlate, }, }; diff --git a/extensions/libxt_addrtype.txlate b/extensions/libxt_addrtype.txlate new file mode 100644 index 00000000..a719b2c9 --- /dev/null +++ b/extensions/libxt_addrtype.txlate @@ -0,0 +1,11 @@ +iptables-translate -A INPUT -m addrtype --src-type LOCAL +nft add rule ip filter INPUT fib saddr type local counter + +iptables-translate -A INPUT -m addrtype --dst-type LOCAL +nft add rule ip filter INPUT fib daddr type local counter + +iptables-translate -A INPUT -m addrtype ! --dst-type ANYCAST,LOCAL +nft add rule ip filter INPUT fib daddr type != { local, anycast } counter + +iptables-translate -A INPUT -m addrtype --limit-iface-in --dst-type ANYCAST,LOCAL +nft add rule ip filter INPUT fib daddr . iif type { local, anycast } counter diff --git a/extensions/libxt_cgroup.txlate b/extensions/libxt_cgroup.txlate new file mode 100644 index 00000000..75f2e6ae --- /dev/null +++ b/extensions/libxt_cgroup.txlate @@ -0,0 +1,5 @@ +iptables-translate -t filter -A INPUT -m cgroup --cgroup 0 -j ACCEPT +nft add rule ip filter INPUT meta cgroup 0 counter accept + +iptables-translate -t filter -A INPUT -m cgroup ! --cgroup 0 -j ACCEPT +nft add rule ip filter INPUT meta cgroup != 0 counter accept diff --git a/extensions/libxt_cluster.c b/extensions/libxt_cluster.c index 3adff12c..c9c35ee2 100644 --- a/extensions/libxt_cluster.c +++ b/extensions/libxt_cluster.c @@ -126,6 +126,56 @@ cluster_save(const void *ip, const struct xt_entry_match *match) info->total_nodes, info->hash_seed); } +static int cluster_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + int node, shift_value = 1, comma_needed = 0; + uint32_t temp_node_mask, node_id = 0, needs_set = 0; + const struct xt_cluster_match_info *info = (void *)params->match->data; + const char *jhash_st = "jhash ct original saddr mod"; + const char *pkttype_st = "meta pkttype set host"; + + if (!(info->node_mask & (info->node_mask - 1))) { + if (info->node_mask <= 2) + xt_xlate_add(xl, "%s %u seed 0x%08x eq %u %s", jhash_st, + info->total_nodes, info->hash_seed, + info->node_mask, pkttype_st); + else { + temp_node_mask = info->node_mask; + while (1) { + temp_node_mask = temp_node_mask >> shift_value; + node_id++; + if (temp_node_mask == 0) + break; + } + xt_xlate_add(xl, "%s %u seed 0x%08x eq %u %s", jhash_st, + info->total_nodes, info->hash_seed, + node_id, pkttype_st); + } + } else { + xt_xlate_add(xl, "%s %u seed 0x%08x ", jhash_st, + info->total_nodes, info->hash_seed); + for (node = 0; node < 32; node++) { + if (info->node_mask & (1 << node)) { + if (needs_set == 0) { + xt_xlate_add(xl, "{ "); + needs_set = 1; + } + + if (comma_needed) + xt_xlate_add(xl, ", "); + xt_xlate_add(xl, "%u", node); + comma_needed++; + } + } + if (needs_set) + xt_xlate_add(xl, " }"); + xt_xlate_add(xl, " %s", pkttype_st); + } + + return 1; +} + static struct xtables_match cluster_mt_reg = { .family = NFPROTO_UNSPEC, .name = "cluster", @@ -138,6 +188,7 @@ static struct xtables_match cluster_mt_reg = { .x6_parse = cluster_parse, .x6_fcheck = cluster_check, .x6_options = cluster_opts, + .xlate = cluster_xlate, }; void _init(void) diff --git a/extensions/libxt_cluster.txlate b/extensions/libxt_cluster.txlate new file mode 100644 index 00000000..a9d3b51a --- /dev/null +++ b/extensions/libxt_cluster.txlate @@ -0,0 +1,26 @@ +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-node 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 2 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 2 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 1 --cluster-local-nodemask 1 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 1 seed 0xdeadbeef eq 1 meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-node 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 32 seed 0xdeadbeef eq 32 meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 32 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 32 seed 0xdeadbeef eq 6 meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 32 --cluster-local-nodemask 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 32 seed 0xdeadbeef { 0, 2 } meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-nodemask 9 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 7 seed 0xdeadbeef { 0, 3 } meta pkttype set host counter meta mark set 0xffff + +iptables-translate -A PREROUTING -t mangle -i eth1 -m cluster --cluster-total-nodes 7 --cluster-local-node 5 --cluster-hash-seed 0xdeadbeef -j MARK --set-mark 0xffff +nft add rule ip mangle PREROUTING iifname eth1 jhash ct original saddr mod 7 seed 0xdeadbeef eq 5 meta pkttype set host counter meta mark set 0xffff diff --git a/extensions/libxt_comment.txlate b/extensions/libxt_comment.txlate new file mode 100644 index 00000000..c610b0e5 --- /dev/null +++ b/extensions/libxt_comment.txlate @@ -0,0 +1,8 @@ +iptables-translate -A INPUT -s 192.168.0.0 -m comment --comment "A privatized IP block" +nft add rule ip filter INPUT ip saddr 192.168.0.0 counter comment \"A privatized IP block\" + +iptables-translate -A INPUT -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j LONGNACCEPT -m comment --comment "foobar" +nft add rule ip filter INPUT ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter jump LONGNACCEPT comment \"foobar\" + +iptables-translate -A FORWARD -p tcp -m tcp --sport http -s 192.168.0.0/16 -d 192.168.0.0/16 -j DROP -m comment --comment singlecomment +nft add rule ip filter FORWARD ip saddr 192.168.0.0/16 ip daddr 192.168.0.0/16 tcp sport 80 counter drop comment \"singlecomment\" diff --git a/extensions/libxt_connbytes.txlate b/extensions/libxt_connbytes.txlate new file mode 100644 index 00000000..f78958d2 --- /dev/null +++ b/extensions/libxt_connbytes.txlate @@ -0,0 +1,14 @@ +iptables-translate -A OUTPUT -m connbytes --connbytes 200 --connbytes-dir original --connbytes-mode packets +nft add rule ip filter OUTPUT ct original packets ge 200 counter + +iptables-translate -A OUTPUT -m connbytes ! --connbytes 200 --connbytes-dir reply --connbytes-mode packets +nft add rule ip filter OUTPUT ct reply packets lt 200 counter + +iptables-translate -A OUTPUT -m connbytes --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes +nft add rule ip filter OUTPUT ct bytes 200-600 counter + +iptables-translate -A OUTPUT -m connbytes ! --connbytes 200:600 --connbytes-dir both --connbytes-mode bytes +nft add rule ip filter OUTPUT ct bytes != 200-600 counter + +iptables-translate -A OUTPUT -m connbytes --connbytes 200:200 --connbytes-dir both --connbytes-mode avgpkt +nft add rule ip filter OUTPUT ct avgpkt 200 counter diff --git a/extensions/libxt_connlabel.txlate b/extensions/libxt_connlabel.txlate new file mode 100644 index 00000000..5be42204 --- /dev/null +++ b/extensions/libxt_connlabel.txlate @@ -0,0 +1,5 @@ +iptables-translate -A INPUT -m connlabel --label bit40 +nft add rule ip filter INPUT ct label bit40 counter + +iptables-translate -A INPUT -m connlabel ! --label bit40 --set +nft add rule ip filter INPUT ct label set bit40 ct label and bit40 != bit40 counter diff --git a/extensions/libxt_connmark.txlate b/extensions/libxt_connmark.txlate new file mode 100644 index 00000000..89423259 --- /dev/null +++ b/extensions/libxt_connmark.txlate @@ -0,0 +1,14 @@ +iptables-translate -A INPUT -m connmark --mark 2 -j ACCEPT +nft add rule ip filter INPUT ct mark 0x2 counter accept + +iptables-translate -A INPUT -m connmark ! --mark 2 -j ACCEPT +nft add rule ip filter INPUT ct mark != 0x2 counter accept + +iptables-translate -A INPUT -m connmark --mark 10/10 -j ACCEPT +nft add rule ip filter INPUT ct mark and 0xa == 0xa counter accept + +iptables-translate -A INPUT -m connmark ! --mark 10/10 -j ACCEPT +nft add rule ip filter INPUT ct mark and 0xa != 0xa counter accept + +iptables-translate -t mangle -A PREROUTING -p tcp --dport 40 -m connmark --mark 0x40 +nft add rule ip mangle PREROUTING tcp dport 40 ct mark 0x40 counter diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate new file mode 100644 index 00000000..e35d5ce8 --- /dev/null +++ b/extensions/libxt_conntrack.txlate @@ -0,0 +1,41 @@ +iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCEPT +nft add rule ip filter INPUT ct state new,related counter accept + +ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT +nft add rule ip6 filter INPUT ct state != new,related counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT +nft add rule ip filter INPUT ct original protocol 17 counter accept + +iptables-translate -t filter -A INPUT -m conntrack ! --ctproto UDP -j ACCEPT +nft add rule ip filter INPUT ct original protocol != 17 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.2.131 -j ACCEPT +nft add rule ip filter INPUT ct original saddr 10.100.2.131 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctorigsrc 10.100.0.0/255.255.0.0 -j ACCEPT +nft add rule ip filter INPUT ct original saddr 10.100.0.0/16 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctorigdst 10.100.2.131 -j ACCEPT +nft add rule ip filter INPUT ct original daddr 10.100.2.131 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctreplsrc 10.100.2.131 -j ACCEPT +nft add rule ip filter INPUT ct reply saddr 10.100.2.131 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctrepldst 10.100.2.131 -j ACCEPT +nft add rule ip filter INPUT ct reply daddr 10.100.2.131 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctproto tcp --ctorigsrcport 443:444 -j ACCEPT +nft add rule ip filter INPUT ct original protocol 6 ct original proto-src 443-444 counter accept + +iptables-translate -t filter -A INPUT -m conntrack ! --ctstatus CONFIRMED -j ACCEPT +nft add rule ip filter INPUT ct status != confirmed counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctexpire 3 -j ACCEPT +nft add rule ip filter INPUT ct expiration 3 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctdir ORIGINAL -j ACCEPT +nft add rule ip filter INPUT ct direction original counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT +nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept diff --git a/extensions/libxt_cpu.txlate b/extensions/libxt_cpu.txlate new file mode 100644 index 00000000..c59b0e02 --- /dev/null +++ b/extensions/libxt_cpu.txlate @@ -0,0 +1,5 @@ +iptables-translate -A INPUT -p tcp --dport 80 -m cpu --cpu 0 -j ACCEPT +nft add rule ip filter INPUT tcp dport 80 cpu 0 counter accept + +iptables-translate -A INPUT -p tcp --dport 80 -m cpu ! --cpu 1 -j ACCEPT +nft add rule ip filter INPUT tcp dport 80 cpu != 1 counter accept diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate new file mode 100644 index 00000000..b47dc65f --- /dev/null +++ b/extensions/libxt_dccp.txlate @@ -0,0 +1,14 @@ +iptables-translate -A INPUT -p dccp -m dccp --sport 100 +nft add rule ip filter INPUT dccp sport 100 counter + +iptables-translate -A INPUT -p dccp -m dccp --dport 100:200 +nft add rule ip filter INPUT dccp dport 100-200 counter + +iptables-translate -A INPUT -p dccp -m dccp ! --dport 100 +nft add rule ip filter INPUT dccp dport != 100 counter + +iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK +nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack} counter + +iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100 +nft add rule ip filter INPUT dccp sport 200 dport 100 counter diff --git a/extensions/libxt_devgroup.txlate b/extensions/libxt_devgroup.txlate new file mode 100644 index 00000000..aeb597bd --- /dev/null +++ b/extensions/libxt_devgroup.txlate @@ -0,0 +1,17 @@ +iptables-translate -A FORWARD -m devgroup --src-group 0x2 -j ACCEPT +nft add rule ip filter FORWARD iifgroup 0x2 counter accept + +iptables-translate -A FORWARD -m devgroup --dst-group 0xc/0xc -j ACCEPT +nft add rule ip filter FORWARD oifgroup and 0xc == 0xc counter accept + +iptables-translate -t mangle -A PREROUTING -p tcp --dport 46000 -m devgroup --src-group 23 -j ACCEPT +nft add rule ip mangle PREROUTING tcp dport 46000 iifgroup 0x17 counter accept + +iptables-translate -A FORWARD -m devgroup ! --dst-group 0xc/0xc -j ACCEPT +nft add rule ip filter FORWARD oifgroup and 0xc != 0xc counter accept + +iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 -j ACCEPT +nft add rule ip filter FORWARD iifgroup != 0x2 counter accept + +iptables-translate -A FORWARD -m devgroup ! --src-group 0x2 --dst-group 0xc/0xc -j ACCEPT +nft add rule ip filter FORWARD iifgroup != 0x2 oifgroup and 0xc != 0xc counter accept diff --git a/extensions/libxt_dscp.txlate b/extensions/libxt_dscp.txlate new file mode 100644 index 00000000..2cccc3b4 --- /dev/null +++ b/extensions/libxt_dscp.txlate @@ -0,0 +1,5 @@ +iptables-translate -t filter -A INPUT -m dscp --dscp 0x32 -j ACCEPT +nft add rule ip filter INPUT ip dscp 0x32 counter accept + +ip6tables-translate -t filter -A INPUT -m dscp ! --dscp 0x32 -j ACCEPT +nft add rule ip6 filter INPUT ip6 dscp != 0x32 counter accept diff --git a/extensions/libxt_ecn.txlate b/extensions/libxt_ecn.txlate new file mode 100644 index 00000000..9e3bd310 --- /dev/null +++ b/extensions/libxt_ecn.txlate @@ -0,0 +1,23 @@ +iptables-translate -A INPUT -m ecn --ecn-ip-ect 0 +nft add rule ip filter INPUT ip ecn not-ect counter + +iptables-translate -A INPUT -m ecn --ecn-ip-ect 1 +nft add rule ip filter INPUT ip ecn ect1 counter + +iptables-translate -A INPUT -m ecn --ecn-ip-ect 2 +nft add rule ip filter INPUT ip ecn ect0 counter + +iptables-translate -A INPUT -m ecn --ecn-ip-ect 3 +nft add rule ip filter INPUT ip ecn ce counter + +iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 0 +nft add rule ip filter INPUT ip ecn != not-ect counter + +iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 1 +nft add rule ip filter INPUT ip ecn != ect1 counter + +iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 2 +nft add rule ip filter INPUT ip ecn != ect0 counter + +iptables-translate -A INPUT -m ecn ! --ecn-ip-ect 3 +nft add rule ip filter INPUT ip ecn != ce counter diff --git a/extensions/libxt_esp.txlate b/extensions/libxt_esp.txlate new file mode 100644 index 00000000..a67c6f0e --- /dev/null +++ b/extensions/libxt_esp.txlate @@ -0,0 +1,11 @@ +iptables-translate -A FORWARD -p esp -j ACCEPT +nft add rule ip filter FORWARD ip protocol esp counter accept + +iptables-translate -A INPUT --in-interface wan --protocol esp -j ACCEPT +nft add rule ip filter INPUT iifname wan ip protocol esp counter accept + +iptables-translate -A INPUT -p 50 -m esp --espspi 500 -j DROP +nft add rule ip filter INPUT esp spi 500 counter drop + +iptables-translate -A INPUT -p 50 -m esp --espspi 500:600 -j DROP +nft add rule ip filter INPUT esp spi 500-600 counter drop diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c index 7a1b37a9..70bc615b 100644 --- a/extensions/libxt_hashlimit.c +++ b/extensions/libxt_hashlimit.c @@ -7,14 +7,15 @@ * Based on ipt_limit.c by * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> * Hervé Eychenne <rv@wallfire.org> - * + * * Error corections by nmalykh@bilim.com (22.01.2005) */ #define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 #define _ISOC99_SOURCE 1 +#include <inttypes.h> #include <math.h> #include <stdbool.h> -#include <stdint.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -68,10 +69,13 @@ enum { O_HTABLE_MAX, O_HTABLE_GCINT, O_HTABLE_EXPIRE, + O_RATEMATCH, + O_INTERVAL, F_BURST = 1 << O_BURST, F_UPTO = 1 << O_UPTO, F_ABOVE = 1 << O_ABOVE, F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE, + F_RATEMATCH = 1 << O_RATEMATCH, }; static void hashlimit_mt_help(void) @@ -95,6 +99,29 @@ static void hashlimit_mt_help(void) "\n", XT_HASHLIMIT_BURST); } +static void hashlimit_mt_help_v3(void) +{ + printf( +"hashlimit match options:\n" +" --hashlimit-upto <avg> max average match rate\n" +" [Packets per second unless followed by \n" +" /sec /minute /hour /day postfixes]\n" +" --hashlimit-above <avg> min average match rate\n" +" --hashlimit-mode <mode> mode is a comma-separated list of\n" +" dstip,srcip,dstport,srcport (or none)\n" +" --hashlimit-srcmask <length> source address grouping prefix length\n" +" --hashlimit-dstmask <length> destination address grouping prefix length\n" +" --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n" +" --hashlimit-burst <num> number to match in a burst, default %u\n" +" --hashlimit-htable-size <num> number of hashtable buckets\n" +" --hashlimit-htable-max <num> number of hashtable entries\n" +" --hashlimit-htable-gcinterval interval between garbage collection runs\n" +" --hashlimit-htable-expire after which time are idle entries expired?\n" +" --hashlimit-rate-match rate match the flow without rate-limiting it\n" +" --hashlimit-rate-interval interval in seconds for hashlimit-rate-match\n" +"\n", XT_HASHLIMIT_BURST); +} + #define s struct xt_hashlimit_info static const struct xt_option_entry hashlimit_opts[] = { {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, @@ -153,6 +180,35 @@ static const struct xt_option_entry hashlimit_mt_opts_v1[] = { #undef s #define s struct xt_hashlimit_mtinfo2 +static const struct xt_option_entry hashlimit_mt_opts_v2[] = { + {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, + {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, + {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */ + {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN}, + {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN}, + {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING}, + {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.size)}, + {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.max)}, + {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.gc_interval)}, + {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.expire)}, + {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING}, + {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, +}; +#undef s + +#define s struct xt_hashlimit_mtinfo3 static const struct xt_option_entry hashlimit_mt_opts[] = { {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE, .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, @@ -178,12 +234,14 @@ static const struct xt_option_entry hashlimit_mt_opts[] = { {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING}, {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, + {.name = "hashlimit-rate-match", .id = O_RATEMATCH, .type = XTTYPE_NONE}, + {.name = "hashlimit-rate-interval", .id = O_INTERVAL, .type = XTTYPE_STRING}, XTOPT_TABLEEND, }; #undef s static int -cfg_copy(struct hashlimit_cfg2 *to, const void *from, int revision) +cfg_copy(struct hashlimit_cfg3 *to, const void *from, int revision) { if (revision == 1) { struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from; @@ -198,7 +256,19 @@ cfg_copy(struct hashlimit_cfg2 *to, const void *from, int revision) to->srcmask = cfg->srcmask; to->dstmask = cfg->dstmask; } else if (revision == 2) { - memcpy(to, from, sizeof(struct hashlimit_cfg2)); + struct hashlimit_cfg2 *cfg = (struct hashlimit_cfg2 *)from; + + to->mode = cfg->mode; + to->avg = cfg->avg; + to->burst = cfg->burst; + to->size = cfg->size; + to->max = cfg->max; + to->gc_interval = cfg->gc_interval; + to->expire = cfg->expire; + to->srcmask = cfg->srcmask; + to->dstmask = cfg->dstmask; + } else if (revision == 3) { + memcpy(to, from, sizeof(struct hashlimit_cfg3)); } else { return -EINVAL; } @@ -262,7 +332,7 @@ static uint64_t parse_burst(const char *burst, int revision) if (v > max) xtables_error(PARAMETER_PROBLEM, "bad value for option " "\"--hashlimit-burst\", value \"%s\" too large " - "(max %lumb).", burst, max/1024/1024); + "(max %"PRIu64"mb).", burst, max/1024/1024); return v; } @@ -285,8 +355,8 @@ static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata * tmp = (uint64_t) r * factor; if (tmp > max) xtables_error(PARAMETER_PROBLEM, - "Rate value too large \"%llu\" (max %lu)\n", - (unsigned long long)tmp, max); + "Rate value too large \"%"PRIu64"\" (max %"PRIu64")\n", + tmp, max); tmp = bytes_to_cost(tmp); if (tmp == 0) @@ -346,6 +416,16 @@ int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int r return 1; } +static int parse_interval(const char *rate, uint32_t *val) +{ + int r = atoi(rate); + if (r <= 0) + return 0; + + *val = r; + return 1; +} + static void hashlimit_init(struct xt_entry_match *m) { struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data; @@ -377,7 +457,7 @@ static void hashlimit_mt6_init_v1(struct xt_entry_match *match) info->cfg.dstmask = 128; } -static void hashlimit_mt4_init(struct xt_entry_match *match) +static void hashlimit_mt4_init_v2(struct xt_entry_match *match) { struct xt_hashlimit_mtinfo2 *info = (void *)match->data; @@ -388,7 +468,7 @@ static void hashlimit_mt4_init(struct xt_entry_match *match) info->cfg.dstmask = 32; } -static void hashlimit_mt6_init(struct xt_entry_match *match) +static void hashlimit_mt6_init_v2(struct xt_entry_match *match) { struct xt_hashlimit_mtinfo2 *info = (void *)match->data; @@ -399,6 +479,30 @@ static void hashlimit_mt6_init(struct xt_entry_match *match) info->cfg.dstmask = 128; } +static void hashlimit_mt4_init(struct xt_entry_match *match) +{ + struct xt_hashlimit_mtinfo3 *info = (void *)match->data; + + info->cfg.mode = 0; + info->cfg.burst = XT_HASHLIMIT_BURST; + info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; + info->cfg.srcmask = 32; + info->cfg.dstmask = 32; + info->cfg.interval = 0; +} + +static void hashlimit_mt6_init(struct xt_entry_match *match) +{ + struct xt_hashlimit_mtinfo3 *info = (void *)match->data; + + info->cfg.mode = 0; + info->cfg.burst = XT_HASHLIMIT_BURST; + info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; + info->cfg.srcmask = 128; + info->cfg.dstmask = 128; + info->cfg.interval = 0; +} + /* Parse a 'mode' parameter into the required bitmask */ static int parse_mode(uint32_t *mode, const char *option_arg) { @@ -488,7 +592,7 @@ static void hashlimit_mt_parse_v1(struct xt_option_call *cb) } } -static void hashlimit_mt_parse(struct xt_option_call *cb) +static void hashlimit_mt_parse_v2(struct xt_option_call *cb) { struct xt_hashlimit_mtinfo2 *info = cb->data; @@ -529,6 +633,54 @@ static void hashlimit_mt_parse(struct xt_option_call *cb) } } +static void hashlimit_mt_parse(struct xt_option_call *cb) +{ + struct xt_hashlimit_mtinfo3 *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_BURST: + info->cfg.burst = parse_burst(cb->arg, 2); + break; + case O_UPTO: + if (cb->invert) + info->cfg.mode |= XT_HASHLIMIT_INVERT; + if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2)) + info->cfg.mode |= XT_HASHLIMIT_BYTES; + else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2)) + xtables_param_act(XTF_BAD_VALUE, "hashlimit", + "--hashlimit-upto", cb->arg); + break; + case O_ABOVE: + if (!cb->invert) + info->cfg.mode |= XT_HASHLIMIT_INVERT; + if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2)) + info->cfg.mode |= XT_HASHLIMIT_BYTES; + else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2)) + xtables_param_act(XTF_BAD_VALUE, "hashlimit", + "--hashlimit-above", cb->arg); + break; + case O_MODE: + if (parse_mode(&info->cfg.mode, cb->arg) < 0) + xtables_param_act(XTF_BAD_VALUE, "hashlimit", + "--hashlimit-mode", cb->arg); + break; + case O_SRCMASK: + info->cfg.srcmask = cb->val.hlen; + break; + case O_DSTMASK: + info->cfg.dstmask = cb->val.hlen; + break; + case O_RATEMATCH: + info->cfg.mode |= XT_HASHLIMIT_RATE_MATCH; + break; + case O_INTERVAL: + if (!parse_interval(cb->arg, &info->cfg.interval)) + xtables_param_act(XTF_BAD_VALUE, "hashlimit", + "--hashlimit-rate-interval", cb->arg); + } +} + static void hashlimit_check(struct xt_fcheck_call *cb) { const struct hashlimit_mt_udata *udata = cb->udata; @@ -557,7 +709,8 @@ static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb) if (cb->xflags & F_BURST) { if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) xtables_error(PARAMETER_PROBLEM, - "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg)); + "burst cannot be smaller than %"PRIu64"b", + cost_to_bytes(info->cfg.avg)); burst = info->cfg.burst; burst /= cost_to_bytes(info->cfg.avg); @@ -571,7 +724,7 @@ static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb) burst_error_v1(); } -static void hashlimit_mt_check(struct xt_fcheck_call *cb) +static void hashlimit_mt_check_v2(struct xt_fcheck_call *cb) { const struct hashlimit_mt_udata *udata = cb->udata; struct xt_hashlimit_mtinfo2 *info = cb->data; @@ -587,6 +740,37 @@ static void hashlimit_mt_check(struct xt_fcheck_call *cb) if (cb->xflags & F_BURST) { if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) xtables_error(PARAMETER_PROBLEM, + "burst cannot be smaller than %"PRIu64"b", + cost_to_bytes(info->cfg.avg)); + + burst = info->cfg.burst; + burst /= cost_to_bytes(info->cfg.avg); + if (info->cfg.burst % cost_to_bytes(info->cfg.avg)) + burst++; + if (!(cb->xflags & F_HTABLE_EXPIRE)) + info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; + } + info->cfg.burst = burst; + } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX) + burst_error(); +} + +static void hashlimit_mt_check(struct xt_fcheck_call *cb) +{ + const struct hashlimit_mt_udata *udata = cb->udata; + struct xt_hashlimit_mtinfo3 *info = cb->data; + + if (!(cb->xflags & (F_UPTO | F_ABOVE))) + xtables_error(PARAMETER_PROBLEM, + "You have to specify --hashlimit"); + if (!(cb->xflags & F_HTABLE_EXPIRE)) + info->cfg.expire = udata->mult * 1000; /* from s to msec */ + + if (info->cfg.mode & XT_HASHLIMIT_BYTES) { + uint32_t burst = 0; + if (cb->xflags & F_BURST) { + if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) + xtables_error(PARAMETER_PROBLEM, "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg)); burst = info->cfg.burst; @@ -599,6 +783,18 @@ static void hashlimit_mt_check(struct xt_fcheck_call *cb) info->cfg.burst = burst; } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX) burst_error(); + + if (cb->xflags & F_RATEMATCH) { + if (!(info->cfg.mode & XT_HASHLIMIT_BYTES)) + info->cfg.avg /= udata->mult; + + if (info->cfg.interval == 0) { + if (info->cfg.mode & XT_HASHLIMIT_BYTES) + info->cfg.interval = 1; + else + info->cfg.interval = udata->mult; + } + } } struct rates { @@ -615,7 +811,7 @@ static const struct rates rates[] = { { "min", XT_HASHLIMIT_SCALE_v2*60 }, { "sec", XT_HASHLIMIT_SCALE_v2 } }; -static uint32_t print_rate(uint32_t period, int revision) +static uint32_t print_rate(uint64_t period, int revision) { unsigned int i; const struct rates *_rates = (revision == 1) ? rates_v1 : rates; @@ -631,7 +827,7 @@ static uint32_t print_rate(uint32_t period, int revision) || _rates[i].mult/period < _rates[i].mult%period) break; - printf(" %lu/%s", _rates[i-1].mult / period, _rates[i-1].name); + printf(" %"PRIu64"/%s", _rates[i-1].mult / period, _rates[i-1].name); /* return in msec */ return _rates[i-1].mult / scale * 1000; } @@ -721,9 +917,10 @@ static void hashlimit_print(const void *ip, } static void -hashlimit_mt_print(const struct hashlimit_cfg2 *cfg, unsigned int dmask, int revision) +hashlimit_mt_print(const struct hashlimit_cfg3 *cfg, unsigned int dmask, int revision) { - uint32_t quantum; + uint64_t quantum; + uint64_t period; if (cfg->mode & XT_HASHLIMIT_INVERT) fputs(" limit: above", stdout); @@ -733,7 +930,15 @@ hashlimit_mt_print(const struct hashlimit_cfg2 *cfg, unsigned int dmask, int rev if (cfg->mode & XT_HASHLIMIT_BYTES) { quantum = print_bytes(cfg->avg, cfg->burst, ""); } else { - quantum = print_rate(cfg->avg, revision); + if (revision == 3) { + period = cfg->avg; + if (cfg->interval != 0) + period *= cfg->interval; + + quantum = print_rate(period, revision); + } else { + quantum = print_rate(cfg->avg, revision); + } printf(" burst %llu", cfg->burst); } if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | @@ -754,6 +959,13 @@ hashlimit_mt_print(const struct hashlimit_cfg2 *cfg, unsigned int dmask, int rev printf(" srcmask %u", cfg->srcmask); if (cfg->dstmask != dmask) printf(" dstmask %u", cfg->dstmask); + + if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH)) + printf(" rate-match"); + + if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH)) + if (cfg->interval != 1) + printf(" rate-interval %u", cfg->interval); } static void @@ -761,7 +973,7 @@ hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; - struct hashlimit_cfg2 cfg; + struct hashlimit_cfg3 cfg; int ret; ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); @@ -777,7 +989,7 @@ hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; - struct hashlimit_cfg2 cfg; + struct hashlimit_cfg3 cfg; int ret; ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); @@ -789,21 +1001,52 @@ hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match, } static void -hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, +hashlimit_mt4_print_v2(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + struct hashlimit_cfg3 cfg; + int ret; + + ret = cfg_copy(&cfg, (const void *)&info->cfg, 2); + + if (ret) + xtables_error(OTHER_PROBLEM, "unknown revision"); - hashlimit_mt_print(&info->cfg, 32, 2); + hashlimit_mt_print(&cfg, 32, 2); } static void -hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, +hashlimit_mt6_print_v2(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + struct hashlimit_cfg3 cfg; + int ret; + + ret = cfg_copy(&cfg, (const void *)&info->cfg, 2); + + if (ret) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + hashlimit_mt_print(&cfg, 128, 2); +} +static void +hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data; + + hashlimit_mt_print(&info->cfg, 32, 3); +} + +static void +hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data; - hashlimit_mt_print(&info->cfg, 128, 2); + hashlimit_mt_print(&info->cfg, 128, 3); } static void hashlimit_save(const void *ip, const struct xt_entry_match *match) @@ -831,7 +1074,7 @@ static void hashlimit_save(const void *ip, const struct xt_entry_match *match) } static void -hashlimit_mt_save(const struct hashlimit_cfg2 *cfg, const char* name, unsigned int dmask, int revision) +hashlimit_mt_save(const struct hashlimit_cfg3 *cfg, const char* name, unsigned int dmask, int revision) { uint32_t quantum; @@ -868,13 +1111,20 @@ hashlimit_mt_save(const struct hashlimit_cfg2 *cfg, const char* name, unsigned i printf(" --hashlimit-srcmask %u", cfg->srcmask); if (cfg->dstmask != dmask) printf(" --hashlimit-dstmask %u", cfg->dstmask); + + if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH)) + printf(" --hashlimit-rate-match"); + + if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH)) + if (cfg->interval != 1) + printf(" --hashlimit-rate-interval %u", cfg->interval); } static void hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match) { const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; - struct hashlimit_cfg2 cfg; + struct hashlimit_cfg3 cfg; int ret; ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); @@ -889,7 +1139,7 @@ static void hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match) { const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; - struct hashlimit_cfg2 cfg; + struct hashlimit_cfg3 cfg; int ret; ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); @@ -901,19 +1151,300 @@ hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match) } static void -hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match) +hashlimit_mt4_save_v2(const void *ip, const struct xt_entry_match *match) { const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + struct hashlimit_cfg3 cfg; + int ret; + + ret = cfg_copy(&cfg, (const void *)&info->cfg, 2); - hashlimit_mt_save(&info->cfg, info->name, 32, 2); + if (ret) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + hashlimit_mt_save(&cfg, info->name, 32, 2); } static void -hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match) +hashlimit_mt6_save_v2(const void *ip, const struct xt_entry_match *match) { const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; + struct hashlimit_cfg3 cfg; + int ret; + + ret = cfg_copy(&cfg, (const void *)&info->cfg, 2); + + if (ret) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + hashlimit_mt_save(&cfg, info->name, 128, 2); +} + +static void +hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data; + + hashlimit_mt_save(&info->cfg, info->name, 32, 3); +} + +static void +hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data; + + hashlimit_mt_save(&info->cfg, info->name, 128, 3); +} + +static const struct rates rates_v1_xlate[] = { + { "day", XT_HASHLIMIT_SCALE * 24 * 60 * 60 }, + { "hour", XT_HASHLIMIT_SCALE * 60 * 60 }, + { "minute", XT_HASHLIMIT_SCALE * 60 }, + { "second", XT_HASHLIMIT_SCALE } }; + +static const struct rates rates_xlate[] = { + { "day", XT_HASHLIMIT_SCALE_v2 * 24 * 60 * 60 }, + { "hour", XT_HASHLIMIT_SCALE_v2 * 60 * 60 }, + { "minute", XT_HASHLIMIT_SCALE_v2 * 60 }, + { "second", XT_HASHLIMIT_SCALE_v2 } }; + +static void print_packets_rate_xlate(struct xt_xlate *xl, uint64_t avg, + int revision) +{ + unsigned int i; + const struct rates *_rates = (revision == 1) ? + rates_v1_xlate : rates_xlate; + + for (i = 1; i < ARRAY_SIZE(rates); ++i) + if (avg > _rates[i].mult || + _rates[i].mult / avg < _rates[i].mult % avg) + break; + + xt_xlate_add(xl, " %llu/%s ", + _rates[i-1].mult / avg, _rates[i-1].name); +} + +static void print_bytes_rate_xlate(struct xt_xlate *xl, + const struct hashlimit_cfg3 *cfg) +{ + unsigned int i; + unsigned long long r; + + r = cost_to_bytes(cfg->avg); + + for (i = 0; i < ARRAY_SIZE(units) -1; ++i) + if (r >= units[i].thresh && + bytes_to_cost(r & ~(units[i].thresh - 1)) == cfg->avg) + break; + + xt_xlate_add(xl, " %llu %sbytes/second", r / units[i].thresh, + units[i].name); + + r *= cfg->burst; + for (i = 0; i < ARRAY_SIZE(units) -1; ++i) + if (r >= units[i].thresh) + break; + + if (cfg->burst > 0) + xt_xlate_add(xl, " burst %llu %sbytes", r / units[i].thresh, + units[i].name); +} + +static void hashlimit_print_subnet_xlate(struct xt_xlate *xl, + uint32_t nsub, int family) +{ + char sep = (family == NFPROTO_IPV4) ? '.' : ':'; + char *fmt = (family == NFPROTO_IPV4) ? "%u" : "%04x"; + unsigned int nblocks = (family == NFPROTO_IPV4) ? 4 : 8; + unsigned int nbits = (family == NFPROTO_IPV4) ? 8 : 16; + unsigned int acm, i; + + xt_xlate_add(xl, " and "); + while (nblocks--) { + acm = 0; + + for (i = 0; i < nbits; i++) { + acm <<= 1; + + if (nsub > 0) { + acm++; + nsub--; + } + } + + xt_xlate_add(xl, fmt, acm); + if (nblocks > 0) + xt_xlate_add(xl, "%c", sep); + } +} + +static const char *const hashlimit_modes4_xlate[] = { + [XT_HASHLIMIT_HASH_DIP] = "ip daddr", + [XT_HASHLIMIT_HASH_DPT] = "tcp dport", + [XT_HASHLIMIT_HASH_SIP] = "ip saddr", + [XT_HASHLIMIT_HASH_SPT] = "tcp sport", +}; + +static const char *const hashlimit_modes6_xlate[] = { + [XT_HASHLIMIT_HASH_DIP] = "ip6 daddr", + [XT_HASHLIMIT_HASH_DPT] = "tcp dport", + [XT_HASHLIMIT_HASH_SIP] = "ip6 saddr", + [XT_HASHLIMIT_HASH_SPT] = "tcp sport", +}; + +static int hashlimit_mode_xlate(struct xt_xlate *xl, + uint32_t mode, int family, + unsigned int nsrc, unsigned int ndst) +{ + const char * const *_modes = (family == NFPROTO_IPV4) ? + hashlimit_modes4_xlate : hashlimit_modes6_xlate; + bool prevopt = false; + unsigned int mask; + + mode &= ~XT_HASHLIMIT_INVERT & ~XT_HASHLIMIT_BYTES; + + for (mask = 1; mode > 0; mask <<= 1) { + if (!(mode & mask)) + continue; + + if (!prevopt) { + xt_xlate_add(xl, " "); + prevopt = true; + } + else { + xt_xlate_add(xl, " . "); + } + + xt_xlate_add(xl, "%s", _modes[mask]); + + if (mask == XT_HASHLIMIT_HASH_DIP && + ((family == NFPROTO_IPV4 && ndst != 32) || + (family == NFPROTO_IPV6 && ndst != 128))) + hashlimit_print_subnet_xlate(xl, ndst, family); + else if (mask == XT_HASHLIMIT_HASH_SIP && + ((family == NFPROTO_IPV4 && nsrc != 32) || + (family == NFPROTO_IPV6 && nsrc != 128))) + hashlimit_print_subnet_xlate(xl, nsrc, family); + + mode &= ~mask; + } + + return prevopt; +} + +static int hashlimit_mt_xlate(struct xt_xlate *xl, const char *name, + const struct hashlimit_cfg3 *cfg, + int revision, int family) +{ + int ret = 1; + + xt_xlate_add(xl, "meter %s {", name); + ret = hashlimit_mode_xlate(xl, cfg->mode, family, + cfg->srcmask, cfg->dstmask); + if (cfg->expire != 1000) + xt_xlate_add(xl, " timeout %us", cfg->expire / 1000); + xt_xlate_add(xl, " limit rate"); + + if (cfg->mode & XT_HASHLIMIT_INVERT) + xt_xlate_add(xl, " over"); + + if (cfg->mode & XT_HASHLIMIT_BYTES) + print_bytes_rate_xlate(xl, cfg); + else { + print_packets_rate_xlate(xl, cfg->avg, revision); + if (cfg->burst != XT_HASHLIMIT_BURST) + xt_xlate_add(xl, "burst %lu packets", cfg->burst); + + } + xt_xlate_add(xl, "}"); + + return ret; +} + +static int hashlimit_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_info *info = (const void *)params->match->data; + int ret = 1; + + xt_xlate_add(xl, "meter %s {", info->name); + ret = hashlimit_mode_xlate(xl, info->cfg.mode, NFPROTO_IPV4, 32, 32); + xt_xlate_add(xl, " timeout %us limit rate", info->cfg.expire / 1000); + print_packets_rate_xlate(xl, info->cfg.avg, 1); + xt_xlate_add(xl, " burst %lu packets", info->cfg.burst); + xt_xlate_add(xl, "}"); + + return ret; +} + +static int hashlimit_mt4_xlate_v1(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_mtinfo1 *info = + (const void *)params->match->data; + struct hashlimit_cfg3 cfg; + + if (cfg_copy(&cfg, (const void *)&info->cfg, 1)) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV4); +} + +static int hashlimit_mt6_xlate_v1(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_mtinfo1 *info = + (const void *)params->match->data; + struct hashlimit_cfg3 cfg; - hashlimit_mt_save(&info->cfg, info->name, 128, 2); + if (cfg_copy(&cfg, (const void *)&info->cfg, 1)) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV6); +} + +static int hashlimit_mt4_xlate_v2(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_mtinfo2 *info = + (const void *)params->match->data; + struct hashlimit_cfg3 cfg; + + if (cfg_copy(&cfg, (const void *)&info->cfg, 2)) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV4); +} + +static int hashlimit_mt6_xlate_v2(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_mtinfo2 *info = + (const void *)params->match->data; + struct hashlimit_cfg3 cfg; + + if (cfg_copy(&cfg, (const void *)&info->cfg, 2)) + xtables_error(OTHER_PROBLEM, "unknown revision"); + + return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV6); +} + +static int hashlimit_mt4_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_mtinfo3 *info = + (const void *)params->match->data; + + return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV4); +} + +static int hashlimit_mt6_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + const struct xt_hashlimit_mtinfo3 *info = + (const void *)params->match->data; + + return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV6); } static struct xtables_match hashlimit_mt_reg[] = { @@ -932,6 +1463,7 @@ static struct xtables_match hashlimit_mt_reg[] = { .save = hashlimit_save, .x6_options = hashlimit_opts, .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_xlate, }, { .version = XTABLES_VERSION, @@ -948,6 +1480,7 @@ static struct xtables_match hashlimit_mt_reg[] = { .save = hashlimit_mt4_save_v1, .x6_options = hashlimit_mt_opts_v1, .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_mt4_xlate_v1, }, { .version = XTABLES_VERSION, @@ -964,6 +1497,7 @@ static struct xtables_match hashlimit_mt_reg[] = { .save = hashlimit_mt6_save_v1, .x6_options = hashlimit_mt_opts_v1, .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_mt6_xlate_v1, }, { .version = XTABLES_VERSION, @@ -973,6 +1507,40 @@ static struct xtables_match hashlimit_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), .help = hashlimit_mt_help, + .init = hashlimit_mt4_init_v2, + .x6_parse = hashlimit_mt_parse_v2, + .x6_fcheck = hashlimit_mt_check_v2, + .print = hashlimit_mt4_print_v2, + .save = hashlimit_mt4_save_v2, + .x6_options = hashlimit_mt_opts_v2, + .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_mt4_xlate_v2, + }, + { + .version = XTABLES_VERSION, + .name = "hashlimit", + .revision = 2, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), + .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), + .help = hashlimit_mt_help, + .init = hashlimit_mt6_init_v2, + .x6_parse = hashlimit_mt_parse_v2, + .x6_fcheck = hashlimit_mt_check_v2, + .print = hashlimit_mt6_print_v2, + .save = hashlimit_mt6_save_v2, + .x6_options = hashlimit_mt_opts_v2, + .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_mt6_xlate_v2, + }, + { + .version = XTABLES_VERSION, + .name = "hashlimit", + .revision = 3, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)), + .userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo), + .help = hashlimit_mt_help_v3, .init = hashlimit_mt4_init, .x6_parse = hashlimit_mt_parse, .x6_fcheck = hashlimit_mt_check, @@ -980,15 +1548,16 @@ static struct xtables_match hashlimit_mt_reg[] = { .save = hashlimit_mt4_save, .x6_options = hashlimit_mt_opts, .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_mt4_xlate, }, { .version = XTABLES_VERSION, .name = "hashlimit", - .revision = 2, + .revision = 3, .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), - .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), - .help = hashlimit_mt_help, + .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)), + .userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo), + .help = hashlimit_mt_help_v3, .init = hashlimit_mt6_init, .x6_parse = hashlimit_mt_parse, .x6_fcheck = hashlimit_mt_check, @@ -996,6 +1565,7 @@ static struct xtables_match hashlimit_mt_reg[] = { .save = hashlimit_mt6_save, .x6_options = hashlimit_mt_opts, .udata_size = sizeof(struct hashlimit_mt_udata), + .xlate = hashlimit_mt6_xlate, }, }; diff --git a/extensions/libxt_hashlimit.man b/extensions/libxt_hashlimit.man index 6aac3f28..5dbb3273 100644 --- a/extensions/libxt_hashlimit.man +++ b/extensions/libxt_hashlimit.man @@ -51,6 +51,14 @@ After how many milliseconds do hash entries expire. .TP \fB\-\-hashlimit\-htable\-gcinterval\fP \fImsec\fP How many milliseconds between garbage collection intervals. +.TP +\fB\-\-hashlimit\-rate\-match\fP +Classify the flow instead of rate-limiting it. This acts like a +true/flase match on whether the rate is above/below a certain number +.TP +\fB\-\-hashlimit\-rate\-interval\fP \fIsec\fP +Can be used with \-\-hashlimit\-rate\-match to specify the interval +at which the rate should be sampled .PP Examples: .TP diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t index d27c8616..ccd0d1e6 100644 --- a/extensions/libxt_hashlimit.t +++ b/extensions/libxt_hashlimit.t @@ -26,3 +26,8 @@ -m hashlimit --hashlimit-name mini1;;FAIL -m hashlimit --hashlimit-upto 1/sec;;FAIL -m hashlimit;;FAIL +-m hashlimit --hashlimit-upto 40/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name syn-flood;=;OK +-m hashlimit --hashlimit-upto 40/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name rate1 --hashlimit-rate-match;=;OK +-m hashlimit --hashlimit-upto 40mb/s --hashlimit-mode srcip --hashlimit-name rate2 --hashlimit-rate-match;=;OK +-m hashlimit --hashlimit-upto 40/sec --hashlimit-burst 20 --hashlimit-mode srcip --hashlimit-name rate3 --hashlimit-rate-match --hashlimit-rate-interval 10;=;OK +-m hashlimit --hashlimit-upto 40mb/s --hashlimit-mode srcip --hashlimit-name rate4 --hashlimit-rate-match --hashlimit-rate-interval 10;=;OK diff --git a/extensions/libxt_hashlimit.txlate b/extensions/libxt_hashlimit.txlate new file mode 100644 index 00000000..6c8d07f1 --- /dev/null +++ b/extensions/libxt_hashlimit.txlate @@ -0,0 +1,5 @@ +iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-above 20kb/s --hashlimit-burst 1mb --hashlimit-mode dstip --hashlimit-name https --hashlimit-dstmask 24 -m state --state NEW -j DROP +nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr and 255.255.255.0 timeout 60s limit rate over 20 kbytes/second burst 1 mbytes} ct state new counter drop + +iptables-translate -A OUTPUT -m tcp -p tcp --dport 443 -m hashlimit --hashlimit-upto 300 --hashlimit-burst 15 --hashlimit-mode srcip,dstip --hashlimit-name https --hashlimit-htable-expire 300000 -m state --state NEW -j DROP +nft add rule ip filter OUTPUT tcp dport 443 meter https { ip daddr . ip saddr timeout 300s limit rate 300/second burst 15 packets} ct state new counter drop diff --git a/extensions/libxt_helper.txlate b/extensions/libxt_helper.txlate new file mode 100644 index 00000000..8259aba3 --- /dev/null +++ b/extensions/libxt_helper.txlate @@ -0,0 +1,5 @@ +iptables-translate -A FORWARD -m helper --helper sip +nft add rule ip filter FORWARD ct helper \"sip\" counter + +iptables-translate -A FORWARD -m helper ! --helper ftp +nft add rule ip filter FORWARD ct helper != \"ftp\" counter diff --git a/extensions/libxt_ipcomp.t b/extensions/libxt_ipcomp.t new file mode 100644 index 00000000..ce111142 --- /dev/null +++ b/extensions/libxt_ipcomp.t @@ -0,0 +1,5 @@ +:INPUT,FORWARD +-m policy --dir in --pol ipsec --proto ipcomp;=;OK +-m policy --dir in --pol none --proto ipcomp;;FAIL +-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto ipcomp;=;OK +-m policy --dir in --pol ipsec --strict --reqid 1 --spi 0x1 --proto ipcomp --mode tunnel --tunnel-dst 10.0.0.0/8 --tunnel-src 10.0.0.0/8 --next --reqid 2;=;OK diff --git a/extensions/libxt_ipcomp.txlate b/extensions/libxt_ipcomp.txlate new file mode 100644 index 00000000..f9efe53c --- /dev/null +++ b/extensions/libxt_ipcomp.txlate @@ -0,0 +1,5 @@ +iptables-translate -t filter -A INPUT -m ipcomp --ipcompspi 0x12 -j ACCEPT +nft add rule ip filter INPUT comp cpi 18 counter accept + +iptables-translate -t filter -A INPUT -m ipcomp ! --ipcompspi 0x12 -j ACCEPT +nft add rule ip filter INPUT comp cpi != 18 counter accept diff --git a/extensions/libxt_iprange.txlate b/extensions/libxt_iprange.txlate new file mode 100644 index 00000000..999f4b72 --- /dev/null +++ b/extensions/libxt_iprange.txlate @@ -0,0 +1,14 @@ +iptables-translate -A INPUT -m iprange --src-range 192.168.25.149-192.168.25.151 -j ACCEPT +nft add rule ip filter INPUT ip saddr 192.168.25.149-192.168.25.151 counter accept + +iptables-translate -A INPUT -m iprange --dst-range 192.168.25.149-192.168.25.151 -j ACCEPT +nft add rule ip filter INPUT ip daddr 192.168.25.149-192.168.25.151 counter accept + +iptables-translate -A INPUT -m iprange --dst-range 3.3.3.3-6.6.6.6 --src-range 4.4.4.4-7.7.7.7 -j ACCEPT +nft add rule ip filter INPUT ip saddr 4.4.4.4-7.7.7.7 ip daddr 3.3.3.3-6.6.6.6 counter accept + +ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 -j ACCEPT +nft add rule ip6 filter INPUT ip6 daddr != ::2d01-::2d03 counter accept + +ip6tables-translate -A INPUT -m iprange ! --dst-range ::2d01-::2d03 --src-range ::2d01-::2d03 -j ACCEPT +nft add rule ip6 filter INPUT ip6 saddr ::2d01-::2d03 ip6 daddr != ::2d01-::2d03 counter accept diff --git a/extensions/libxt_length.txlate b/extensions/libxt_length.txlate new file mode 100644 index 00000000..e777c265 --- /dev/null +++ b/extensions/libxt_length.txlate @@ -0,0 +1,11 @@ +iptables-translate -A INPUT -p icmp -m length --length 86:0xffff -j DROP +nft add rule ip filter INPUT ip protocol icmp meta length 86-65535 counter drop + +iptables-translate -A INPUT -p udp -m length --length :400 +nft add rule ip filter INPUT ip protocol udp meta length 0-400 counter + +iptables-translate -A INPUT -p udp -m length --length 40 +nft add rule ip filter INPUT ip protocol udp meta length 40 counter + +iptables-translate -A INPUT -p udp -m length ! --length 40 +nft add rule ip filter INPUT ip protocol udp meta length != 40 counter diff --git a/extensions/libxt_limit.c b/extensions/libxt_limit.c index 5cc95c2e..c8ddca87 100644 --- a/extensions/libxt_limit.c +++ b/extensions/libxt_limit.c @@ -4,6 +4,7 @@ * Hervé Eychenne <rv@wallfire.org> */ #define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 #define _ISOC99_SOURCE 1 #include <math.h> #include <stdio.h> diff --git a/extensions/libxt_limit.txlate b/extensions/libxt_limit.txlate new file mode 100644 index 00000000..df9ed2d5 --- /dev/null +++ b/extensions/libxt_limit.txlate @@ -0,0 +1,8 @@ +iptables-translate -A INPUT -m limit --limit 3/m --limit-burst 3 +nft add rule ip filter INPUT limit rate 3/minute burst 3 packets counter + +iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 5 +nft add rule ip filter INPUT limit rate 10/second burst 5 packets counter + +iptables-translate -A INPUT -m limit --limit 10/s --limit-burst 0 +nft add rule ip filter INPUT limit rate 10/second counter diff --git a/extensions/libxt_mac.txlate b/extensions/libxt_mac.txlate new file mode 100644 index 00000000..08696f3d --- /dev/null +++ b/extensions/libxt_mac.txlate @@ -0,0 +1,5 @@ +iptables-translate -A INPUT -m mac --mac-source 0a:12:3e:4f:b2:c6 -j DROP +nft add rule ip filter INPUT ether saddr 0a:12:3e:4f:b2:c6 counter drop + +iptables-translate -A INPUT -p tcp --dport 80 -m mac --mac-source 0a:12:3e:4f:b2:c6 -j ACCEPT +nft add rule ip filter INPUT tcp dport 80 ether saddr 0a:12:3e:4f:b2:c6 counter accept diff --git a/extensions/libxt_mark.txlate b/extensions/libxt_mark.txlate new file mode 100644 index 00000000..6bfb5243 --- /dev/null +++ b/extensions/libxt_mark.txlate @@ -0,0 +1,5 @@ +iptables-translate -I INPUT -p tcp -m mark ! --mark 0xa/0xa +nft insert rule ip filter INPUT ip protocol tcp mark and 0xa != 0xa counter + +iptables-translate -I INPUT -p tcp -m mark ! --mark 0x1 +nft insert rule ip filter INPUT ip protocol tcp mark != 0x1 counter diff --git a/extensions/libxt_multiport.txlate b/extensions/libxt_multiport.txlate new file mode 100644 index 00000000..752e7148 --- /dev/null +++ b/extensions/libxt_multiport.txlate @@ -0,0 +1,11 @@ +iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80,81 -j ACCEPT +nft add rule ip filter INPUT ip protocol tcp tcp dport { 80,81} counter accept + +iptables-translate -t filter -A INPUT -p tcp -m multiport --dports 80:88 -j ACCEPT +nft add rule ip filter INPUT ip protocol tcp tcp dport 80-88 counter accept + +iptables-translate -t filter -A INPUT -p tcp -m multiport ! --dports 80:88 -j ACCEPT +nft add rule ip filter INPUT ip protocol tcp tcp dport != 80-88 counter accept + +iptables-translate -t filter -A INPUT -p tcp -m multiport --sports 50 -j ACCEPT +nft add rule ip filter INPUT ip protocol tcp tcp sport 50 counter accept diff --git a/extensions/libxt_owner.txlate b/extensions/libxt_owner.txlate new file mode 100644 index 00000000..86fb0585 --- /dev/null +++ b/extensions/libxt_owner.txlate @@ -0,0 +1,8 @@ +iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner root -j ACCEPT +nft add rule ip nat OUTPUT tcp dport 80 skuid 0 counter accept + +iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner --gid-owner 0-10 -j ACCEPT +nft add rule ip nat OUTPUT tcp dport 80 skgid 0-10 counter accept + +iptables-translate -t nat -A OUTPUT -p tcp --dport 80 -m owner ! --uid-owner 1000 -j ACCEPT +nft add rule ip nat OUTPUT tcp dport 80 skuid != 1000 counter accept diff --git a/extensions/libxt_pkttype.txlate b/extensions/libxt_pkttype.txlate new file mode 100644 index 00000000..6506a380 --- /dev/null +++ b/extensions/libxt_pkttype.txlate @@ -0,0 +1,8 @@ +iptables-translate -A INPUT -m pkttype --pkt-type broadcast -j DROP +nft add rule ip filter INPUT pkttype broadcast counter drop + +iptables-translate -A INPUT -m pkttype ! --pkt-type unicast -j DROP +nft add rule ip filter INPUT pkttype != unicast counter drop + +iptables-translate -A INPUT -m pkttype --pkt-type multicast -j ACCEPT +nft add rule ip filter INPUT pkttype multicast counter accept diff --git a/extensions/libxt_policy.c b/extensions/libxt_policy.c index 0a64a80c..f9a4819c 100644 --- a/extensions/libxt_policy.c +++ b/extensions/libxt_policy.c @@ -376,6 +376,31 @@ static void policy6_save(const void *ip, const struct xt_entry_match *match) } } +static int policy_xlate(struct xt_xlate *xl, + const struct xt_xlate_mt_params *params) +{ + static const unsigned int allowed = XT_POLICY_MATCH_STRICT | + XT_POLICY_MATCH_NONE | + XT_POLICY_MATCH_IN; + static const struct xt_policy_elem empty; + const struct xt_policy_info *info = (const void *)params->match->data; + + if ((info->flags & ~allowed) || info->len > 1) + return 0; + + if (memcmp(&info->pol[0], &empty, sizeof(empty))) + return 0; + + xt_xlate_add(xl, "meta secpath "); + + if (info->flags & XT_POLICY_MATCH_NONE) + xt_xlate_add(xl, "missing"); + else + xt_xlate_add(xl, "exists"); + + return 1; +} + static struct xtables_match policy_mt_reg[] = { { .name = "policy", @@ -389,6 +414,7 @@ static struct xtables_match policy_mt_reg[] = { .print = policy4_print, .save = policy4_save, .x6_options = policy_opts, + .xlate = policy_xlate, }, { .name = "policy", @@ -402,6 +428,7 @@ static struct xtables_match policy_mt_reg[] = { .print = policy6_print, .save = policy6_save, .x6_options = policy_opts, + .xlate = policy_xlate, }, }; diff --git a/extensions/libxt_policy.txlate b/extensions/libxt_policy.txlate new file mode 100644 index 00000000..66788a76 --- /dev/null +++ b/extensions/libxt_policy.txlate @@ -0,0 +1,5 @@ +iptables-translate -A INPUT -m policy --pol ipsec --dir in +nft add rule ip filter INPUT meta secpath exists counter + +iptables-translate -A INPUT -m policy --pol none --dir in +nft add rule ip filter INPUT meta secpath missing counter diff --git a/extensions/libxt_quota.txlate b/extensions/libxt_quota.txlate new file mode 100644 index 00000000..91142141 --- /dev/null +++ b/extensions/libxt_quota.txlate @@ -0,0 +1,5 @@ +iptables-translate -A OUTPUT -m quota --quota 111 +nft add rule ip filter OUTPUT quota 111 bytes counter + +iptables-translate -A OUTPUT -m quota ! --quota 111 +nft add rule ip filter OUTPUT quota over 111 bytes counter diff --git a/extensions/libxt_recent.c b/extensions/libxt_recent.c index e1801f1c..055ae350 100644 --- a/extensions/libxt_recent.c +++ b/extensions/libxt_recent.c @@ -199,7 +199,7 @@ static void recent_print(const void *ip, const struct xt_entry_match *match, if(info->hit_count) printf(" hit_count: %d", info->hit_count); if (info->check_set & XT_RECENT_TTL) printf(" TTL-Match"); - if(info->name) printf(" name: %s", info->name); + printf(" name: %s", info->name); if (info->side == XT_RECENT_SOURCE) printf(" side: source"); if (info->side == XT_RECENT_DEST) @@ -239,7 +239,7 @@ static void recent_save(const void *ip, const struct xt_entry_match *match, if(info->hit_count) printf(" --hitcount %d", info->hit_count); if (info->check_set & XT_RECENT_TTL) printf(" --rttl"); - if(info->name) printf(" --name %s",info->name); + printf(" --name %s",info->name); switch(family) { case NFPROTO_IPV4: diff --git a/extensions/libxt_rpfilter.txlate b/extensions/libxt_rpfilter.txlate new file mode 100644 index 00000000..8d7733ba --- /dev/null +++ b/extensions/libxt_rpfilter.txlate @@ -0,0 +1,8 @@ +iptables-translate -t mangle -A PREROUTING -m rpfilter +nft add rule ip mangle PREROUTING fib saddr . iif oif != 0 counter + +iptables-translate -t mangle -A PREROUTING -m rpfilter --validmark --loose +nft add rule ip mangle PREROUTING fib saddr . mark oif != 0 counter + +ip6tables-translate -t mangle -A PREROUTING -m rpfilter --validmark --invert +nft add rule ip6 mangle PREROUTING fib saddr . mark . iif oif 0 counter diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index df1936be..140de265 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -370,7 +370,7 @@ print_chunk(uint32_t chunknum, int numeric) for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); ++i) if (sctp_chunk_names[i].chunk_type == chunknum) - printf("%s", sctp_chunk_names[chunknum].name); + printf("%s", sctp_chunk_names[i].name); } } diff --git a/extensions/libxt_sctp.t b/extensions/libxt_sctp.t index 2f75e2a6..4016e4fb 100644 --- a/extensions/libxt_sctp.t +++ b/extensions/libxt_sctp.t @@ -23,10 +23,7 @@ -p sctp -m sctp --chunk-types all COOKIE_ACK;=;OK -p sctp -m sctp --chunk-types all ECN_ECNE;=;OK -p sctp -m sctp --chunk-types all ECN_CWR;=;OK -# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all ASCONF -# -p sctp -m sctp --chunk-types all ASCONF;=;OK -# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all ASCONF_ACK -# -p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK -# ERROR: iptables-save segfaults: iptables -A INPUT -p sctp -m sctp --chunk-types all FORWARD_TSN -# -p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK +-p sctp -m sctp --chunk-types all ASCONF;=;OK +-p sctp -m sctp --chunk-types all ASCONF_ACK;=;OK +-p sctp -m sctp --chunk-types all FORWARD_TSN;=;OK -p sctp -m sctp --chunk-types all SHUTDOWN_COMPLETE;=;OK diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate new file mode 100644 index 00000000..72f4641a --- /dev/null +++ b/extensions/libxt_sctp.txlate @@ -0,0 +1,38 @@ +iptables-translate -A INPUT -p sctp --dport 80 -j DROP +nft add rule ip filter INPUT sctp dport 80 counter drop + +iptables-translate -A INPUT -p sctp --sport 50 -j DROP +nft add rule ip filter INPUT sctp sport 50 counter drop + +iptables-translate -A INPUT -p sctp ! --dport 80 -j DROP +nft add rule ip filter INPUT sctp dport != 80 counter drop + +iptables-translate -A INPUT -p sctp ! --sport 50 -j DROP +nft add rule ip filter INPUT sctp sport != 50 counter drop + +iptables-translate -A INPUT -p sctp --sport 80:100 -j ACCEPT +nft add rule ip filter INPUT sctp sport 80-100 counter accept + +iptables-translate -A INPUT -p sctp --dport 50:56 -j ACCEPT +nft add rule ip filter INPUT sctp dport 50-56 counter accept + +iptables-translate -A INPUT -p sctp ! --sport 80:100 -j ACCEPT +nft add rule ip filter INPUT sctp sport != 80-100 counter accept + +iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT +nft add rule ip filter INPUT sctp dport != 50-56 counter accept + +iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT +nft add rule ip filter INPUT sctp sport 50 dport 80 counter accept + +iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT +nft add rule ip filter INPUT sctp sport 50 dport 80-100 counter accept + +iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT +nft add rule ip filter INPUT sctp sport 50-55 dport 80 counter accept + +iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT +nft add rule ip filter INPUT sctp sport 50 dport != 80-100 counter accept + +iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT +nft add rule ip filter INPUT sctp sport != 50-55 dport 80 counter accept diff --git a/extensions/libxt_statistic.txlate b/extensions/libxt_statistic.txlate new file mode 100644 index 00000000..4c3dea43 --- /dev/null +++ b/extensions/libxt_statistic.txlate @@ -0,0 +1,8 @@ +iptables-translate -A OUTPUT -m statistic --mode nth --every 10 --packet 1 +nft add rule ip filter OUTPUT numgen inc mod 10 1 counter + +iptables-translate -A OUTPUT -m statistic --mode nth ! --every 10 --packet 5 +nft add rule ip filter OUTPUT numgen inc mod 10 != 5 counter + +iptables-translate -A OUTPUT -m statistic --mode random --probability 0.1 +nft # -A OUTPUT -m statistic --mode random --probability 0.1 diff --git a/extensions/libxt_tcp.txlate b/extensions/libxt_tcp.txlate new file mode 100644 index 00000000..db099037 --- /dev/null +++ b/extensions/libxt_tcp.txlate @@ -0,0 +1,20 @@ +iptables-translate -A INPUT -p tcp -i eth0 --sport 53 -j ACCEPT +nft add rule ip filter INPUT iifname eth0 tcp sport 53 counter accept + +iptables-translate -A OUTPUT -p tcp -o eth0 --dport 53:66 -j DROP +nft add rule ip filter OUTPUT oifname eth0 tcp dport 53-66 counter drop + +iptables-translate -I OUTPUT -p tcp -d 8.8.8.8 -j ACCEPT +nft insert rule ip filter OUTPUT ip protocol tcp ip daddr 8.8.8.8 counter accept + +iptables-translate -I OUTPUT -p tcp --dport 1020:1023 --sport 53 -j ACCEPT +nft insert rule ip filter OUTPUT tcp sport 53 tcp dport 1020-1023 counter accept + +iptables -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP +nft add rule ip filter INPUT tcp flags & fin|ack == fin counter drop + +iptables-translate -A INPUT -p tcp --syn -j ACCEPT +nft add rule ip filter INPUT tcp flags & (fin|syn|rst|ack) == syn counter accept + +iptables-translate -A INPUT -p tcp --syn --dport 80 -j ACCEPT +nft add rule ip filter INPUT tcp dport 80 tcp flags & (fin|syn|rst|ack) == syn counter accept diff --git a/extensions/libxt_tcpmss.c b/extensions/libxt_tcpmss.c index c7c59717..bcd357aa 100644 --- a/extensions/libxt_tcpmss.c +++ b/extensions/libxt_tcpmss.c @@ -27,8 +27,12 @@ static void tcpmss_parse(struct xt_option_call *cb) xtables_option_parse(cb); mssinfo->mss_min = cb->val.u16_range[0]; mssinfo->mss_max = mssinfo->mss_min; - if (cb->nvals == 2) + if (cb->nvals == 2) { mssinfo->mss_max = cb->val.u16_range[1]; + if (mssinfo->mss_max < mssinfo->mss_min) + xtables_error(PARAMETER_PROBLEM, + "tcpmss: invalid range given"); + } if (cb->invert) mssinfo->invert = 1; } diff --git a/extensions/libxt_tcpmss.man b/extensions/libxt_tcpmss.man index 8ee715cd..8253c363 100644 --- a/extensions/libxt_tcpmss.man +++ b/extensions/libxt_tcpmss.man @@ -1,4 +1,4 @@ This matches the TCP MSS (maximum segment size) field of the TCP header. You can only use this on TCP SYN or SYN/ACK packets, since the MSS is only negotiated during the TCP handshake at connection startup time. .TP [\fB!\fP] \fB\-\-mss\fP \fIvalue\fP[\fB:\fP\fIvalue\fP] -Match a given TCP MSS value or range. +Match a given TCP MSS value or range. If a range is given, the second \fIvalue\fP must be greater than or equal to the first \fIvalue\fP. diff --git a/extensions/libxt_tcpmss.t b/extensions/libxt_tcpmss.t index 3181e49d..2b415957 100644 --- a/extensions/libxt_tcpmss.t +++ b/extensions/libxt_tcpmss.t @@ -3,3 +3,4 @@ -p tcp -m tcpmss --mss 42;=;OK -p tcp -m tcpmss --mss 42:12345;=;OK -p tcp -m tcpmss --mss 42:65536;;FAIL +-p tcp -m tcpmss --mss 65535:1000;;FAIL diff --git a/extensions/libxt_udp.txlate b/extensions/libxt_udp.txlate new file mode 100644 index 00000000..a9adfcda --- /dev/null +++ b/extensions/libxt_udp.txlate @@ -0,0 +1,11 @@ +iptables-translate -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT +nft add rule ip filter INPUT iifname eth0 udp sport 53 counter accept + +iptables-translate -A OUTPUT -p udp -o eth0 --dport 53:66 -j DROP +nft add rule ip filter OUTPUT oifname eth0 udp dport 53-66 counter drop + +iptables-translate -I OUTPUT -p udp -d 8.8.8.8 -j ACCEPT +nft insert rule ip filter OUTPUT ip protocol udp ip daddr 8.8.8.8 counter accept + +iptables-translate -I OUTPUT -p udp --dport 1020:1023 --sport 53 -j ACCEPT +nft insert rule ip filter OUTPUT udp sport 53 udp dport 1020-1023 counter accept diff --git a/include/iptables/internal.h b/include/iptables/internal.h index 3b9013ab..bf5aa64c 100644 --- a/include/iptables/internal.h +++ b/include/iptables/internal.h @@ -1,7 +1,7 @@ #ifndef IPTABLES_INTERNAL_H #define IPTABLES_INTERNAL_H 1 -#define IPTABLES_VERSION "1.6.1" +#define IPTABLES_VERSION "1.6.2" /** * Program's own name and version. diff --git a/include/linux/netfilter/xt_hashlimit.h b/include/linux/netfilter/xt_hashlimit.h index d9808b5d..ade33f6c 100644 --- a/include/linux/netfilter/xt_hashlimit.h +++ b/include/linux/netfilter/xt_hashlimit.h @@ -17,12 +17,13 @@ struct xt_hashlimit_htable; enum { - XT_HASHLIMIT_HASH_DIP = 1 << 0, - XT_HASHLIMIT_HASH_DPT = 1 << 1, - XT_HASHLIMIT_HASH_SIP = 1 << 2, - XT_HASHLIMIT_HASH_SPT = 1 << 3, - XT_HASHLIMIT_INVERT = 1 << 4, - XT_HASHLIMIT_BYTES = 1 << 5, + XT_HASHLIMIT_HASH_DIP = 1 << 0, + XT_HASHLIMIT_HASH_DPT = 1 << 1, + XT_HASHLIMIT_HASH_SIP = 1 << 2, + XT_HASHLIMIT_HASH_SPT = 1 << 3, + XT_HASHLIMIT_INVERT = 1 << 4, + XT_HASHLIMIT_BYTES = 1 << 5, + XT_HASHLIMIT_RATE_MATCH = 1 << 6, }; struct hashlimit_cfg { @@ -77,6 +78,21 @@ struct hashlimit_cfg2 { __u8 srcmask, dstmask; }; +struct hashlimit_cfg3 { + __u64 avg; /* Average secs between packets * scale */ + __u64 burst; /* Period multiplier for upper limit. */ + __u32 mode; /* bitmask of XT_HASHLIMIT_HASH_* */ + + /* user specified */ + __u32 size; /* how many buckets */ + __u32 max; /* max number of entries */ + __u32 gc_interval; /* gc interval */ + __u32 expire; /* when do entries expire? */ + + __u32 interval; /* in seconds*/ + __u8 srcmask, dstmask; +}; + struct xt_hashlimit_mtinfo1 { char name[IFNAMSIZ]; struct hashlimit_cfg1 cfg; @@ -93,4 +109,12 @@ struct xt_hashlimit_mtinfo2 { struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); }; +struct xt_hashlimit_mtinfo3 { + char name[NAME_MAX]; + struct hashlimit_cfg3 cfg; + + /* Used internally by the kernel */ + struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); +}; + #endif /*_XT_HASHLIMIT_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_srh.h b/include/linux/netfilter_ipv6/ip6t_srh.h new file mode 100644 index 00000000..087efa1a --- /dev/null +++ b/include/linux/netfilter_ipv6/ip6t_srh.h @@ -0,0 +1,56 @@ +#ifndef _IP6T_SRH_H +#define _IP6T_SRH_H + +#include <linux/types.h> +#include <linux/netfilter.h> + +/* Values for "mt_flags" field in struct ip6t_srh */ +#define IP6T_SRH_NEXTHDR 0x0001 +#define IP6T_SRH_LEN_EQ 0x0002 +#define IP6T_SRH_LEN_GT 0x0004 +#define IP6T_SRH_LEN_LT 0x0008 +#define IP6T_SRH_SEGS_EQ 0x0010 +#define IP6T_SRH_SEGS_GT 0x0020 +#define IP6T_SRH_SEGS_LT 0x0040 +#define IP6T_SRH_LAST_EQ 0x0080 +#define IP6T_SRH_LAST_GT 0x0100 +#define IP6T_SRH_LAST_LT 0x0200 +#define IP6T_SRH_TAG 0x0400 +#define IP6T_SRH_MASK 0x07FF + +/* Values for "mt_invflags" field in struct ip6t_srh */ +#define IP6T_SRH_INV_NEXTHDR 0x0001 +#define IP6T_SRH_INV_LEN_EQ 0x0002 +#define IP6T_SRH_INV_LEN_GT 0x0004 +#define IP6T_SRH_INV_LEN_LT 0x0008 +#define IP6T_SRH_INV_SEGS_EQ 0x0010 +#define IP6T_SRH_INV_SEGS_GT 0x0020 +#define IP6T_SRH_INV_SEGS_LT 0x0040 +#define IP6T_SRH_INV_LAST_EQ 0x0080 +#define IP6T_SRH_INV_LAST_GT 0x0100 +#define IP6T_SRH_INV_LAST_LT 0x0200 +#define IP6T_SRH_INV_TAG 0x0400 +#define IP6T_SRH_INV_MASK 0x07FF + +/** + * struct ip6t_srh - SRH match options + * @ next_hdr: Next header field of SRH + * @ hdr_len: Extension header length field of SRH + * @ segs_left: Segments left field of SRH + * @ last_entry: Last entry field of SRH + * @ tag: Tag field of SRH + * @ mt_flags: match options + * @ mt_invflags: Invert the sense of match options + */ + +struct ip6t_srh { + __u8 next_hdr; + __u8 hdr_len; + __u8 segs_left; + __u8 last_entry; + __u16 tag; + __u16 mt_flags; + __u16 mt_invflags; +}; + +#endif /*_IP6T_SRH_H*/ diff --git a/include/xtables-version.h b/include/xtables-version.h index 65327656..ed31ad85 100644 --- a/include/xtables-version.h +++ b/include/xtables-version.h @@ -1,2 +1,2 @@ -#define XTABLES_VERSION "libxtables.so.10" -#define XTABLES_VERSION_CODE 10 +#define XTABLES_VERSION "libxtables.so.12" +#define XTABLES_VERSION_CODE 12 diff --git a/iptables/ip6tables-restore.c b/iptables/ip6tables-restore.c index 0db8d849..181e29f7 100644 --- a/iptables/ip6tables-restore.c +++ b/iptables/ip6tables-restore.c @@ -26,7 +26,7 @@ #define DEBUGP(x, args...) #endif -static int counters = 0, verbose = 0, noflush = 0, wait = 0; +static int counters, verbose, noflush, wait; static struct timeval wait_interval = { .tv_sec = 1, @@ -36,6 +36,7 @@ static struct timeval wait_interval = { static const struct option options[] = { {.name = "counters", .has_arg = 0, .val = 'c'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, + {.name = "version", .has_arg = 0, .val = 'V'}, {.name = "test", .has_arg = 0, .val = 't'}, {.name = "help", .has_arg = 0, .val = 'h'}, {.name = "noflush", .has_arg = 0, .val = 'n'}, @@ -46,13 +47,15 @@ static const struct option options[] = { {NULL}, }; -static void print_usage(const char *name, const char *version) __attribute__((noreturn)); +#define prog_name ip6tables_globals.program_name +#define prog_vers ip6tables_globals.program_version static void print_usage(const char *name, const char *version) { - fprintf(stderr, "Usage: %s [-c] [-v] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n" + fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n" " [ --counters ]\n" " [ --verbose ]\n" + " [ --version]\n" " [ --test ]\n" " [ --help ]\n" " [ --noflush ]\n" @@ -60,8 +63,6 @@ static void print_usage(const char *name, const char *version) " [ --wait-interval=<usecs>\n" " [ --table=<TABLE> ]\n" " [ --modprobe=<command> ]\n", name); - - exit(1); } static struct xtc_handle *create_handle(const char *tablename) @@ -78,8 +79,7 @@ static struct xtc_handle *create_handle(const char *tablename) if (!handle) { xtables_error(PARAMETER_PROBLEM, "%s: unable to initialize " - "table '%s'\n", ip6tables_globals.program_name, - tablename); + "table '%s'\n", prog_name, tablename); exit(1); } return handle; @@ -165,8 +165,11 @@ static void add_param_to_argv(char *parsestart) param_buffer[param_len] = '\0'; /* check if table name specified */ - if (!strncmp(param_buffer, "-t", 2) - || !strncmp(param_buffer, "--table", 8)) { + if ((param_buffer[0] == '-' && + param_buffer[1] != '-' && + strchr(param_buffer, 't')) || + (!strncmp(param_buffer, "--t", 3) && + !strncmp(param_buffer, "--table", strlen(param_buffer)))) { xtables_error(PARAMETER_PROBLEM, "The -t option (seen in line %u) cannot be " "used in ip6tables-restore.\n", line); @@ -213,7 +216,7 @@ int ip6tables_restore_main(int argc, char *argv[]) init_extensions6(); #endif - while ((c = getopt_long(argc, argv, "bcvthnwWM:T:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -224,13 +227,16 @@ int ip6tables_restore_main(int argc, char *argv[]) case 'v': verbose = 1; break; + case 'V': + printf("%s v%s\n", prog_name, prog_vers); + exit(0); case 't': testing = 1; break; case 'h': print_usage("ip6tables-restore", IPTABLES_VERSION); - break; + exit(0); case 'n': noflush = 1; break; @@ -246,6 +252,10 @@ int ip6tables_restore_main(int argc, char *argv[]) case 'T': tablename = optarg; break; + default: + fprintf(stderr, + "Try `ip6tables-restore -h' for more information.\n"); + exit(1); } } @@ -263,6 +273,11 @@ int ip6tables_restore_main(int argc, char *argv[]) } else in = stdin; + if (!wait_interval.tv_sec && !wait) { + fprintf(stderr, "Option --wait-interval requires option --wait\n"); + exit(1); + } + /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { int ret = 0; diff --git a/iptables/ip6tables-save.c b/iptables/ip6tables-save.c index 053413a9..8e3a6afd 100644 --- a/iptables/ip6tables-save.c +++ b/iptables/ip6tables-save.c @@ -14,17 +14,19 @@ #include <time.h> #include <netdb.h> #include <arpa/inet.h> +#include <unistd.h> #include "libiptc/libip6tc.h" #include "ip6tables.h" #include "ip6tables-multi.h" -static int show_counters = 0; +static int show_counters; static const struct option options[] = { {.name = "counters", .has_arg = false, .val = 'c'}, {.name = "dump", .has_arg = false, .val = 'd'}, {.name = "table", .has_arg = true, .val = 't'}, {.name = "modprobe", .has_arg = true, .val = 'M'}, + {.name = "file", .has_arg = true, .val = 'f'}, {NULL}, }; @@ -128,7 +130,8 @@ static int do_output(const char *tablename) int ip6tables_save_main(int argc, char *argv[]) { const char *tablename = NULL; - int c; + FILE *file = NULL; + int ret, c; ip6tables_globals.program_name = "ip6tables-save"; c = xtables_init_all(&ip6tables_globals, NFPROTO_IPV6); @@ -143,7 +146,7 @@ int ip6tables_save_main(int argc, char *argv[]) init_extensions6(); #endif - while ((c = getopt_long(argc, argv, "bcdt:M:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -159,9 +162,28 @@ int ip6tables_save_main(int argc, char *argv[]) case 'M': xtables_modprobe_program = optarg; break; + case 'f': + file = fopen(optarg, "w"); + if (file == NULL) { + fprintf(stderr, "Failed to open file, error: %s\n", + strerror(errno)); + exit(1); + } + ret = dup2(fileno(file), STDOUT_FILENO); + if (ret == -1) { + fprintf(stderr, "Failed to redirect stdout, error: %s\n", + strerror(errno)); + exit(1); + } + fclose(file); + break; case 'd': do_output(tablename); exit(0); + default: + fprintf(stderr, + "Look at manual page `ip6tables-save.8' for more information.\n"); + exit(1); } } diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in index 7a286b91..f751492d 100644 --- a/iptables/iptables-restore.8.in +++ b/iptables/iptables-restore.8.in @@ -23,11 +23,13 @@ iptables-restore \(em Restore IP Tables .P ip6tables-restore \(em Restore IPv6 Tables .SH SYNOPSIS -\fBiptables\-restore\fP [\fB\-chntv\fP] [\fB\-M\fP \fImodprobe\fP] -[\fB\-T\fP \fIname\fP] [\fBfile\fP] +\fBiptables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIsecs\fP] +[\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] +[\fBfile\fP] .P -\fBip6tables\-restore\fP [\fB\-chntv\fP] [\fB\-M\fP \fImodprobe\fP] -[\fB\-T\fP \fIname\fP] [\fBfile\fP] +\fBip6tables\-restore\fP [\fB\-chntvV\fP] [\fB\-w\fP \fIsecs\fP] +[\fB\-W\fP \fIusecs\fP] [\fB\-M\fP \fImodprobe\fP] [\fB\-T\fP \fIname\fP] +[\fBfile\fP] .SH DESCRIPTION .PP .B iptables-restore @@ -53,6 +55,24 @@ Only parse and construct the ruleset, but do not commit it. \fB\-v\fP, \fB\-\-verbose\fP Print additional debug info during ruleset processing. .TP +\fB\-V\fP, \fB\-\-version\fP +Print the program version number. +.TP +\fB\-w\fP, \fB\-\-wait\fP [\fIseconds\fP] +Wait for the xtables lock. +To prevent multiple instances of the program from running concurrently, +an attempt will be made to obtain an exclusive lock at launch. By default, +the program will exit if the lock cannot be obtained. This option will +make the program wait (indefinitely or for optional \fIseconds\fP) until +the exclusive lock can be obtained. +.TP +\fB\-W\fP, \fB\-\-wait-interval\fP \fImicroseconds\fP +Interval to wait per each iteration. +When running latency sensitive applications, waiting for the xtables lock +for extended durations may not be acceptable. This option will make each +iteration take the amount of time specified. The default interval is +1 second. This option only works with \fB\-w\fP. +.TP \fB\-M\fP, \fB\-\-modprobe\fP \fImodprobe_program\fP Specify the path to the modprobe program. By default, iptables-restore will inspect /proc/sys/kernel/modprobe to determine the executable's path. diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c index 078d1d46..e63a3e50 100644 --- a/iptables/iptables-restore.c +++ b/iptables/iptables-restore.c @@ -23,7 +23,7 @@ #define DEBUGP(x, args...) #endif -static int counters = 0, verbose = 0, noflush = 0, wait = 0; +static int counters, verbose, noflush, wait; static struct timeval wait_interval = { .tv_sec = 1, @@ -33,6 +33,7 @@ static struct timeval wait_interval = { static const struct option options[] = { {.name = "counters", .has_arg = 0, .val = 'c'}, {.name = "verbose", .has_arg = 0, .val = 'v'}, + {.name = "version", .has_arg = 0, .val = 'V'}, {.name = "test", .has_arg = 0, .val = 't'}, {.name = "help", .has_arg = 0, .val = 'h'}, {.name = "noflush", .has_arg = 0, .val = 'n'}, @@ -43,15 +44,15 @@ static const struct option options[] = { {NULL}, }; -static void print_usage(const char *name, const char *version) __attribute__((noreturn)); - #define prog_name iptables_globals.program_name +#define prog_vers iptables_globals.program_version static void print_usage(const char *name, const char *version) { - fprintf(stderr, "Usage: %s [-c] [-v] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n" + fprintf(stderr, "Usage: %s [-c] [-v] [-V] [-t] [-h] [-n] [-w secs] [-W usecs] [-T table] [-M command]\n" " [ --counters ]\n" " [ --verbose ]\n" + " [ --version]\n" " [ --test ]\n" " [ --help ]\n" " [ --noflush ]\n" @@ -59,8 +60,6 @@ static void print_usage(const char *name, const char *version) " [ --wait-interval=<usecs>\n" " [ --table=<TABLE> ]\n" " [ --modprobe=<command> ]\n", name); - - exit(1); } static struct xtc_handle *create_handle(const char *tablename) @@ -163,8 +162,11 @@ static void add_param_to_argv(char *parsestart) param_buffer[param_len] = '\0'; /* check if table name specified */ - if (!strncmp(param_buffer, "-t", 2) - || !strncmp(param_buffer, "--table", 8)) { + if ((param_buffer[0] == '-' && + param_buffer[1] != '-' && + strchr(param_buffer, 't')) || + (!strncmp(param_buffer, "--t", 3) && + !strncmp(param_buffer, "--table", strlen(param_buffer)))) { xtables_error(PARAMETER_PROBLEM, "The -t option (seen in line %u) cannot be " "used in iptables-restore.\n", line); @@ -212,7 +214,7 @@ iptables_restore_main(int argc, char *argv[]) init_extensions4(); #endif - while ((c = getopt_long(argc, argv, "bcvthnwWM:T:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcvVthnwWM:T:", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -223,13 +225,16 @@ iptables_restore_main(int argc, char *argv[]) case 'v': verbose = 1; break; + case 'V': + printf("%s v%s\n", prog_name, prog_vers); + exit(0); case 't': testing = 1; break; case 'h': print_usage("iptables-restore", IPTABLES_VERSION); - break; + exit(0); case 'n': noflush = 1; break; @@ -245,6 +250,10 @@ iptables_restore_main(int argc, char *argv[]) case 'T': tablename = optarg; break; + default: + fprintf(stderr, + "Try `iptables-restore -h' for more information.\n"); + exit(1); } } @@ -262,6 +271,11 @@ iptables_restore_main(int argc, char *argv[]) } else in = stdin; + if (!wait_interval.tv_sec && !wait) { + fprintf(stderr, "Option --wait-interval requires option --wait\n"); + exit(1); + } + /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { int ret = 0; diff --git a/iptables/iptables-save.8.in b/iptables/iptables-save.8.in index 7f99d8a3..51e11f3e 100644 --- a/iptables/iptables-save.8.in +++ b/iptables/iptables-save.8.in @@ -19,27 +19,31 @@ .\" .\" .SH NAME -iptables-save \(em dump iptables rules to stdout +iptables-save \(em dump iptables rules .P -ip6tables-save \(em dump iptables rules to stdout +ip6tables-save \(em dump iptables rules .SH SYNOPSIS \fBiptables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP] -[\fB\-t\fP \fItable\fP] +[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP] .P \fBip6tables\-save\fP [\fB\-M\fP \fImodprobe\fP] [\fB\-c\fP] -[\fB\-t\fP \fItable\fP] +[\fB\-t\fP \fItable\fP] [\fB\-f\fP \fIfilename\fP] .SH DESCRIPTION .PP .B iptables-save and .B ip6tables-save are used to dump the contents of IP or IPv6 Table in easily parseable format -to STDOUT. Use I/O-redirection provided by your shell to write to a file. +either to STDOUT or to a specified file. .TP \fB\-M\fR, \fB\-\-modprobe\fR \fImodprobe_program\fP Specify the path to the modprobe program. By default, iptables-save will inspect /proc/sys/kernel/modprobe to determine the executable's path. .TP +\fB\-f\fR, \fB\-\-file\fR \fIfilename\fP +Specify a filename to log the output to. If not specified, iptables-save +will log to STDOUT. +.TP \fB\-c\fR, \fB\-\-counters\fR include the current values of all packet and byte counters in the output .TP diff --git a/iptables/iptables-save.c b/iptables/iptables-save.c index e8ae9c6c..d59bd34a 100644 --- a/iptables/iptables-save.c +++ b/iptables/iptables-save.c @@ -13,17 +13,19 @@ #include <string.h> #include <time.h> #include <netdb.h> +#include <unistd.h> #include "libiptc/libiptc.h" #include "iptables.h" #include "iptables-multi.h" -static int show_counters = 0; +static int show_counters; static const struct option options[] = { {.name = "counters", .has_arg = false, .val = 'c'}, {.name = "dump", .has_arg = false, .val = 'd'}, {.name = "table", .has_arg = true, .val = 't'}, {.name = "modprobe", .has_arg = true, .val = 'M'}, + {.name = "file", .has_arg = true, .val = 'f'}, {NULL}, }; @@ -127,7 +129,8 @@ int iptables_save_main(int argc, char *argv[]) { const char *tablename = NULL; - int c; + FILE *file = NULL; + int ret, c; iptables_globals.program_name = "iptables-save"; c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); @@ -142,7 +145,7 @@ iptables_save_main(int argc, char *argv[]) init_extensions4(); #endif - while ((c = getopt_long(argc, argv, "bcdt:M:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcdt:M:f:", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -158,9 +161,28 @@ iptables_save_main(int argc, char *argv[]) case 'M': xtables_modprobe_program = optarg; break; + case 'f': + file = fopen(optarg, "w"); + if (file == NULL) { + fprintf(stderr, "Failed to open file, error: %s\n", + strerror(errno)); + exit(1); + } + ret = dup2(fileno(file), STDOUT_FILENO); + if (ret == -1) { + fprintf(stderr, "Failed to redirect stdout, error: %s\n", + strerror(errno)); + exit(1); + } + fclose(file); + break; case 'd': do_output(tablename); exit(0); + default: + fprintf(stderr, + "Look at manual page `iptables-save.8' for more information.\n"); + exit(1); } } diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c index c60b4b77..3a4d5e37 100644 --- a/iptables/iptables-standalone.c +++ b/iptables/iptables-standalone.c @@ -76,9 +76,8 @@ iptables_main(int argc, char *argv[]) fprintf(stderr, "iptables: %s.\n", iptc_strerror(errno)); } - if (errno == EAGAIN) { + if (errno == EAGAIN) exit(RESOURCE_PROBLEM); - } } exit(!ret); diff --git a/iptables/iptables-xml.c b/iptables/iptables-xml.c index 740a563c..49674ec1 100644 --- a/iptables/iptables-xml.c +++ b/iptables/iptables-xml.c @@ -34,9 +34,9 @@ struct xtables_globals iptables_xml_globals = { static void print_usage(const char *name, const char *version) __attribute__ ((noreturn)); -static int verbose = 0; +static int verbose; /* Whether to combine actions of sequential rules with identical conditions */ -static int combine = 0; +static int combine; /* Keeping track of external matches and targets. */ static struct option options[] = { {"verbose", 0, NULL, 'v'}, @@ -73,10 +73,10 @@ parse_counters(char *string, struct xt_counters *ctr) /* global new argv and argc */ static char *newargv[255]; -static unsigned int newargc = 0; +static unsigned int newargc; static char *oldargv[255]; -static unsigned int oldargc = 0; +static unsigned int oldargc; /* arg meta data, were they quoted, frinstance */ static int newargvattr[255]; @@ -96,7 +96,7 @@ struct chain { #define maxChains 10240 /* max chains per table */ static struct chain chains[maxChains]; -static int nextChain = 0; +static int nextChain; /* funCtion adding one argument to newargv, updating newargc * returns true if argument added, false otherwise */ @@ -426,12 +426,9 @@ do_rule_part(char *leveltag1, char *leveltag2, int part, int argc, else printf("%s%s", spacer, argv[arg]); spacer = " "; - } else if (!argvattr[arg] && isTarget(argv[arg]) - && existsChain(argv[arg + 1]) - && (2 + arg >= argc)) { - if (!((1 + arg) < argc)) - // no args to -j, -m or -g, ignore & finish loop - break; + } else if (!argvattr[arg] && isTarget(argv[arg]) && + (arg + 1 < argc) && + existsChain(argv[arg + 1])) { CLOSE_LEVEL(2); if (level1) printf("%s", leveli1); @@ -819,9 +816,11 @@ iptables_xml_main(int argc, char *argv[]) *(param_buffer + param_len) = '\0'; /* check if table name specified */ - if (!strncmp(param_buffer, "-t", 3) - || !strncmp(param_buffer, - "--table", 8)) { + if ((param_buffer[0] == '-' && + param_buffer[1] != '-' && + strchr(param_buffer, 't')) || + (!strncmp(param_buffer, "--t", 3) && + !strncmp(param_buffer, "--table", strlen(param_buffer)))) { xtables_error(PARAMETER_PROBLEM, "Line %u seems to have a " "-t table option.\n", diff --git a/iptables/iptables.c b/iptables/iptables.c index d61d5b90..69d19fec 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -1114,9 +1114,8 @@ void print_rule4(const struct ipt_entry *e, e->ip.invflags & IPT_INV_FRAG ? " !" : ""); /* Print matchinfo part */ - if (e->target_offset) { + if (e->target_offset) IPT_MATCH_ITERATE(e, print_match_save, &e->ip); - } /* print counters for iptables -R */ if (counters < 0) diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index e5947a7c..00dd3e93 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -320,6 +320,8 @@ static void nft_ipv4_print_firewall(struct nftnl_rule *r, unsigned int num, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); + + xtables_rule_matches_free(&cs.matches); } static void save_ipv4_addr(char letter, const struct in_addr *addr, @@ -488,7 +490,7 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl) return ret; /* Always add counters per rule, as in iptables */ - xt_xlate_add(xl, "counter "); + xt_xlate_add(xl, "counter"); ret = xlate_action(cs, !!(cs->fw.ip.flags & IPT_F_GOTO), xl); comment = xt_xlate_get_comment(xl); diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 9cf4058f..9867d1ee 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -251,6 +251,8 @@ static void nft_ipv6_print_firewall(struct nftnl_rule *r, unsigned int num, if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); + + xtables_rule_matches_free(&cs.matches); } static void save_ipv6_addr(char letter, const struct in6_addr *addr, @@ -437,7 +439,7 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl) return ret; /* Always add counters per rule, as in iptables */ - xt_xlate_add(xl, "counter "); + xt_xlate_add(xl, "counter"); ret = xlate_action(cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO), xl); comment = xt_xlate_get_comment(xl); diff --git a/iptables/nft.c b/iptables/nft.c index fee91bc7..91381419 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -147,7 +147,8 @@ static void mnl_nftnl_batch_reset(void) list_for_each_entry_safe(batch_page, next, &batch_page_list, head) { list_del(&batch_page->head); - free(batch_page->batch); + free(mnl_nlmsg_batch_head(batch_page->batch)); + mnl_nlmsg_batch_stop(batch_page->batch); free(batch_page); batch_num_pages--; } @@ -1454,13 +1455,18 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl return ret == 0 ? 1 : 0; } +/* From linux/netlink.h */ +#ifndef NLM_F_NONREC +#define NLM_F_NONREC 0x100 /* Do not delete recursively */ +#endif + static int __nft_chain_del(struct nft_handle *h, struct nftnl_chain *c) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN, h->family, - NLM_F_ACK, h->seq); + NLM_F_NONREC | NLM_F_ACK, h->seq); nftnl_chain_nlmsg_build_payload(nlh, c); return mnl_talk(h, nlh, NULL, NULL); @@ -2348,7 +2354,8 @@ static int nft_action(struct nft_handle *h, int action) break; case NFT_COMPAT_CHAIN_USER_DEL: nft_compat_chain_batch_add(h, NFT_MSG_DELCHAIN, - 0, seq++, n->chain); + NLM_F_NONREC, seq++, + n->chain); break; case NFT_COMPAT_CHAIN_UPDATE: nft_compat_chain_batch_add(h, NFT_MSG_NEWCHAIN, @@ -2536,8 +2543,8 @@ static void xtables_config_perror(uint32_t flags, const char *fmt, ...) int nft_xtables_config_load(struct nft_handle *h, const char *filename, uint32_t flags) { - struct nftnl_table_list *table_list = nftnl_table_list_alloc(); - struct nftnl_chain_list *chain_list = nftnl_chain_list_alloc(); + struct nftnl_table_list *table_list = NULL; + struct nftnl_chain_list *chain_list = NULL; struct nftnl_table_list_iter *titer = NULL; struct nftnl_chain_list_iter *citer = NULL; struct nftnl_table *table; @@ -2548,6 +2555,9 @@ int nft_xtables_config_load(struct nft_handle *h, const char *filename, if (h->restore) return 0; + table_list = nftnl_table_list_alloc(); + chain_list = nftnl_chain_list_alloc(); + if (xtables_config_parse(filename, table_list, chain_list) < 0) { if (errno == ENOENT) { xtables_config_perror(flags, diff --git a/iptables/xshared.c b/iptables/xshared.c index 825479c3..06db72d4 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -343,7 +343,7 @@ void parse_wait_interval(int argc, char *argv[], struct timeval *wait_interval) else if (xs_has_arg(argc, argv)) arg = argv[optind++]; else - return; + xtables_error(PARAMETER_PROBLEM, "wait interval value required"); ret = sscanf(arg, "%u", &usec); if (ret == 1) { diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c index 6aa000a1..4a968f4b 100644 --- a/iptables/xtables-arp.c +++ b/iptables/xtables-arp.c @@ -150,7 +150,7 @@ static struct option original_opts[] = { int RUNTIME_NF_ARP_NUMHOOKS = 3; static struct option *opts = original_opts; -static unsigned int global_option_offset = 0; +static unsigned int global_option_offset; extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); struct xtables_globals arptables_globals = { diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index a551c8c1..fc39ad9c 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -24,7 +24,7 @@ #define DEBUGP(x, args...) #endif -static int counters = 0, verbose = 0, noflush = 0; +static int counters, verbose, noflush; /* Keeping track of external matches and targets. */ static const struct option options[] = { @@ -40,8 +40,6 @@ static const struct option options[] = { {NULL}, }; -static void print_usage(const char *name, const char *version) __attribute__((noreturn)); - #define prog_name xtables_globals.program_name static void print_usage(const char *name, const char *version) @@ -56,8 +54,6 @@ static void print_usage(const char *name, const char *version) " [ --modprobe=<command> ]\n" " [ --ipv4 ]\n" " [ --ipv6 ]\n", name); - - exit(1); } static int parse_counters(char *string, struct xt_counters *ctr) @@ -140,8 +136,11 @@ static void add_param_to_argv(char *parsestart) param_buffer[param_len] = '\0'; /* check if table name specified */ - if (!strncmp(param_buffer, "-t", 2) - || !strncmp(param_buffer, "--table", 8)) { + if ((param_buffer[0] == '-' && + param_buffer[1] != '-' && + strchr(param_buffer, 't')) || + (!strncmp(param_buffer, "--t", 3) && + !strncmp(param_buffer, "--table", strlen(param_buffer)))) { xtables_error(PARAMETER_PROBLEM, "The -t option (seen in line %u) cannot be " "used in xtables-restore.\n", line); @@ -181,8 +180,10 @@ static void chain_delete(struct nftnl_chain_list *clist, const char *curtable, /* This chain has been found, delete from list. Later * on, unvisited chains will be purged out. */ - if (chain_obj != NULL) + if (chain_obj != NULL) { nftnl_chain_list_del(chain_obj); + nftnl_chain_free(chain_obj); + } } struct nft_xt_restore_cb restore_cb = { @@ -434,6 +435,9 @@ void xtables_restore_parse(struct nft_handle *h, xt_params->program_name, line + 1); exit(1); } + + if (chain_list) + nftnl_chain_list_free(chain_list); } static int @@ -486,7 +490,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) case 'h': print_usage("xtables-restore", IPTABLES_VERSION); - break; + exit(0); case 'n': noflush = 1; break; @@ -503,6 +507,10 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) h.family = AF_INET6; xtables_set_nfproto(AF_INET6); break; + default: + fprintf(stderr, + "Try `xtables-restore -h' for more information.\n"); + exit(1); } } @@ -522,6 +530,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[]) xtables_restore_parse(&h, &p, &restore_cb, argc, argv); + nft_fini(&h); fclose(p.in); return 0; } diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index f30867cf..5b498b04 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -14,6 +14,7 @@ #include <string.h> #include <time.h> #include <netdb.h> +#include <unistd.h> #include "libiptc/libiptc.h" #include "iptables.h" #include "xtables-multi.h" @@ -32,6 +33,7 @@ static const struct option options[] = { {.name = "dump", .has_arg = false, .val = 'd'}, {.name = "table", .has_arg = true, .val = 't'}, {.name = "modprobe", .has_arg = true, .val = 'M'}, + {.name = "file", .has_arg = true, .val = 'f'}, {.name = "ipv4", .has_arg = false, .val = '4'}, {.name = "ipv6", .has_arg = false, .val = '6'}, {NULL}, @@ -82,7 +84,8 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[]) struct nft_handle h = { .family = family, }; - int c; + FILE *file = NULL; + int ret, c; xtables_globals.program_name = progname; c = xtables_init_all(&xtables_globals, family); @@ -104,7 +107,7 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[]) exit(EXIT_FAILURE); } - while ((c = getopt_long(argc, argv, "bcdt:M:46", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "bcdt:M:f:46", options, NULL)) != -1) { switch (c) { case 'b': fprintf(stderr, "-b/--binary option is not implemented\n"); @@ -120,6 +123,21 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[]) case 'M': xtables_modprobe_program = optarg; break; + case 'f': + file = fopen(optarg, "w"); + if (file == NULL) { + fprintf(stderr, "Failed to open file, error: %s\n", + strerror(errno)); + exit(1); + } + ret = dup2(fileno(file), STDOUT_FILENO); + if (ret == -1) { + fprintf(stderr, "Failed to redirect stdout, error: %s\n", + strerror(errno)); + exit(1); + } + fclose(file); + break; case 'd': dump = true; break; @@ -130,6 +148,10 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[]) h.family = AF_INET6; xtables_set_nfproto(AF_INET6); break; + default: + fprintf(stderr, + "Look at manual page `xtables-save.8' for more information.\n"); + exit(1); } } diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c index 355a4460..139c477f 100644 --- a/iptables/xtables-standalone.c +++ b/iptables/xtables-standalone.c @@ -85,9 +85,8 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) fprintf(stderr, "iptables: %s.\n", nft_strerror(errno)); } - if (errno == EAGAIN) { + if (errno == EAGAIN) exit(RESOURCE_PROBLEM); - } } exit(!ret); diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c index 153bd650..4f6a9caf 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -60,12 +60,13 @@ int xlate_action(const struct iptables_command_state *cs, bool goto_set, if (cs->target != NULL) { /* Standard target? */ if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0) - xt_xlate_add(xl, "accept"); + xt_xlate_add(xl, " accept"); else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0) - xt_xlate_add(xl, "drop"); + xt_xlate_add(xl, " drop"); else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0) - xt_xlate_add(xl, "return"); + xt_xlate_add(xl, " return"); else if (cs->target->xlate) { + xt_xlate_add(xl, " "); struct xt_xlate_tg_params params = { .ip = (const void *)&cs->fw, .target = cs->target->t, @@ -79,9 +80,9 @@ int xlate_action(const struct iptables_command_state *cs, bool goto_set, } else if (strlen(cs->jumpto) > 0) { /* Not standard, then it's a go / jump to chain */ if (goto_set) - xt_xlate_add(xl, "goto %s", cs->jumpto); + xt_xlate_add(xl, " goto %s", cs->jumpto); else - xt_xlate_add(xl, "jump %s", cs->jumpto); + xt_xlate_add(xl, " jump %s", cs->jumpto); } return ret; @@ -195,6 +196,8 @@ static int xlate(struct nft_handle *h, struct nft_xt_cmd_parse *p, } break; } + if (!cs->restore && i < args->s.naddrs - 1) + printf("nft "); } return ret; @@ -234,9 +237,8 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], switch (p.command) { case CMD_APPEND: ret = 1; - if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add)) { + if (!xlate(h, &p, &cs, &args, true, nft_rule_xlate_add)) print_ipt_cmd(argc, argv); - } break; case CMD_DELETE: break; @@ -248,9 +250,8 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], break; case CMD_INSERT: ret = 1; - if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add)) { + if (!xlate(h, &p, &cs, &args, false, nft_rule_xlate_add)) print_ipt_cmd(argc, argv); - } break; case CMD_FLUSH: if (p.chain) { @@ -356,6 +357,8 @@ static int xlate_chain_set(struct nft_handle *h, const char *table, if (strcmp(table, "nat") == 0) type = "nat"; + else if (strcmp(table, "mangle") == 0 && strcmp(chain, "OUTPUT") == 0) + type = "route"; printf("add chain %s %s %s { type %s ", family2str[h->family], table, chain, type); @@ -379,6 +382,14 @@ static int xlate_chain_set(struct nft_handle *h, const char *table, return 1; } +static int dummy_compat_rev(const char *name, uint8_t rev, int opt) +{ + /* Avoid querying the kernel - it's not needed when just translating + * rules and not even possible when running as unprivileged user. + */ + return 1; +} + static struct nft_xt_restore_cb cb_xlate = { .table_new = xlate_table_new, .chain_set = xlate_chain_set, @@ -398,6 +409,7 @@ static int xtables_xlate_main(int family, const char *progname, int argc, }; xtables_globals.program_name = progname; + xtables_globals.compat_rev = dummy_compat_rev; ret = xtables_init_all(&xtables_globals, family); if (ret < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", @@ -440,6 +452,7 @@ static int xtables_restore_xlate_main(int family, const char *progname, int c; xtables_globals.program_name = progname; + xtables_globals.compat_rev = dummy_compat_rev; ret = xtables_init_all(&xtables_globals, family); if (ret < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", diff --git a/iptables/xtables.c b/iptables/xtables.c index 286866f7..ac113254 100644 --- a/iptables/xtables.c +++ b/iptables/xtables.c @@ -1281,6 +1281,8 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, *table = p.table; xtables_rule_matches_free(&cs.matches); + if (cs.target) + free(cs.target->t); if (h->family == AF_INET) { free(args.s.addr.v4); diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index d21c391e..b28ca0ae 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -1693,7 +1693,8 @@ iptcc_standard_map(struct rule_head *r, int verdict) static int iptcc_map_target(struct xtc_handle *const handle, - struct rule_head *r) + struct rule_head *r, + bool dry_run) { STRUCT_ENTRY *e = r->entry; STRUCT_ENTRY_TARGET *t = GET_TARGET(e); @@ -1738,7 +1739,8 @@ iptcc_map_target(struct xtc_handle *const handle, 0, FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name)); r->type = IPTCC_R_MODULE; - set_changed(handle); + if (!dry_run) + set_changed(handle); return 1; } @@ -1788,7 +1790,7 @@ TC_INSERT_ENTRY(const IPT_CHAINLABEL chain, memcpy(r->entry, e, e->next_offset); r->counter_map.maptype = COUNTER_MAP_SET; - if (!iptcc_map_target(handle, r)) { + if (!iptcc_map_target(handle, r, false)) { free(r); return 0; } @@ -1838,7 +1840,7 @@ TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain, memcpy(r->entry, e, e->next_offset); r->counter_map.maptype = COUNTER_MAP_SET; - if (!iptcc_map_target(handle, r)) { + if (!iptcc_map_target(handle, r, false)) { free(r); return 0; } @@ -1877,7 +1879,7 @@ TC_APPEND_ENTRY(const IPT_CHAINLABEL chain, memcpy(r->entry, e, e->next_offset); r->counter_map.maptype = COUNTER_MAP_SET; - if (!iptcc_map_target(handle, r)) { + if (!iptcc_map_target(handle, r, false)) { DEBUGP("unable to map target of rule for chain `%s'\n", chain); free(r); return 0; @@ -1983,7 +1985,7 @@ static int delete_entry(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw, memcpy(r->entry, origfw, origfw->next_offset); r->counter_map.maptype = COUNTER_MAP_NOMAP; - if (!iptcc_map_target(handle, r)) { + if (!iptcc_map_target(handle, r, dry_run)) { DEBUGP("unable to map target of rule for chain `%s'\n", chain); free(r); return 0; diff --git a/libxtables/xtables.c b/libxtables/xtables.c index d43f9706..57a11022 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -538,15 +538,15 @@ void xtables_parse_interface(const char *arg, char *vianame, } else { /* Include nul-terminator in match */ memset(mask, 0xFF, vialen + 1); - for (i = 0; vianame[i]; i++) { - if (vianame[i] == '/' || - vianame[i] == ' ') { - fprintf(stderr, - "Warning: weird character in interface" - " `%s' ('/' and ' ' are not allowed by the kernel).\n", - vianame); - break; - } + } + + /* Display warning on invalid characters */ + for (i = 0; vianame[i]; i++) { + if (vianame[i] == '/' || vianame[i] == ' ') { + fprintf(stderr, "Warning: weird character in interface" + " `%s' ('/' and ' ' are not allowed by the kernel).\n", + vianame); + break; } } } @@ -1367,26 +1367,22 @@ static struct in_addr *host_to_ipaddr(const char *name, unsigned int *naddr) unsigned int i; memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_RAW; *naddr = 0; - if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) { + err = getaddrinfo(name, NULL, &hints, &res); + if (err != 0) return NULL; - } else { - for (p = res; p != NULL; p = p->ai_next) - ++*naddr; - addr = xtables_calloc(*naddr, sizeof(struct in_addr)); - for (i = 0, p = res; p != NULL; p = p->ai_next) - memcpy(&addr[i++], - &((const struct sockaddr_in *)p->ai_addr)->sin_addr, - sizeof(struct in_addr)); - freeaddrinfo(res); - return addr; - } - - return NULL; + for (p = res; p != NULL; p = p->ai_next) + ++*naddr; + addr = xtables_calloc(*naddr, sizeof(struct in_addr)); + for (i = 0, p = res; p != NULL; p = p->ai_next) + memcpy(&addr[i++], + &((const struct sockaddr_in *)p->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(res); + return addr; } static struct in_addr * @@ -1657,28 +1653,24 @@ host_to_ip6addr(const char *name, unsigned int *naddr) unsigned int i; memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_RAW; *naddr = 0; - if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) { + err = getaddrinfo(name, NULL, &hints, &res); + if (err != 0) return NULL; - } else { - /* Find length of address chain */ - for (p = res; p != NULL; p = p->ai_next) - ++*naddr; - /* Copy each element of the address chain */ - addr = xtables_calloc(*naddr, sizeof(struct in6_addr)); - for (i = 0, p = res; p != NULL; p = p->ai_next) - memcpy(&addr[i++], - &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr, - sizeof(struct in6_addr)); - freeaddrinfo(res); - return addr; - } - - return NULL; + /* Find length of address chain */ + for (p = res; p != NULL; p = p->ai_next) + ++*naddr; + /* Copy each element of the address chain */ + addr = xtables_calloc(*naddr, sizeof(struct in6_addr)); + for (i = 0, p = res; p != NULL; p = p->ai_next) + memcpy(&addr[i++], + &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr, + sizeof(struct in6_addr)); + freeaddrinfo(res); + return addr; } static struct in6_addr *network_to_ip6addr(const char *name) diff --git a/utils/.gitignore b/utils/.gitignore index 216d1e4a..7c6afbf4 100644 --- a/utils/.gitignore +++ b/utils/.gitignore @@ -1,2 +1,3 @@ /nfnl_osf +/nfnl_osf.8 /nfbpf_compile diff --git a/utils/Makefile.am b/utils/Makefile.am index c4192a9e..80029e30 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -6,8 +6,10 @@ AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include \ sbin_PROGRAMS = pkgdata_DATA = +man_MANS = if HAVE_LIBNFNETLINK +man_MANS += nfnl_osf.8 sbin_PROGRAMS += nfnl_osf pkgdata_DATA += pf.os @@ -23,3 +25,5 @@ if ENABLE_SYNCONF sbin_PROGRAMS += nfsynproxy nfsynproxy_LDADD = -lpcap endif + +CLEANFILES = nfnl_osf.8 diff --git a/utils/nfnl_osf.8.in b/utils/nfnl_osf.8.in new file mode 100644 index 00000000..140b5c3f --- /dev/null +++ b/utils/nfnl_osf.8.in @@ -0,0 +1,67 @@ +.TH NFNL_OSF 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@" + +.SH NAME +nfnl_osf \- OS fingerprint loader utility +.SH SYNOPSIS + +.ad l +.in +8 +.ti -8 +.B nfnl_osf +.BI -f " fingerprints" +[ +.B -d +] + +.SH DESCRIPTION +The +.B nfnl_osf +utility allows to load a set of operating system signatures into the kernel for +later matching against using iptables' +.B osf +match. + +.SH OPTIONS + +.TP +.BI -f " fingerprints" +Read signatures from file +.IR fingerprints . + +.TP +.B -d +Instead of adding the signatures from +.I fingerprints +into the kernel, remove them. + +.SH EXIT STATUS +Exit status is 0 if command succeeded, otherwise a negative return code +indicates the type of error which happened: + +.TP +.B -1 +Illegal arguments passed, fingerprints file not readable or failure in netlink +communication. + +.TP +.B -ENOENT +Fingerprints file not specified. + +.TP +.B -EINVAL +Netlink handle initialization failed or fingerprints file format invalid. + +.SH FILES + +An up to date set of operating system signatures can be downloaded from +http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os . + +.SH SEE ALSO + +The description of +.B osf +match in +.BR iptables-extensions (8) +contains further information about the topic as well as example +.B nfnl_osf +invocations. diff --git a/utils/nfnl_osf.c b/utils/nfnl_osf.c index 645ec648..720e3a38 100644 --- a/utils/nfnl_osf.c +++ b/utils/nfnl_osf.c @@ -438,7 +438,7 @@ int main(int argc, char *argv[]) break; default: fprintf(stderr, - "Usage: %s -f fingerprints -d <del rules> -h\n", + "Usage: %s -f fingerprints [-d]\n", argv[0]); return -1; } diff --git a/utils/nfsynproxy.c b/utils/nfsynproxy.c index baedc92c..bf5c4163 100644 --- a/utils/nfsynproxy.c +++ b/utils/nfsynproxy.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#define _GNU_SOURCE #include <stdlib.h> #include <stdbool.h> #include <unistd.h> diff --git a/utils/pf.os b/utils/pf.os index 01fb85be..e285851e 100644 --- a/utils/pf.os +++ b/utils/pf.os @@ -1,5 +1,5 @@ # $FreeBSD: head/etc/pf.os 258865 2013-12-03 04:32:02Z eadler $ -# $OpenBSD: pf.os,v 1.26 2012/08/03 12:25:16 jsg Exp $ +# $OpenBSD: pf.os,v 1.27 2016/09/03 17:08:57 sthen Exp $ # passive OS fingerprinting # ------------------------- # @@ -315,6 +315,9 @@ S22:64:1:52:M*,N,N,S,N,W0: Linux:2.2:ts:Linux 2.2 w/o timestamps 16384:64:1:64:M*,N,N,S,N,W3,N,N,T: OpenBSD:4.9::OpenBSD 4.9 16384:64:0:64:M*,N,N,S,N,W3,N,N,T: OpenBSD:4.9:no-df:OpenBSD 4.9 (scrub no-df) +16384:64:1:64:M*,N,N,S,N,W6,N,N,T: OpenBSD:6.1::OpenBSD 6.1 +16384:64:0:64:M*,N,N,S,N,W6,N,N,T: OpenBSD:6.1:no-df:OpenBSD 6.1 (scrub no-df) + # ----------------- DragonFly BSD ----------------- 57344:64:1:60:M*,N,W0,N,N,T: DragonFly:1.0:A:DragonFly 1.0A diff --git a/xlate-test.py b/xlate-test.py new file mode 100755 index 00000000..dbba1d67 --- /dev/null +++ b/xlate-test.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# encoding: utf-8 + +import os +import sys +import shlex +import argparse +from subprocess import Popen, PIPE + +keywords = ("iptables-translate", "ip6tables-translate") + +if sys.stdout.isatty(): + colors = {"magenta": "\033[95m", "green": "\033[92m", "yellow": "\033[93m", + "red": "\033[91m", "end": "\033[0m"} +else: + colors = {"magenta": "", "green": "", "yellow": "", "red": "", "end": ""} + + +def magenta(string): + return colors["magenta"] + string + colors["end"] + + +def red(string): + return colors["red"] + string + colors["end"] + + +def yellow(string): + return colors["yellow"] + string + colors["end"] + + +def green(string): + return colors["green"] + string + colors["end"] + + +def run_test(name, payload): + test_passed = True + tests = passed = failed = errors = 0 + result = [] + + for line in payload: + if line.startswith(keywords): + tests += 1 + process = Popen(shlex.split(line), stdout=PIPE, stderr=PIPE) + (output, error) = process.communicate() + if process.returncode == 0: + translation = output.decode("utf-8").rstrip(" \n") + expected = next(payload).rstrip(" \n") + if translation != expected: + test_passed = False + failed += 1 + result.append(name + ": " + red("Fail")) + result.append(magenta("src: ") + line.rstrip(" \n")) + result.append(magenta("exp: ") + expected) + result.append(magenta("res: ") + translation + "\n") + test_passed = False + else: + passed += 1 + else: + test_passed = False + errors += 1 + result.append(name + ": " + red("Error: ") + "iptables-translate failure") + result.append(error.decode("utf-8")) + if (passed == tests) and not args.test: + print(name + ": " + green("OK")) + if not test_passed: + print("\n".join(result)) + if args.test: + print("1 test file, %d tests, %d tests passed, %d tests failed, %d errors" % (tests, passed, failed, errors)) + else: + return tests, passed, failed, errors + + +def load_test_files(): + test_files = total_tests = total_passed = total_error = total_failed = 0 + for test in sorted(os.listdir("extensions")): + if test.endswith(".txlate"): + with open("extensions/" + test, "r") as payload: + tests, passed, failed, errors = run_test(test, payload) + test_files += 1 + total_tests += tests + total_passed += passed + total_failed += failed + total_error += errors + + + print("%d test files, %d tests, %d tests passed, %d tests failed, %d errors" % (test_files, total_tests, total_passed, total_failed, total_error)) + +def main(): + if args.test: + if not args.test.endswith(".txlate"): + args.test += ".txlate" + try: + with open(args.test, "r") as payload: + run_test(args.test, payload) + except IOError: + print(red("Error: ") + "test file does not exist") + else: + load_test_files() + + +parser = argparse.ArgumentParser() +parser.add_argument("test", nargs="?", help="run only the specified test file") +args = parser.parse_args() +main() |