summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/xtables.h.in6
-rw-r--r--xtoptions.c51
2 files changed, 56 insertions, 1 deletions
diff --git a/include/xtables.h.in b/include/xtables.h.in
index d8a31245..a9a9ffad 100644
--- a/include/xtables.h.in
+++ b/include/xtables.h.in
@@ -53,6 +53,8 @@ struct in_addr;
* %XTTYPE_MARKMASK32: 32-bit mark with optional mask
* %XTTYPE_SYSLOGLEVEL: syslog level by name or number
* %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
*/
enum xt_option_type {
XTTYPE_NONE,
@@ -68,6 +70,8 @@ enum xt_option_type {
XTTYPE_MARKMASK32,
XTTYPE_SYSLOGLEVEL,
XTTYPE_ONEHOST,
+ XTTYPE_PORT,
+ XTTYPE_PORT_NE,
};
/**
@@ -123,7 +127,7 @@ struct xt_option_call {
uint8_t nvals;
union {
uint8_t u8, u8_range[2], syslog_level;
- uint16_t u16, u16_range[2];
+ uint16_t u16, u16_range[2], port;
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 e0c3213f..c3cc40e6 100644
--- a/xtoptions.c
+++ b/xtoptions.c
@@ -354,6 +354,53 @@ static void xtopt_parse_onehost(struct xt_option_call *cb)
sizeof(cb->val.inetaddr));
}
+/**
+ * @name: port name, or number as a string (e.g. "http" or "80")
+ *
+ * Resolve a port name to a number. Returns the port number in integral
+ * form on success, or <0 on error. (errno will not be set.)
+ */
+static int xtables_getportbyname(const char *name)
+{
+ struct addrinfo *res = NULL, *p;
+ int ret;
+
+ ret = getaddrinfo(NULL, name, NULL, &res);
+ if (ret < 0)
+ return -1;
+ ret = -1;
+ for (p = res; p != NULL; p = p->ai_next) {
+ if (p->ai_family == AF_INET6) {
+ ret = ((struct sockaddr_in6 *)p->ai_addr)->sin6_port;
+ break;
+ } else if (p->ai_family == AF_INET) {
+ ret = ((struct sockaddr_in *)p->ai_addr)->sin_port;
+ break;
+ }
+ }
+ freeaddrinfo(res);
+ return ntohs(ret);
+}
+
+/**
+ * Validate and parse a port specification and put the result into @cb.
+ */
+static void xtopt_parse_port(struct xt_option_call *cb)
+{
+ int ret;
+
+ ret = xtables_getportbyname(cb->arg);
+ if (ret < 0)
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "Port \"%s\" does not resolve to anything.\n",
+ cb->arg);
+ cb->val.port = ret;
+ if (cb->entry->type == XTTYPE_PORT_NE)
+ cb->val.port = htons(cb->val.port);
+ if (cb->entry->flags & XTOPT_PUT)
+ *(uint16_t *)XTOPT_MKPTR(cb) = cb->val.port;
+}
+
static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_UINT8] = xtopt_parse_int,
[XTTYPE_UINT16] = xtopt_parse_int,
@@ -367,6 +414,8 @@ static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_MARKMASK32] = xtopt_parse_markmask,
[XTTYPE_SYSLOGLEVEL] = xtopt_parse_sysloglevel,
[XTTYPE_ONEHOST] = xtopt_parse_onehost,
+ [XTTYPE_PORT] = xtopt_parse_port,
+ [XTTYPE_PORT_NE] = xtopt_parse_port,
};
static const size_t xtopt_psize[] = {
@@ -381,6 +430,8 @@ static const size_t xtopt_psize[] = {
[XTTYPE_STRING] = -1,
[XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t),
[XTTYPE_ONEHOST] = sizeof(union nf_inet_addr),
+ [XTTYPE_PORT] = sizeof(uint16_t),
+ [XTTYPE_PORT_NE] = sizeof(uint16_t),
};
/**