summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/xtables.h.in6
-rw-r--r--xtoptions.c59
2 files changed, 64 insertions, 1 deletions
diff --git a/include/xtables.h.in b/include/xtables.h.in
index b06ab613..0cd9f9f8 100644
--- a/include/xtables.h.in
+++ b/include/xtables.h.in
@@ -56,6 +56,8 @@ struct in_addr;
* %XTTYPE_ONEHOST: one host or address (union nf_inet_addr)
* %XTTYPE_PORT: 16-bit port name or number
* %XTTYPE_PORT_NE: 16-bit port name or number, stored as network-endian
+ * %XTTYPE_PORTRC: colon-separated port range (names acceptable)
+ * %XTTYPE_PORTRC_NE: same as %XTTYPE_PORTRC, stored in network-endian
*/
enum xt_option_type {
XTTYPE_NONE,
@@ -74,6 +76,8 @@ enum xt_option_type {
XTTYPE_ONEHOST,
XTTYPE_PORT,
XTTYPE_PORT_NE,
+ XTTYPE_PORTRC,
+ XTTYPE_PORTRC_NE,
};
/**
@@ -129,7 +133,7 @@ struct xt_option_call {
uint8_t nvals;
union {
uint8_t u8, u8_range[2], syslog_level;
- uint16_t u16, u16_range[2], port;
+ uint16_t u16, u16_range[2], port, port_range[2];
uint32_t u32, u32_range[2];
uint64_t u64, u64_range[2];
union nf_inet_addr inetaddr;
diff --git a/xtoptions.c b/xtoptions.c
index 69e43e95..5b1df889 100644
--- a/xtoptions.c
+++ b/xtoptions.c
@@ -483,6 +483,61 @@ static void xtopt_parse_port(struct xt_option_call *cb)
*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.port;
}
+static void xtopt_parse_mport(struct xt_option_call *cb)
+{
+ static const size_t esize = sizeof(uint16_t);
+ const struct xt_option_entry *entry = cb->entry;
+ char *lo_arg, *wp_arg, *arg;
+ unsigned int maxiter;
+ int value;
+
+ wp_arg = lo_arg = strdup(cb->arg);
+ if (lo_arg == NULL)
+ xt_params->exit_err(RESOURCE_PROBLEM, "strdup");
+
+ maxiter = entry->size / esize;
+ if (maxiter == 0)
+ maxiter = 2; /* ARRAY_SIZE(cb->val.port_range) */
+ if (entry->size % esize != 0)
+ xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does "
+ "not have proper size\n", __func__);
+
+ cb->val.port_range[0] = 0;
+ cb->val.port_range[1] = UINT16_MAX;
+ cb->nvals = 0;
+
+ while ((arg = strsep(&wp_arg, ":")) != NULL) {
+ if (cb->nvals == maxiter)
+ xt_params->exit_err(PARAMETER_PROBLEM, "%s: Too many "
+ "components for option \"--%s\" (max: %u)\n",
+ cb->ext_name, entry->name, maxiter);
+ if (*arg == '\0') {
+ ++cb->nvals;
+ continue;
+ }
+
+ value = xtables_getportbyname(arg);
+ if (value < 0)
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "Port \"%s\" does not resolve to "
+ "anything.\n", arg);
+ if (entry->type == XTTYPE_PORTRC_NE)
+ value = htons(value);
+ if (cb->nvals < ARRAY_SIZE(cb->val.port_range))
+ cb->val.port_range[cb->nvals] = value;
+ ++cb->nvals;
+ }
+
+ if (cb->nvals == 1) {
+ cb->val.port_range[1] = cb->val.port_range[0];
+ ++cb->nvals;
+ }
+ if (entry->flags & XTOPT_PUT)
+ memcpy(XTOPT_MKPTR(cb), cb->val.port_range, sizeof(uint16_t) *
+ (cb->nvals <= maxiter ? cb->nvals : maxiter));
+ free(lo_arg);
+}
+
static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_UINT8] = xtopt_parse_int,
[XTTYPE_UINT16] = xtopt_parse_int,
@@ -499,6 +554,8 @@ static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_ONEHOST] = xtopt_parse_onehost,
[XTTYPE_PORT] = xtopt_parse_port,
[XTTYPE_PORT_NE] = xtopt_parse_port,
+ [XTTYPE_PORTRC] = xtopt_parse_mport,
+ [XTTYPE_PORTRC_NE] = xtopt_parse_mport,
};
static const size_t xtopt_psize[] = {
@@ -515,6 +572,8 @@ static const size_t xtopt_psize[] = {
[XTTYPE_ONEHOST] = sizeof(union nf_inet_addr),
[XTTYPE_PORT] = sizeof(uint16_t),
[XTTYPE_PORT_NE] = sizeof(uint16_t),
+ [XTTYPE_PORTRC] = sizeof(uint16_t[2]),
+ [XTTYPE_PORTRC_NE] = sizeof(uint16_t[2]),
};
/**