Code is very similar, join them to reuse parsing code at least. As a side-effect, this enables parsing of service names for ports in DNAT as well as using port number 0 as that's what REDIRECT allows. Signed-off-by: Phil Sutter <phil@xxxxxx> --- Changes since v1: - Fix for segfault when using service name as port due to dereference of uninitialized 'end' variable. - Force numeric ports in ranges' upper boundary, this kills support for names in ranges. - Add more test cases. --- extensions/GNUmakefile.in | 4 +- extensions/libip6t_DNAT.t | 4 + extensions/libip6t_REDIRECT.c | 170 ---------------------------- extensions/libip6t_REDIRECT.t | 6 - extensions/libip6t_REDIRECT.txlate | 5 - extensions/libipt_DNAT.t | 4 + extensions/libipt_REDIRECT.c | 174 ----------------------------- extensions/libipt_REDIRECT.t | 6 - extensions/libipt_REDIRECT.txlate | 5 - extensions/libxt_DNAT.c | 164 ++++++++++++++++++++++++--- extensions/libxt_REDIRECT.t | 16 +++ extensions/libxt_REDIRECT.txlate | 26 +++++ 12 files changed, 204 insertions(+), 380 deletions(-) delete mode 100644 extensions/libip6t_REDIRECT.c delete mode 100644 extensions/libip6t_REDIRECT.t delete mode 100644 extensions/libip6t_REDIRECT.txlate delete mode 100644 extensions/libipt_REDIRECT.c delete mode 100644 extensions/libipt_REDIRECT.t delete mode 100644 extensions/libipt_REDIRECT.txlate create mode 100644 extensions/libxt_REDIRECT.t create mode 100644 extensions/libxt_REDIRECT.txlate diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 956ccb38b2ab9..6dad4e02481bd 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -42,7 +42,7 @@ endif pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c))) @ENABLE_NFTABLES_TRUE@ pfb_build_mod := $(patsubst ${srcdir}/libebt_%.c,%,$(sort $(wildcard ${srcdir}/libebt_*.c))) @ENABLE_NFTABLES_TRUE@ pfa_build_mod := $(patsubst ${srcdir}/libarpt_%.c,%,$(sort $(wildcard ${srcdir}/libarpt_*.c))) -pfx_symlinks := NOTRACK state +pfx_symlinks := NOTRACK state REDIRECT @ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c))) @ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c))) pfx_build_mod := $(filter-out @blacklist_modules@ @blacklist_x_modules@,${pfx_build_mod}) @@ -130,6 +130,8 @@ libxt_NOTRACK.so: libxt_CT.so ln -fs $< $@ libxt_state.so: libxt_conntrack.so ln -fs $< $@ +libxt_REDIRECT.so: libxt_DNAT.so + ln -fs $< $@ # Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD xt_RATEEST_LIBADD = -lm diff --git a/extensions/libip6t_DNAT.t b/extensions/libip6t_DNAT.t index ec7d61f418cfe..e53dfa16a8871 100644 --- a/extensions/libip6t_DNAT.t +++ b/extensions/libip6t_DNAT.t @@ -13,4 +13,8 @@ -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65535;=;OK -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/0;;FAIL -p tcp -j DNAT --to-destination [dead::beef-dead::fee7]:1000-2000/65536;;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:ssh;-p tcp -j DNAT --to-destination [dead::beef]:22;OK +-p tcp -j DNAT --to-destination [dead::beef]:ftp-data;-p tcp -j DNAT --to-destination [dead::beef]:20;OK +-p tcp -j DNAT --to-destination [dead::beef]:echo-ssh;;FAIL +-p tcp -j DNAT --to-destination [dead::beef]:10-20/ftp;-p tcp -j DNAT --to-destination [dead::beef]:10-20/21;OK -j DNAT;;FAIL diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c deleted file mode 100644 index 8e04d2cd33d50..0000000000000 --- a/extensions/libip6t_REDIRECT.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2011 Patrick McHardy <kaber@xxxxxxxxx> - * - * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT - * funded by Astaro. - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv6/ip6_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_PORTS = 0, - O_RANDOM, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, -}; - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports <port>[-<port>]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_range *range) -{ - char *end = ""; - unsigned int port, maxport; - - range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && - (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); - - switch (*end) { - case '\0': - range->min_proto.tcp.port - = range->max_proto.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && - (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) - break; - - if (maxport < port) - break; - - range->min_proto.tcp.port = htons(port); - range->max_proto.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); -} - -static void REDIRECT_parse(struct xt_option_call *cb) -{ - const struct ip6t_entry *entry = cb->xt_entry; - struct nf_nat_range *range = (void *)(*cb->target)->data; - int portok; - - if (entry->ipv6.proto == IPPROTO_TCP - || entry->ipv6.proto == IPPROTO_UDP - || entry->ipv6.proto == IPPROTO_SCTP - || entry->ipv6.proto == IPPROTO_DCCP - || entry->ipv6.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, range); - if (cb->xflags & F_RANDOM) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM: - if (cb->xflags & F_TO_PORTS) - range->flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_range *range = (const void *)target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" redir ports "); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - } -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_range *range = (const void *)target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports "); - printf("%hu", ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - printf("-%hu", ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - } -} - -static int REDIRECT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_range *range = (const void *)params->target->data; - - if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, "redirect to :%hu", - ntohs(range->min_proto.tcp.port)); - if (range->max_proto.tcp.port != range->min_proto.tcp.port) - xt_xlate_add(xl, "-%hu ", - ntohs(range->max_proto.tcp.port)); - if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, " random "); - } - - return 1; -} - -static struct xtables_target redirect_tg_reg = { - .name = "REDIRECT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct nf_nat_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), - .help = REDIRECT_help, - .x6_parse = REDIRECT_parse, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&redirect_tg_reg); -} diff --git a/extensions/libip6t_REDIRECT.t b/extensions/libip6t_REDIRECT.t deleted file mode 100644 index a0fb0ed19a5ea..0000000000000 --- a/extensions/libip6t_REDIRECT.t +++ /dev/null @@ -1,6 +0,0 @@ -:PREROUTING,OUTPUT -*nat --p tcp -j REDIRECT --to-ports 42;=;OK --p udp -j REDIRECT --to-ports 42-1234;=;OK --p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK --j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libip6t_REDIRECT.txlate b/extensions/libip6t_REDIRECT.txlate deleted file mode 100644 index 209f67a4235f9..0000000000000 --- a/extensions/libip6t_REDIRECT.txlate +++ /dev/null @@ -1,5 +0,0 @@ -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/libipt_DNAT.t b/extensions/libipt_DNAT.t index 1c4413b9b3bb5..9007572ae32d3 100644 --- a/extensions/libipt_DNAT.t +++ b/extensions/libipt_DNAT.t @@ -13,4 +13,8 @@ -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65535;=;OK -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/0;;FAIL -p tcp -j DNAT --to-destination 1.1.1.1:1000-2000/65536;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:ssh;-p tcp -j DNAT --to-destination 1.1.1.1:22;OK +-p tcp -j DNAT --to-destination 1.1.1.1:ftp-data;-p tcp -j DNAT --to-destination 1.1.1.1:20;OK +-p tcp -j DNAT --to-destination 1.1.1.1:echo-ssh;;FAIL +-p tcp -j DNAT --to-destination 1.1.1.1:10-20/ftp;-p tcp -j DNAT --to-destination 1.1.1.1:10-20/21;OK -j DNAT;;FAIL diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c deleted file mode 100644 index 7850306f5fe25..0000000000000 --- a/extensions/libipt_REDIRECT.c +++ /dev/null @@ -1,174 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ -#include <linux/netfilter_ipv4/ip_tables.h> -#include <linux/netfilter/nf_nat.h> - -enum { - O_TO_PORTS = 0, - O_RANDOM, - F_TO_PORTS = 1 << O_TO_PORTS, - F_RANDOM = 1 << O_RANDOM, -}; - -static void REDIRECT_help(void) -{ - printf( -"REDIRECT target options:\n" -" --to-ports <port>[-<port>]\n" -" Port (range) to map to.\n" -" [--random]\n"); -} - -static const struct xt_option_entry REDIRECT_opts[] = { - {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, - {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, - XTOPT_TABLEEND, -}; - -static void REDIRECT_init(struct xt_entry_target *t) -{ - struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; - - /* Actually, it's 0, but it's ignored at the moment. */ - mr->rangesize = 1; -} - -/* Parses ports */ -static void -parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) -{ - char *end = ""; - unsigned int port, maxport; - - mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - - if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && - (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); - - switch (*end) { - case '\0': - mr->range[0].min.tcp.port - = mr->range[0].max.tcp.port - = htons(port); - return; - case '-': - if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && - (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) - break; - - if (maxport < port) - break; - - mr->range[0].min.tcp.port = htons(port); - mr->range[0].max.tcp.port = htons(maxport); - return; - default: - break; - } - xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); -} - -static void REDIRECT_parse(struct xt_option_call *cb) -{ - const struct ipt_entry *entry = cb->xt_entry; - struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->data; - int portok; - - if (entry->ip.proto == IPPROTO_TCP - || entry->ip.proto == IPPROTO_UDP - || entry->ip.proto == IPPROTO_SCTP - || entry->ip.proto == IPPROTO_DCCP - || entry->ip.proto == IPPROTO_ICMP) - portok = 1; - else - portok = 0; - - xtables_option_parse(cb); - switch (cb->entry->id) { - case O_TO_PORTS: - if (!portok) - xtables_error(PARAMETER_PROBLEM, - "Need TCP, UDP, SCTP or DCCP with port specification"); - parse_ports(cb->arg, mr); - if (cb->xflags & F_RANDOM) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - case O_RANDOM: - if (cb->xflags & F_TO_PORTS) - mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; - break; - } -} - -static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, - int numeric) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" redir ports "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" random"); - } -} - -static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - printf(" --to-ports "); - printf("%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - printf("-%hu", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - printf(" --random"); - } -} - -static int REDIRECT_xlate(struct xt_xlate *xl, - const struct xt_xlate_tg_params *params) -{ - const struct nf_nat_ipv4_multi_range_compat *mr = - (const void *)params->target->data; - const struct nf_nat_ipv4_range *r = &mr->range[0]; - - if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { - xt_xlate_add(xl, "redirect to :%hu", ntohs(r->min.tcp.port)); - if (r->max.tcp.port != r->min.tcp.port) - xt_xlate_add(xl, "-%hu ", ntohs(r->max.tcp.port)); - if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) - xt_xlate_add(xl, " random "); - } - - return 1; -} - -static struct xtables_target redirect_tg_reg = { - .name = "REDIRECT", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), - .help = REDIRECT_help, - .init = REDIRECT_init, - .x6_parse = REDIRECT_parse, - .print = REDIRECT_print, - .save = REDIRECT_save, - .x6_options = REDIRECT_opts, - .xlate = REDIRECT_xlate, -}; - -void _init(void) -{ - xtables_register_target(&redirect_tg_reg); -} diff --git a/extensions/libipt_REDIRECT.t b/extensions/libipt_REDIRECT.t deleted file mode 100644 index a0fb0ed19a5ea..0000000000000 --- a/extensions/libipt_REDIRECT.t +++ /dev/null @@ -1,6 +0,0 @@ -:PREROUTING,OUTPUT -*nat --p tcp -j REDIRECT --to-ports 42;=;OK --p udp -j REDIRECT --to-ports 42-1234;=;OK --p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK --j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libipt_REDIRECT.txlate b/extensions/libipt_REDIRECT.txlate deleted file mode 100644 index 815bb7714138d..0000000000000 --- a/extensions/libipt_REDIRECT.txlate +++ /dev/null @@ -1,5 +0,0 @@ -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/libxt_DNAT.c b/extensions/libxt_DNAT.c index 7f7c322cb2f9b..5ac8018c12423 100644 --- a/extensions/libxt_DNAT.c +++ b/extensions/libxt_DNAT.c @@ -28,10 +28,12 @@ enum { O_TO_DEST = 0, + O_TO_PORTS, O_RANDOM, O_PERSISTENT, - F_TO_DEST = 1 << O_TO_DEST, - F_RANDOM = 1 << O_RANDOM, + F_TO_DEST = 1 << O_TO_DEST, + F_TO_PORTS = 1 << O_TO_PORTS, + F_RANDOM = 1 << O_RANDOM, }; static void DNAT_help(void) @@ -52,6 +54,15 @@ static void DNAT_help_v2(void) "[--random] [--persistent]\n"); } +static void REDIRECT_help(void) +{ + printf( +"REDIRECT target options:\n" +" --to-ports <port>[-<port>]\n" +" Port (range) to map to.\n" +" [--random]\n"); +} + static const struct xt_option_entry DNAT_opts[] = { {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, .flags = XTOPT_MAND}, @@ -60,6 +71,12 @@ static const struct xt_option_entry DNAT_opts[] = { XTOPT_TABLEEND, }; +static const struct xt_option_entry REDIRECT_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + /* Parses ports */ static void parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) @@ -73,9 +90,13 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; - if (!xtables_strtoui(arg, &end, &port, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); + if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) { + port = xtables_service_to_port(arg, NULL); + if (port == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + end = ""; + } switch (*end) { case '\0': @@ -94,9 +115,9 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) "Garbage after port value: `%s'", end); } - if (!xtables_strtoui(arg, &end, &maxport, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); + /* it is a range, don't allow service names here */ + if (!xtables_strtoui(arg, &end, &maxport, 0, UINT16_MAX)) + xtables_error(PARAMETER_PROBLEM, "Port `%s' not valid", arg); if (maxport < port) /* People are stupid. */ @@ -117,9 +138,12 @@ parse_ports(const char *arg, bool portok, struct nf_nat_range2 *range) "Garbage after port range: `%s'", end); } - if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Port `%s' not valid", arg); + if (!xtables_strtoui(arg, &end, &baseport, 1, UINT16_MAX)) { + baseport = xtables_service_to_port(arg, NULL); + if (baseport == (unsigned)-1) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid", arg); + } range->flags |= NF_NAT_RANGE_PROTO_OFFSET; range->base_proto.tcp.port = htons(baseport); @@ -199,6 +223,9 @@ static void __DNAT_parse(struct xt_option_call *cb, __u16 proto, case O_TO_DEST: parse_to(cb->arg, portok, range, family); break; + case O_TO_PORTS: + parse_ports(cb->arg, portok, range); + break; case O_PERSISTENT: range->flags |= NF_NAT_RANGE_PERSISTENT; break; @@ -217,6 +244,8 @@ static void DNAT_parse(struct xt_option_call *cb) case O_TO_DEST: mr->range->min_ip = range.min_addr.ip; mr->range->max_ip = range.max_addr.ip; + /* fall through */ + case O_TO_PORTS: mr->range->min = range.min_proto; mr->range->max = range.max_proto; /* fall through */ @@ -228,9 +257,11 @@ static void DNAT_parse(struct xt_option_call *cb) static void __DNAT_fcheck(struct xt_fcheck_call *cb, unsigned int *flags) { - static const unsigned int f = F_TO_DEST | F_RANDOM; + static const unsigned int redir_f = F_TO_PORTS | F_RANDOM; + static const unsigned int dnat_f = F_TO_DEST | F_RANDOM; - if ((cb->xflags & f) == f) + if ((cb->xflags & redir_f) == redir_f || + (cb->xflags & dnat_f) == dnat_f) *flags |= NF_NAT_RANGE_PROTO_RANDOM; } @@ -443,6 +474,84 @@ static int DNAT_xlate6_v2(struct xt_xlate *xl, return __DNAT_xlate(xl, (const void *)params->target->data, AF_INET6); } +static void __REDIRECT_print(const struct nf_nat_range2 *range, bool save) +{ + char *range_str = sprint_range(range, AF_INET); + const char *dashdash = save ? "--" : ""; + + if (strlen(range_str)) + /* range_str starts with colon, skip over them */ + printf(" %s %s", save ? "--to-ports" : "redir ports", + range_str + 1); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" %srandom", dashdash); +} + +static int __REDIRECT_xlate(struct xt_xlate *xl, + const struct nf_nat_range2 *range) +{ + char *range_str = sprint_range(range, AF_INET); + + xt_xlate_add(xl, "redirect"); + if (strlen(range_str)) + xt_xlate_add(xl, " to %s", range_str); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + xt_xlate_add(xl, " random"); + + return 1; +} + +static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __REDIRECT_print(&range, false); +} + +static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) +{ + struct nf_nat_range2 range = RANGE2_INIT_FROM_IPV4_MRC(target->data); + + __REDIRECT_print(&range, true); +} + +static int REDIRECT_xlate(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + struct nf_nat_range2 range = + RANGE2_INIT_FROM_IPV4_MRC(params->target->data); + + return __REDIRECT_xlate(xl, &range); +} + +static void REDIRECT_print6(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); + __REDIRECT_print(&range, false); +} + +static void REDIRECT_save6(const void *ip, const struct xt_entry_target *target) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)target->data, sizeof(struct nf_nat_range)); + __REDIRECT_print(&range, true); +} + +static int REDIRECT_xlate6(struct xt_xlate *xl, + const struct xt_xlate_tg_params *params) +{ + struct nf_nat_range2 range = {}; + + memcpy(&range, (const void *)params->target->data, + sizeof(struct nf_nat_range)); + return __REDIRECT_xlate(xl, &range); +} + static struct xtables_target dnat_tg_reg[] = { { .name = "DNAT", @@ -459,6 +568,21 @@ static struct xtables_target dnat_tg_reg[] = { .x6_options = DNAT_opts, .xlate = DNAT_xlate, }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .revision = 0, + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .help = REDIRECT_help, + .print = REDIRECT_print, + .save = REDIRECT_save, + .x6_parse = DNAT_parse, + .x6_fcheck = DNAT_fcheck, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT_xlate, + }, { .name = "DNAT", .version = XTABLES_VERSION, @@ -474,6 +598,20 @@ static struct xtables_target dnat_tg_reg[] = { .x6_options = DNAT_opts, .xlate = DNAT_xlate6, }, + { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = REDIRECT_help, + .print = REDIRECT_print6, + .save = REDIRECT_save6, + .x6_parse = DNAT_parse6, + .x6_fcheck = DNAT_fcheck6, + .x6_options = REDIRECT_opts, + .xlate = REDIRECT_xlate6, + }, { .name = "DNAT", .version = XTABLES_VERSION, diff --git a/extensions/libxt_REDIRECT.t b/extensions/libxt_REDIRECT.t new file mode 100644 index 0000000000000..f607dd0a12c51 --- /dev/null +++ b/extensions/libxt_REDIRECT.t @@ -0,0 +1,16 @@ +:PREROUTING,OUTPUT +*nat +-p tcp -j REDIRECT --to-ports 42;=;OK +-p tcp -j REDIRECT --to-ports 0;=;OK +-p tcp -j REDIRECT --to-ports 65535;=;OK +-p tcp -j REDIRECT --to-ports 65536;;FAIL +-p udp -j REDIRECT --to-ports 0-0;-p udp -j REDIRECT --to-ports 0;OK +-p udp -j REDIRECT --to-ports 512-512;-p udp -j REDIRECT --to-ports 512;OK +-p udp -j REDIRECT --to-ports 42-1234;=;OK +-p tcp -j REDIRECT --to-ports 42-1234 --random;=;OK +-p tcp -j REDIRECT --to-ports 42-1234/567;;FAIL +-p tcp -j REDIRECT --to-ports ssh;-p tcp -j REDIRECT --to-ports 22;OK +-p tcp -j REDIRECT --to-ports ftp-data;-p tcp -j REDIRECT --to-ports 20;OK +-p tcp -j REDIRECT --to-ports ftp-ssh;;FAIL +-p tcp -j REDIRECT --to-ports 10-ssh;;FAIL +-j REDIRECT --to-ports 42;;FAIL diff --git a/extensions/libxt_REDIRECT.txlate b/extensions/libxt_REDIRECT.txlate new file mode 100644 index 0000000000000..2c536495b35a2 --- /dev/null +++ b/extensions/libxt_REDIRECT.txlate @@ -0,0 +1,26 @@ +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT +nft add rule ip nat prerouting tcp dport 80 counter redirect + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 0 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :0 + +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 0-65535 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :0-65535 + +iptables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT --to-ports 10-22 +nft add rule ip nat prerouting tcp dport 80 counter redirect to :10-22 + +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 + +ip6tables-translate -t nat -A prerouting -p tcp --dport 80 -j REDIRECT +nft add rule ip6 nat prerouting tcp dport 80 counter redirect + +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 -- 2.34.1