diff options
author | Phil Sutter <phil@nwl.cc> | 2022-03-17 14:42:51 +0100 |
---|---|---|
committer | Phil Sutter <phil@nwl.cc> | 2022-04-08 18:00:42 +0200 |
commit | 72d542b69ae2f780d9c9307231dcc3a2e3bed3b7 (patch) | |
tree | 2c12162c84a5dde3818852cf19c95f651abfe63e /extensions/libxt_DNAT.c | |
parent | 14d77c8aa29a7b361d7830e40a7f75a05b29f717 (diff) |
extensions: Merge REDIRECT into DNAT
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@nwl.cc>
Diffstat (limited to 'extensions/libxt_DNAT.c')
-rw-r--r-- | extensions/libxt_DNAT.c | 164 |
1 files changed, 151 insertions, 13 deletions
diff --git a/extensions/libxt_DNAT.c b/extensions/libxt_DNAT.c index 7f7c322c..5ac8018c 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", @@ -460,6 +569,21 @@ static struct xtables_target dnat_tg_reg[] = { .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, .family = NFPROTO_IPV6, @@ -475,6 +599,20 @@ static struct xtables_target dnat_tg_reg[] = { .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, .family = NFPROTO_IPV4, |