summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/libip6t_ah.c10
-rw-r--r--extensions/libip6t_frag.c12
-rw-r--r--extensions/libip6t_rt.c14
-rw-r--r--extensions/libipt_REDIRECT.c3
-rw-r--r--extensions/libipt_ah.c10
-rw-r--r--extensions/libxt_NFQUEUE.c12
-rw-r--r--extensions/libxt_TCPMSS.man14
-rw-r--r--extensions/libxt_TPROXY.c8
-rw-r--r--extensions/libxt_conntrack.c73
-rw-r--r--extensions/libxt_esp.c10
-rw-r--r--extensions/libxt_hashlimit.man26
-rw-r--r--extensions/libxt_ipvs.c6
-rw-r--r--extensions/libxt_length.c4
-rw-r--r--extensions/libxt_quota.c3
-rw-r--r--extensions/libxt_rateest.c6
-rw-r--r--extensions/libxt_rateest.man71
-rw-r--r--extensions/libxt_time.c38
-rw-r--r--extensions/libxt_time.man45
-rw-r--r--extensions/libxt_u32.c3
-rw-r--r--include/xtables.h.in16
-rw-r--r--ip6tables.8.in5
-rw-r--r--iptables.8.in5
-rw-r--r--xtables.c20
-rw-r--r--xtoptions.c226
24 files changed, 348 insertions, 292 deletions
diff --git a/extensions/libip6t_ah.c b/extensions/libip6t_ah.c
index d30ddfa4..26f81408 100644
--- a/extensions/libip6t_ah.c
+++ b/extensions/libip6t_ah.c
@@ -28,13 +28,6 @@ static const struct xt_option_entry ah_opts[] = {
};
#undef s
-static void ah_init(struct xt_entry_match *m)
-{
- struct ip6t_ah *ahinfo = (struct ip6t_ah *)m->data;
-
- ahinfo->spis[1] = 0xFFFFFFFF;
-}
-
static void ah_parse(struct xt_option_call *cb)
{
struct ip6t_ah *ahinfo = cb->data;
@@ -42,6 +35,8 @@ static void ah_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_AHSPI:
+ if (cb->nvals == 1)
+ ahinfo->spis[1] = ahinfo->spis[0];
if (cb->invert)
ahinfo->invflags |= IP6T_AH_INV_SPI;
break;
@@ -132,7 +127,6 @@ static struct xtables_match ah_mt6_reg = {
.size = XT_ALIGN(sizeof(struct ip6t_ah)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
.help = ah_help,
- .init = ah_init,
.print = ah_print,
.save = ah_save,
.x6_parse = ah_parse,
diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c
index 12794e42..47793860 100644
--- a/extensions/libip6t_frag.c
+++ b/extensions/libip6t_frag.c
@@ -41,19 +41,16 @@ static const struct xt_option_entry frag_opts[] = {
};
#undef s
-static void frag_init(struct xt_entry_match *m)
-{
- struct ip6t_frag *fraginfo = (struct ip6t_frag *)m->data;
-
- fraginfo->ids[1] = 0xFFFFFFFF;
-}
-
static void frag_parse(struct xt_option_call *cb)
{
struct ip6t_frag *fraginfo = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
+ case O_FRAGID:
+ if (cb->nvals == 1)
+ fraginfo->ids[1] = fraginfo->ids[0];
+ break;
case O_FRAGRES:
fraginfo->flags |= IP6T_FRAG_RES;
break;
@@ -160,7 +157,6 @@ static struct xtables_match frag_mt6_reg = {
.size = XT_ALIGN(sizeof(struct ip6t_frag)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_frag)),
.help = frag_help,
- .init = frag_init,
.print = frag_print,
.save = frag_save,
.x6_parse = frag_parse,
diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c
index eb308204..d470488d 100644
--- a/extensions/libip6t_rt.c
+++ b/extensions/libip6t_rt.c
@@ -31,8 +31,8 @@ IP6T_RT_HOPS);
#define s struct ip6t_rt
static const struct xt_option_entry rt_opts[] = {
- {.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32RC,
- .flags = XTOPT_INVERT},
+ {.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32,
+ .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)},
{.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC,
.flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)},
{.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32,
@@ -99,13 +99,6 @@ parse_addresses(const char *addrstr, struct in6_addr *addrp)
return i;
}
-static void rt_init(struct xt_entry_match *m)
-{
- struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data;
-
- rtinfo->segsleft[1] = 0xFFFFFFFF;
-}
-
static void rt_parse(struct xt_option_call *cb)
{
struct ip6t_rt *rtinfo = cb->data;
@@ -118,6 +111,8 @@ static void rt_parse(struct xt_option_call *cb)
rtinfo->flags |= IP6T_RT_TYP;
break;
case O_RT_SEGSLEFT:
+ if (cb->nvals == 1)
+ rtinfo->segsleft[1] = rtinfo->segsleft[0];
if (cb->invert)
rtinfo->invflags |= IP6T_RT_INV_SGS;
rtinfo->flags |= IP6T_RT_SGS;
@@ -250,7 +245,6 @@ static struct xtables_match rt_mt6_reg = {
.size = XT_ALIGN(sizeof(struct ip6t_rt)),
.userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
.help = rt_help,
- .init = rt_init,
.x6_parse = rt_parse,
.print = rt_print,
.save = rt_save,
diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c
index 426a7463..e67360a0 100644
--- a/extensions/libipt_REDIRECT.c
+++ b/extensions/libipt_REDIRECT.c
@@ -23,8 +23,7 @@ static void REDIRECT_help(void)
}
static const struct xt_option_entry REDIRECT_opts[] = {
- {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND},
+ {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING},
{.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
diff --git a/extensions/libipt_ah.c b/extensions/libipt_ah.c
index 53adfd87..8cf167c4 100644
--- a/extensions/libipt_ah.c
+++ b/extensions/libipt_ah.c
@@ -21,18 +21,13 @@ static const struct xt_option_entry ah_opts[] = {
XTOPT_TABLEEND,
};
-static void ah_init(struct xt_entry_match *m)
-{
- struct ipt_ah *ahinfo = (struct ipt_ah *)m->data;
-
- ahinfo->spis[1] = 0xFFFFFFFF;
-}
-
static void ah_parse(struct xt_option_call *cb)
{
struct ipt_ah *ahinfo = cb->data;
xtables_option_parse(cb);
+ if (cb->nvals == 1)
+ ahinfo->spis[1] = ahinfo->spis[0];
if (cb->invert)
ahinfo->invflags |= IPT_AH_INV_SPI;
}
@@ -97,7 +92,6 @@ static struct xtables_match ah_mt_reg = {
.size = XT_ALIGN(sizeof(struct ipt_ah)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_ah)),
.help = ah_help,
- .init = ah_init,
.print = ah_print,
.save = ah_save,
.x6_parse = ah_parse,
diff --git a/extensions/libxt_NFQUEUE.c b/extensions/libxt_NFQUEUE.c
index a86c88a3..e47b586c 100644
--- a/extensions/libxt_NFQUEUE.c
+++ b/extensions/libxt_NFQUEUE.c
@@ -13,6 +13,8 @@ enum {
O_QUEUE_NUM = 0,
O_QUEUE_BALANCE,
O_QUEUE_BYPASS,
+ F_QUEUE_NUM = 1 << O_QUEUE_NUM,
+ F_QUEUE_BALANCE = 1 << O_QUEUE_BALANCE,
};
static void NFQUEUE_help(void)
@@ -41,9 +43,10 @@ static void NFQUEUE_help_v2(void)
#define s struct xt_NFQ_info
static const struct xt_option_entry NFQUEUE_opts[] = {
{.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16,
- .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum)},
+ .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum),
+ .excl = F_QUEUE_BALANCE},
{.name = "queue-balance", .id = O_QUEUE_BALANCE,
- .type = XTTYPE_UINT16RC},
+ .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM},
{.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE},
XTOPT_TABLEEND,
};
@@ -81,14 +84,11 @@ static void NFQUEUE_parse_v2(struct xt_option_call *cb)
{
struct xt_NFQ_info_v2 *info = cb->data;
- xtables_option_parse(cb);
+ NFQUEUE_parse_v1(cb);
switch (cb->entry->id) {
case O_QUEUE_BYPASS:
info->bypass = 1;
break;
- default:
- NFQUEUE_parse_v1(cb);
- break;
}
}
diff --git a/extensions/libxt_TCPMSS.man b/extensions/libxt_TCPMSS.man
index ac8fb4e8..8da8e761 100644
--- a/extensions/libxt_TCPMSS.man
+++ b/extensions/libxt_TCPMSS.man
@@ -11,19 +11,13 @@ packets. The symptoms of this
problem are that everything works fine from your Linux
firewall/router, but machines behind it can never exchange large
packets:
-.PD 0
-.RS 0.1i
-.TP 0.3i
-1)
+.IP 1. 4
Web browsers connect, then hang with no data received.
-.TP
-2)
+.IP 2. 4
Small mail works fine, but large emails hang.
-.TP
-3)
+.IP 3. 4
ssh works fine, but scp hangs after initial handshaking.
-.RE
-.PD
+.PP
Workaround: activate this option and add a rule to your firewall
configuration like:
.IP
diff --git a/extensions/libxt_TPROXY.c b/extensions/libxt_TPROXY.c
index 61646c93..d13ec85f 100644
--- a/extensions/libxt_TPROXY.c
+++ b/extensions/libxt_TPROXY.c
@@ -20,8 +20,8 @@ enum {
#define s struct xt_tproxy_target_info
static const struct xt_option_entry tproxy_tg0_opts[] = {
- {.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT_NE,
- .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, lport)},
+ {.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT,
+ .flags = XTOPT_MAND | XTOPT_NBO | XTOPT_PUT, XTOPT_POINTER(s, lport)},
{.name = "on-ip", .id = P_ADDR, .type = XTTYPE_HOST},
{.name = "tproxy-mark", .id = P_MARK, .type = XTTYPE_MARKMASK32},
XTOPT_TABLEEND,
@@ -29,8 +29,8 @@ static const struct xt_option_entry tproxy_tg0_opts[] = {
#undef s
#define s struct xt_tproxy_target_info_v1
static const struct xt_option_entry tproxy_tg1_opts[] = {
- {.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT_NE,
- .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, lport)},
+ {.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT,
+ .flags = XTOPT_MAND | XTOPT_NBO | XTOPT_PUT, XTOPT_POINTER(s, lport)},
{.name = "on-ip", .id = P_ADDR, .type = XTTYPE_HOST,
.flags = XTOPT_PUT, XTOPT_POINTER(s, laddr)},
{.name = "tproxy-mark", .id = P_MARK, .type = XTTYPE_MARKMASK32},
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index ed0bd939..e1d85755 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -291,69 +291,6 @@ conntrack_ps_statuses(struct xt_conntrack_mtinfo3 *info, const char *arg)
xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
}
-static unsigned long
-parse_expire(const char *s)
-{
- unsigned int len;
-
- if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX))
- xtables_error(PARAMETER_PROBLEM, "expire value invalid: \"%s\"\n", s);
- else
- return len;
-}
-
-/* If a single value is provided, min and max are both set to the value */
-static void
-parse_expires(const char *s, struct xt_conntrack_info *sinfo)
-{
- char *buffer;
- char *cp;
-
- buffer = strdup(s);
- if ((cp = strchr(buffer, ':')) == NULL)
- sinfo->expires_min = sinfo->expires_max =
- parse_expire(buffer);
- else {
- *cp = '\0';
- cp++;
-
- sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
- sinfo->expires_max = cp[0]
- ? parse_expire(cp)
- : (unsigned long)-1;
- }
- free(buffer);
-
- if (sinfo->expires_min > sinfo->expires_max)
- xtables_error(PARAMETER_PROBLEM,
- "expire min. range value `%lu' greater than max. "
- "range value `%lu'", sinfo->expires_min, sinfo->expires_max);
-}
-
-static void
-conntrack_ps_expires(struct xt_conntrack_mtinfo3 *info, const char *s)
-{
- unsigned int min, max;
- char *end;
-
- if (!xtables_strtoui(s, &end, &min, 0, UINT32_MAX))
- xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
- max = min;
- if (*end == ':')
- if (!xtables_strtoui(end + 1, &end, &max, 0, UINT32_MAX))
- xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
- if (*end != '\0')
- xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
-
- if (min > max)
- xtables_error(PARAMETER_PROBLEM,
- "expire min. range value \"%u\" greater than max. "
- "range value \"%u\"", min, max);
-
- info->expires_min = min;
- info->expires_max = max;
-}
-
static void conntrack_parse(struct xt_option_call *cb)
{
struct xt_conntrack_info *sinfo = cb->data;
@@ -408,7 +345,10 @@ static void conntrack_parse(struct xt_option_call *cb)
sinfo->flags |= XT_CONNTRACK_STATUS;
break;
case O_CTEXPIRE:
- parse_expires(cb->arg, sinfo);
+ sinfo->expires_min = cb->val.u32_range[0];
+ sinfo->expires_max = cb->val.u32_range[0];
+ if (cb->nvals >= 2)
+ sinfo->expires_max = cb->val.u32_range[1];
if (cb->invert)
sinfo->invflags |= XT_CONNTRACK_EXPIRES;
sinfo->flags |= XT_CONNTRACK_EXPIRES;
@@ -473,7 +413,10 @@ static void conntrack_mt_parse(struct xt_option_call *cb, uint8_t rev)
info->invert_flags |= XT_CONNTRACK_STATUS;
break;
case O_CTEXPIRE:
- conntrack_ps_expires(info, cb->arg);
+ info->expires_min = cb->val.u32_range[0];
+ info->expires_max = cb->val.u32_range[0];
+ if (cb->nvals >= 2)
+ info->expires_max = cb->val.u32_range[1];
info->match_flags |= XT_CONNTRACK_EXPIRES;
if (cb->invert)
info->invert_flags |= XT_CONNTRACK_EXPIRES;
diff --git a/extensions/libxt_esp.c b/extensions/libxt_esp.c
index e9d7990e..294338b4 100644
--- a/extensions/libxt_esp.c
+++ b/extensions/libxt_esp.c
@@ -21,18 +21,13 @@ static const struct xt_option_entry esp_opts[] = {
XTOPT_TABLEEND,
};
-static void esp_init(struct xt_entry_match *m)
-{
- struct xt_esp *espinfo = (struct xt_esp *)m->data;
-
- espinfo->spis[1] = 0xFFFFFFFF;
-}
-
static void esp_parse(struct xt_option_call *cb)
{
struct xt_esp *espinfo = cb->data;
xtables_option_parse(cb);
+ if (cb->nvals == 1)
+ espinfo->spis[1] = espinfo->spis[0];
if (cb->invert)
espinfo->invflags |= XT_ESP_INV_SPI;
}
@@ -91,7 +86,6 @@ static struct xtables_match esp_match = {
.size = XT_ALIGN(sizeof(struct xt_esp)),
.userspacesize = XT_ALIGN(sizeof(struct xt_esp)),
.help = esp_help,
- .init = esp_init,
.print = esp_print,
.save = esp_save,
.x6_parse = esp_parse,
diff --git a/extensions/libxt_hashlimit.man b/extensions/libxt_hashlimit.man
index e91d0c63..f90577e7 100644
--- a/extensions/libxt_hashlimit.man
+++ b/extensions/libxt_hashlimit.man
@@ -2,16 +2,7 @@
\fBlimit\fP match) for a group of connections using a \fBsingle\fP iptables
rule. Grouping can be done per-hostgroup (source and/or destination address)
and/or per-port. It gives you the ability to express "\fIN\fP packets per time
-quantum per group":
-.TP
-matching on source host
-"1000 packets per second for every host in 192.168.0.0/16"
-.TP
-matching on source port
-"100 packets per second for every service of 192.168.1.1"
-.TP
-matching on subnet
-"10000 packets per minute for every /28 subnet in 10.0.0.0/8"
+quantum per group" (see below for some examples).
.PP
A hash limit option (\fB\-\-hashlimit\-upto\fP, \fB\-\-hashlimit\-above\fP) and
\fB\-\-hashlimit\-name\fP are required.
@@ -57,3 +48,18 @@ After how many milliseconds do hash entries expire.
.TP
\fB\-\-hashlimit\-htable\-gcinterval\fP \fImsec\fP
How many milliseconds between garbage collection intervals.
+.PP
+Examples:
+.TP
+matching on source host
+"1000 packets per second for every host in 192.168.0.0/16" =>
+\-s 192.168.0.0/16 \-\-hashlimit\-mode srcip \-\-hashlimit\-upto 1000/sec
+.TP
+matching on source port
+"100 packets per second for every service of 192.168.1.1" =>
+\-s 192.168.1.1 \-\-hashlimit\-mode srcport \-\-hashlimit\-upto 100/sec
+.TP
+matching on subnet
+"10000 packets per minute for every /28 subnet (groups of 8 addresses)
+in 10.0.0.0/8" =>
+\-s 10.0.0.8 \-\-hashlimit\-mask 28 \-\-hashlimit\-upto 10000/min
diff --git a/extensions/libxt_ipvs.c b/extensions/libxt_ipvs.c
index 88d235f6..46727660 100644
--- a/extensions/libxt_ipvs.c
+++ b/extensions/libxt_ipvs.c
@@ -32,12 +32,14 @@ static const struct xt_option_entry ipvs_mt_opts[] = {
{.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK,
.flags = XTOPT_INVERT},
{.name = "vport", .id = O_VPORT, .type = XTTYPE_PORT,
- .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, vport)},
+ .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(s, vport)},
{.name = "vdir", .id = O_VDIR, .type = XTTYPE_STRING},
{.name = "vmethod", .id = O_VMETHOD, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
{.name = "vportctl", .id = O_VPORTCTL, .type = XTTYPE_PORT,
- .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, vportctl)},
+ .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(s, vportctl)},
XTOPT_TABLEEND,
};
#undef s
diff --git a/extensions/libxt_length.c b/extensions/libxt_length.c
index 4f3a3318..6ea76465 100644
--- a/extensions/libxt_length.c
+++ b/extensions/libxt_length.c
@@ -26,7 +26,9 @@ static void length_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
info->min = cb->val.u16_range[0];
- info->max = (cb->nvals == 2) ? cb->val.u16_range[1] : UINT16_MAX;
+ info->max = cb->val.u16_range[0];
+ if (cb->nvals >= 2)
+ info->max = cb->val.u16_range[1];
if (cb->invert)
info->invert = 1;
}
diff --git a/extensions/libxt_quota.c b/extensions/libxt_quota.c
index 988f404f..ff498da7 100644
--- a/extensions/libxt_quota.c
+++ b/extensions/libxt_quota.c
@@ -13,7 +13,8 @@ enum {
static const struct xt_option_entry quota_opts[] = {
{.name = "quota", .id = O_QUOTA, .type = XTTYPE_UINT64,
- .flags = XTOPT_MAND | XTOPT_INVERT},
+ .flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_quota_info, quota)},
XTOPT_TABLEEND,
};
diff --git a/extensions/libxt_rateest.c b/extensions/libxt_rateest.c
index e70edc67..509b3e31 100644
--- a/extensions/libxt_rateest.c
+++ b/extensions/libxt_rateest.c
@@ -65,11 +65,11 @@ static const struct rate_suffix {
{ "bit", 1. },
{ "Kibit", 1024. },
{ "kbit", 1000. },
- { "mibit", 1024.*1024. },
+ { "Mibit", 1024.*1024. },
{ "mbit", 1000000. },
- { "gibit", 1024.*1024.*1024. },
+ { "Gibit", 1024.*1024.*1024. },
{ "gbit", 1000000000. },
- { "tibit", 1024.*1024.*1024.*1024. },
+ { "Tibit", 1024.*1024.*1024.*1024. },
{ "tbit", 1000000000000. },
{ "Bps", 8. },
{ "KiBps", 8.*1024. },
diff --git a/extensions/libxt_rateest.man b/extensions/libxt_rateest.man
index 75303c50..42a82f32 100644
--- a/extensions/libxt_rateest.man
+++ b/extensions/libxt_rateest.man
@@ -1,34 +1,75 @@
The rate estimator can match on estimated rates as collected by the RATEEST
target. It supports matching on absolute bps/pps values, comparing two rate
estimators and matching on the difference between two rate estimators.
+.PP
+For a better understanding of the available options, these are all possible
+combinations:
+.\" * Absolute:
+.IP \(bu 4
+\fBrateest\fP \fIoperator\fP \fBrateest-bps\fP
+.IP \(bu 4
+\fBrateest\fP \fIoperator\fP \fBrateest-pps\fP
+.\" * Absolute + Delta:
+.IP \(bu 4
+(\fBrateest\fP minus \fBrateest-bps1\fP) \fIoperator\fP \fBrateest-bps2\fP
+.IP \(bu 4
+(\fBrateest\fP minus \fBrateest-pps1\fP) \fIoperator\fP \fBrateest-pps2\fP
+.\" * Relative:
+.IP \(bu 4
+\fBrateest1\fP \fIoperator\fP \fBrateest2\fP \fBrateest-bps\fP(without rate!)
+.IP \(bu 4
+\fBrateest1\fP \fIoperator\fP \fBrateest2\fP \fBrateest-pps\fP(without rate!)
+.\" * Relative + Delta:
+.IP \(bu 4
+(\fBrateest1\fP minus \fBrateest-bps1\fP) \fIoperator\fP
+(\fBrateest2\fP minus \fBrateest-bps2\fP)
+.IP \(bu 4
+(\fBrateest1\fP minus \fBrateest-pps1\fP) \fIoperator\fP
+(\fBrateest2\fP minus \fBrateest-pps2\fP)
+.TP
+\fB\-\-rateest\-delta\fP
+For each estimator (either absolute or relative mode), calculate the difference
+between the estimator-determined flow rate and the static value chosen with the
+BPS/PPS options. If the flow rate is higher than the specified BPS/PPS, 0 will
+be used instead of a negative value. In other words, "max(0, rateest#_rate -
+rateest#_bps)" is used.
+.TP
+[\fB!\fP] \fB\-\-rateest\-lt\fP
+Match if rate is less than given rate/estimator.
+.TP
+[\fB!\fP] \fB\-\-rateest\-gt\fP
+Match if rate is greater than given rate/estimator.
+.TP
+[\fB!\fP] \fB\-\-rateest\-eq\fP
+Match if rate is equal to given rate/estimator.
+.PP
+In the so-called "absolute mode", only one rate estimator is used and compared
+against a static value, while in "relative mode", two rate estimators are
+compared against another.
+.TP
+\fB\-\-rateest\fP \fIname\fP
+Name of the one rate estimator for absolute mode.
.TP
\fB\-\-rateest1\fP \fIname\fP
-Name of the first rate estimator.
.TP
\fB\-\-rateest2\fP \fIname\fP
-Name of the second rate estimator (if difference is to be calculated).
+The names of the two rate estimators for relative mode.
.TP
-\fB\-\-rateest\-delta\fP
-Compare difference(s) to given rate(s)
+\fB\-\-rateest\-bps\fP [\fIvalue\fP]
+.TP
+\fB\-\-rateest\-pps\fP [\fIvalue\fP]
.TP
\fB\-\-rateest\-bps1\fP [\fIvalue\fP]
.TP
\fB\-\-rateest\-bps2\fP [\fIvalue\fP]
-Compare bytes per second.
.TP
\fB\-\-rateest\-pps1\fP [\fIvalue\fP]
.TP
\fB\-\-rateest\-pps2\fP [\fIvalue\fP]
-Compare packets per second.
-.TP
-[\fB!\fP] \fB\-\-rateest\-lt\fP
-Match if rate is less than given rate/estimator.
-.TP
-[\fB!\fP] \fB\-\-rateest\-gt\fP
-Match if rate is greater than given rate/estimator.
-.TP
-[\fB!\fP] \fB\-\-rateest\-eq\fP
-Match if rate is equal to given rate/estimator.
+Compare the estimator(s) by bytes or packets per second, and compare against
+the chosen value. See the above bullet list for which option is to be used in
+which case. A unit suffix may be used - available ones are: bit, [kmgt]bit,
+[KMGT]ibit, Bps, [KMGT]Bps, [KMGT]iBps.
.PP
Example: This is what can be used to route outgoing data connections from an
FTP server over two lines based on the available bandwidth at the time the data
diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c
index b538476c..44c05b8f 100644
--- a/extensions/libxt_time.c
+++ b/extensions/libxt_time.c
@@ -26,6 +26,10 @@ enum {
O_WEEKDAYS,
O_LOCAL_TZ,
O_UTC,
+ O_KERNEL_TZ,
+ F_LOCAL_TZ = 1 << O_LOCAL_TZ,
+ F_UTC = 1 << O_UTC,
+ F_KERNEL_TZ = 1 << O_KERNEL_TZ,
};
static const char *const week_days[] = {
@@ -41,8 +45,12 @@ static const struct xt_option_entry time_opts[] = {
.flags = XTOPT_INVERT},
{.name = "monthdays", .id = O_MONTHDAYS, .type = XTTYPE_STRING,
.flags = XTOPT_INVERT},
- {.name = "localtz", .id = O_LOCAL_TZ, .type = XTTYPE_NONE},
- {.name = "utc", .id = O_UTC, .type = XTTYPE_NONE},
+ {.name = "localtz", .id = O_LOCAL_TZ, .type = XTTYPE_NONE,
+ .excl = F_UTC},
+ {.name = "utc", .id = O_UTC, .type = XTTYPE_NONE,
+ .excl = F_LOCAL_TZ | F_KERNEL_TZ},
+ {.name = "kerneltz", .id = O_KERNEL_TZ, .type = XTTYPE_NONE,
+ .excl = F_UTC},
XTOPT_TABLEEND,
};
@@ -59,7 +67,7 @@ static void time_help(void)
"[!] --weekdays value List of weekdays on which to match, sep. by comma\n"
" (Possible days: Mon,Tue,Wed,Thu,Fri,Sat,Sun or 1 to 7\n"
" Defaults to all weekdays.)\n"
-" --localtz/--utc Time is interpreted as UTC/local time\n");
+" --kerneltz Work with the kernel timezone instead of UTC\n");
}
static void time_init(struct xt_entry_match *m)
@@ -75,9 +83,6 @@ static void time_init(struct xt_entry_match *m)
/* ...and have no date-begin or date-end boundary */
info->date_start = 0;
info->date_stop = INT_MAX;
-
- /* local time is default */
- info->flags |= XT_TIME_LOCAL_TZ;
}
static time_t time_parse_date(const char *s, bool end)
@@ -136,6 +141,12 @@ static time_t time_parse_date(const char *s, bool end)
tm.tm_min = minute;
tm.tm_sec = second;
tm.tm_isdst = 0;
+ /*
+ * Offsetting, if any, is done by xt_time.ko,
+ * so we have to disable it here in userspace.
+ */
+ setenv("TZ", "UTC", true);
+ tzset();
ret = mktime(&tm);
if (ret >= 0)
return ret;
@@ -263,6 +274,12 @@ static void time_parse(struct xt_option_call *cb)
info->daytime_stop = time_parse_minutes(cb->arg);
break;
case O_LOCAL_TZ:
+ fprintf(stderr, "WARNING: --localtz is being replaced by "
+ "--kerneltz, since \"local\" is ambiguous. Note the "
+ "kernel timezone has caveats - "
+ "see manpage for details.\n");
+ /* fallthrough */
+ case O_KERNEL_TZ:
info->flags |= XT_TIME_LOCAL_TZ;
break;
case O_MONTHDAYS:
@@ -275,9 +292,6 @@ static void time_parse(struct xt_option_call *cb)
if (cb->invert)
info->weekdays_match ^= XT_TIME_ALL_WEEKDAYS;
break;
- case O_UTC:
- info->flags &= ~XT_TIME_LOCAL_TZ;
- break;
}
}
@@ -289,7 +303,7 @@ static void time_print_date(time_t date, const char *command)
if (date == 0 || date == LONG_MAX)
return;
- t = localtime(&date);
+ t = gmtime(&date);
if (command != NULL)
/*
* Need a contiguous string (no whitespaces), hence using
@@ -413,8 +427,8 @@ static void time_save(const void *ip, const struct xt_entry_match *match)
}
time_print_date(info->date_start, "--datestart");
time_print_date(info->date_stop, "--datestop");
- if (!(info->flags & XT_TIME_LOCAL_TZ))
- printf(" --utc");
+ if (info->flags & XT_TIME_LOCAL_TZ)
+ printf(" --kerneltz");
}
static struct xtables_match time_match = {
diff --git a/extensions/libxt_time.man b/extensions/libxt_time.man
index 2bceaf66..1d677b94 100644
--- a/extensions/libxt_time.man
+++ b/extensions/libxt_time.man
@@ -1,10 +1,10 @@
This matches if the packet arrival time/date is within a given range. All
-options are optional, but are ANDed when specified.
+options are optional, but are ANDed when specified. All times are interpreted
+as UTC by default.
.TP
\fB\-\-datestart\fP \fIYYYY\fP[\fB\-\fP\fIMM\fP[\fB\-\fP\fIDD\fP[\fBT\fP\fIhh\fP[\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]]]]]
.TP
\fB\-\-datestop\fP \fIYYYY\fP[\fB\-\fP\fIMM\fP[\fB\-\fP\fIDD\fP[\fBT\fP\fIhh\fP[\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]]]]]
-.IP
Only match during the given time, which must be in ISO 8601 "T" notation.
The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07.
.IP
@@ -14,34 +14,51 @@ and 2038-01-19, respectively.
\fB\-\-timestart\fP \fIhh\fP\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]
.TP
\fB\-\-timestop\fP \fIhh\fP\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]
-.IP
Only match during the given daytime. The possible time range is 00:00:00 to
23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted
as base-10.
.TP
[\fB!\fP] \fB\-\-monthdays\fP \fIday\fP[\fB,\fP\fIday\fP...]
-.IP
Only match on the given days of the month. Possible values are \fB1\fP
to \fB31\fP. Note that specifying \fB31\fP will of course not match
on months which do not have a 31st day; the same goes for 28- or 29-day
February.
.TP
[\fB!\fP] \fB\-\-weekdays\fP \fIday\fP[\fB,\fP\fIday\fP...]
-.IP
Only match on the given weekdays. Possible values are \fBMon\fP, \fBTue\fP,
\fBWed\fP, \fBThu\fP, \fBFri\fP, \fBSat\fP, \fBSun\fP, or values from \fB1\fP
to \fB7\fP, respectively. You may also use two-character variants (\fBMo\fP,
\fBTu\fP, etc.).
.TP
-\fB\-\-utc\fP
-.IP
-Interpret the times given for \fB\-\-datestart\fP, \fB\-\-datestop\fP,
-\fB\-\-timestart\fP and \fB\-\-timestop\fP to be UTC.
-.TP
-\fB\-\-localtz\fP
-.IP
-Interpret the times given for \fB\-\-datestart\fP, \fB\-\-datestop\fP,
-\fB\-\-timestart\fP and \fB\-\-timestop\fP to be local kernel time. (Default)
+\fB\-\-kerneltz\fP
+Use the kernel timezone instead of UTC to determine whether a packet meets the
+time regulations.
+.PP
+About kernel timezones: Linux keeps the system time in UTC, and always does so.
+On boot, system time is initialized from a referential time source. Where this
+time source has no timezone information, such as the x86 CMOS RTC, UTC will be
+assumed. If the time source is however not in UTC, userspace should provide the
+correct system time and timezone to the kernel once it has the information.
+.PP
+Local time is a feature on top of the (timezone independent) system time. Each
+process has its own idea of local time, specified via the TZ environment
+variable. The kernel also has its own timezone offset variable. The TZ
+userspace environment variable specifies how the UTC-based system time is
+displayed, e.g. when you run date(1), or what you see on your desktop clock.
+The TZ string may resolve to different offsets at different dates, which is
+what enables the automatic time-jumping in userspace. when DST changes. The
+kernel's timezone offset variable is used when it has to convert between
+non-UTC sources, such as FAT filesystems, to UTC (since the latter is what the
+rest of the system uses).
+.PP
+The caveat with the kernel timezone is that Linux distributions may ignore to
+set the kernel timezone, and instead only set the system time. Even if a
+particular distribution does set the timezone at boot, it is usually does not
+keep the kernel timezone offset - which is what changes on DST - up to date.
+ntpd will not touch the kernel timezone, so running it will not resolve the
+issue. As such, one may encounter a timezone that is always +0000, or one that
+is wrong half of the time of the year. As such, \fBusing \-\-kerneltz is highly
+discouraged.\fP
.PP
EXAMPLES. To match on weekends, use:
.IP
diff --git a/extensions/libxt_u32.c b/extensions/libxt_u32.c
index 9198edca..774d5eac 100644
--- a/extensions/libxt_u32.c
+++ b/extensions/libxt_u32.c
@@ -23,7 +23,8 @@ enum {
};
static const struct xt_option_entry u32_opts[] = {
- {.name = "u32", .id = O_U32, .type = XTTYPE_STRING},
+ {.name = "u32", .id = O_U32, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND},
XTOPT_TABLEEND,
};
diff --git a/include/xtables.h.in b/include/xtables.h.in
index 38c0e5ee..2565dd23 100644
--- a/include/xtables.h.in
+++ b/include/xtables.h.in
@@ -64,10 +64,9 @@ struct in_addr;
* %XTTYPE_HOSTMASK: one host or address, with an optional prefix length
* (ptr: union nf_inet_addr; only host portion is stored)
* %XTTYPE_PROTOCOL: protocol number/name from /etc/protocols (ptr: uint8_t)
- * %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
+ * %XTTYPE_PORT: 16-bit port name or number (supports %XTOPT_NBO)
+ * %XTTYPE_PORTRC: colon-separated port range (names acceptable),
+ * (supports %XTOPT_NBO)
* %XTTYPE_PLEN: prefix length
* %XTTYPE_PLENMASK: prefix length (ptr: union nf_inet_addr)
* %XTTYPE_ETHERMAC: Ethernet MAC address in hex form
@@ -91,9 +90,7 @@ enum xt_option_type {
XTTYPE_HOSTMASK,
XTTYPE_PROTOCOL,
XTTYPE_PORT,
- XTTYPE_PORT_NE,
XTTYPE_PORTRC,
- XTTYPE_PORTRC_NE,
XTTYPE_PLEN,
XTTYPE_PLENMASK,
XTTYPE_ETHERMAC,
@@ -104,12 +101,15 @@ enum xt_option_type {
* %XTOPT_MAND: option is mandatory
* %XTOPT_MULTI: option may be specified multiple times
* %XTOPT_PUT: store value into memory at @ptroff
+ * %XTOPT_NBO: store value in network-byte order
+ * (only certain XTTYPEs recognize this)
*/
enum xt_option_flags {
XTOPT_INVERT = 1 << 0,
XTOPT_MAND = 1 << 1,
XTOPT_MULTI = 1 << 2,
XTOPT_PUT = 1 << 3,
+ XTOPT_NBO = 1 << 4,
};
/**
@@ -408,8 +408,8 @@ extern void xtables_register_matches(struct xtables_match *, unsigned int);
extern void xtables_register_target(struct xtables_target *me);
extern void xtables_register_targets(struct xtables_target *, unsigned int);
-extern bool xtables_strtoul(const char *, char **, unsigned long *,
- unsigned long, unsigned long);
+extern bool xtables_strtoul(const char *, char **, uintmax_t *,
+ uintmax_t, uintmax_t);
extern bool xtables_strtoui(const char *, char **, unsigned int *,
unsigned int, unsigned int);
extern int xtables_service_to_port(const char *name, const char *proto);
diff --git a/ip6tables.8.in b/ip6tables.8.in
index 61d6667e..48ba18e1 100644
--- a/ip6tables.8.in
+++ b/ip6tables.8.in
@@ -243,15 +243,14 @@ add, delete, insert, replace and append commands).
[\fB!\fP] \fB\-p\fP, \fB\-\-protocol\fP \fIprotocol\fP
The protocol of the rule or of the packet to check.
The specified protocol can be one of \fBtcp\fP, \fBudp\fP, \fBudplite\fP,
-\fBicmpv6\fP, \fBesp\fP, \fBmh\fP or \fBall\fP,
+\fBicmpv6\fP, \fBesp\fP, \fBmh\fP or the special keyword "\fBall\fP",
or it can be a numeric value, representing one of these protocols or a
different one. A protocol name from /etc/protocols is also allowed.
But IPv6 extension headers except \fBesp\fP are not allowed.
\fBesp\fP and \fBipv6\-nonext\fP
can be used with Kernel version 2.6.11 or later.
A "!" argument before the protocol inverts the
-test. The number zero is equivalent to \fBall\fP.
-Protocol \fBall\fP
+test. The number zero is equivalent to \fBall\fP. "\fBall\fP"
will match with all protocols and is taken as default when this
option is omitted.
.TP
diff --git a/iptables.8.in b/iptables.8.in
index 110c5994..d09bf7aa 100644
--- a/iptables.8.in
+++ b/iptables.8.in
@@ -246,12 +246,11 @@ add, delete, insert, replace and append commands).
[\fB!\fP] \fB\-p\fP, \fB\-\-protocol\fP \fIprotocol\fP
The protocol of the rule or of the packet to check.
The specified protocol can be one of \fBtcp\fP, \fBudp\fP, \fBudplite\fP,
-\fBicmp\fP, \fBesp\fP, \fBah\fP, \fBsctp\fP or \fBall\fP,
+\fBicmp\fP, \fBesp\fP, \fBah\fP, \fBsctp\fP or the special keyword "\fBall\fP",
or it can be a numeric value, representing one of these protocols or a
different one. A protocol name from /etc/protocols is also allowed.
A "!" argument before the protocol inverts the
-test. The number zero is equivalent to \fBall\fP.
-Protocol \fBall\fP
+test. The number zero is equivalent to \fBall\fP. "\fBall\fP"
will match with all protocols and is taken as default when this
option is omitted.
.TP
diff --git a/xtables.c b/xtables.c
index f10cdb70..acfcf8bd 100644
--- a/xtables.c
+++ b/xtables.c
@@ -15,9 +15,10 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -426,15 +427,20 @@ int xtables_load_ko(const char *modprobe, bool quiet)
* Returns true/false whether number was accepted. On failure, *value has
* undefined contents.
*/
-bool xtables_strtoul(const char *s, char **end, unsigned long *value,
- unsigned long min, unsigned long max)
+bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
+ uintmax_t min, uintmax_t max)
{
- unsigned long v;
+ uintmax_t v;
+ const char *p;
char *my_end;
errno = 0;
- v = strtoul(s, &my_end, 0);
-
+ /* Since strtoul allows leading minus, we have to check for ourself. */
+ for (p = s; isspace(*p); ++p)
+ ;
+ if (*p == '-')
+ return false;
+ v = strtoumax(s, &my_end, 0);
if (my_end == s)
return false;
if (end != NULL)
@@ -454,7 +460,7 @@ bool xtables_strtoul(const char *s, char **end, unsigned long *value,
bool xtables_strtoui(const char *s, char **end, unsigned int *value,
unsigned int min, unsigned int max)
{
- unsigned long v;
+ uintmax_t v;
bool ret;
ret = xtables_strtoul(s, end, &v, min, max);
diff --git a/xtoptions.c b/xtoptions.c
index eb9e4e6b..ac0601f2 100644
--- a/xtoptions.c
+++ b/xtoptions.c
@@ -41,6 +41,31 @@ struct tos_value_mask {
uint8_t value, mask;
};
+static const size_t xtopt_psize[] = {
+ /*
+ * All types not listed here, and thus essentially being initialized to
+ * zero have zero on purpose.
+ */
+ [XTTYPE_UINT8] = sizeof(uint8_t),
+ [XTTYPE_UINT16] = sizeof(uint16_t),
+ [XTTYPE_UINT32] = sizeof(uint32_t),
+ [XTTYPE_UINT64] = sizeof(uint64_t),
+ [XTTYPE_UINT8RC] = sizeof(uint8_t[2]),
+ [XTTYPE_UINT16RC] = sizeof(uint16_t[2]),
+ [XTTYPE_UINT32RC] = sizeof(uint32_t[2]),
+ [XTTYPE_UINT64RC] = sizeof(uint64_t[2]),
+ [XTTYPE_DOUBLE] = sizeof(double),
+ [XTTYPE_STRING] = -1,
+ [XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t),
+ [XTTYPE_HOST] = sizeof(union nf_inet_addr),
+ [XTTYPE_HOSTMASK] = sizeof(union nf_inet_addr),
+ [XTTYPE_PROTOCOL] = sizeof(uint8_t),
+ [XTTYPE_PORT] = sizeof(uint16_t),
+ [XTTYPE_PORTRC] = sizeof(uint16_t[2]),
+ [XTTYPE_PLENMASK] = sizeof(union nf_inet_addr),
+ [XTTYPE_ETHERMAC] = sizeof(uint8_t[6]),
+};
+
/**
* Creates getopt options from the x6-style option map, and assigns each a
* getopt id.
@@ -99,29 +124,66 @@ xtables_options_xfrm(struct option *orig_opts, struct option *oldopts,
}
/**
+ * Give the upper limit for a certain type.
+ */
+static uintmax_t xtopt_max_by_type(enum xt_option_type type)
+{
+ switch (type) {
+ case XTTYPE_UINT8:
+ case XTTYPE_UINT8RC:
+ return UINT8_MAX;
+ case XTTYPE_UINT16:
+ case XTTYPE_UINT16RC:
+ return UINT16_MAX;
+ case XTTYPE_UINT32:
+ case XTTYPE_UINT32RC:
+ return UINT32_MAX;
+ case XTTYPE_UINT64:
+ case XTTYPE_UINT64RC:
+ return UINT64_MAX;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Return the size of a single entity based upon a type - predominantly an
+ * XTTYPE_UINT*RC type.
+ */
+static size_t xtopt_esize_by_type(enum xt_option_type type)
+{
+ switch (type) {
+ case XTTYPE_UINT8RC:
+ return xtopt_psize[XTTYPE_UINT8];
+ case XTTYPE_UINT16RC:
+ return xtopt_psize[XTTYPE_UINT16];
+ case XTTYPE_UINT32RC:
+ return xtopt_psize[XTTYPE_UINT32];
+ case XTTYPE_UINT64RC:
+ return xtopt_psize[XTTYPE_UINT64];
+ default:
+ return xtopt_psize[type];
+ }
+}
+
+/**
* Require a simple integer.
*/
static void xtopt_parse_int(struct xt_option_call *cb)
{
const struct xt_option_entry *entry = cb->entry;
- unsigned long long lmin = 0, lmax = UINT32_MAX;
- unsigned int value;
+ uintmax_t lmin = 0, lmax = xtopt_max_by_type(entry->type);
+ uintmax_t value;
- if (entry->type == XTTYPE_UINT8)
- lmax = UINT8_MAX;
- else if (entry->type == XTTYPE_UINT16)
- lmax = UINT16_MAX;
- else if (entry->type == XTTYPE_UINT64)
- lmax = UINT64_MAX;
if (cb->entry->min != 0)
lmin = cb->entry->min;
if (cb->entry->max != 0)
lmax = cb->entry->max;
- if (!xtables_strtoui(cb->arg, NULL, &value, lmin, lmax))
+ if (!xtables_strtoul(cb->arg, NULL, &value, lmin, lmax))
xt_params->exit_err(PARAMETER_PROBLEM,
"%s: bad value for option \"--%s\", "
- "or out of range (%llu-%llu).\n",
+ "or out of range (%ju-%ju).\n",
cb->ext_name, entry->name, lmin, lmax);
if (entry->type == XTTYPE_UINT8) {
@@ -167,6 +229,48 @@ static void xtopt_parse_float(struct xt_option_call *cb)
}
/**
+ * Copy the parsed value to the appropriate entry in cb->val.
+ */
+static void xtopt_mint_value_to_cb(struct xt_option_call *cb, uintmax_t value)
+{
+ const struct xt_option_entry *entry = cb->entry;
+
+ if (cb->nvals >= ARRAY_SIZE(cb->val.u32_range))
+ return;
+ if (entry->type == XTTYPE_UINT8RC)
+ cb->val.u8_range[cb->nvals] = value;
+ else if (entry->type == XTTYPE_UINT16RC)
+ cb->val.u16_range[cb->nvals] = value;
+ else if (entry->type == XTTYPE_UINT32RC)
+ cb->val.u32_range[cb->nvals] = value;
+ else if (entry->type == XTTYPE_UINT64RC)
+ cb->val.u64_range[cb->nvals] = value;
+}
+
+/**
+ * Copy the parsed value to the data area, using appropriate type access.
+ */
+static void xtopt_mint_value_to_ptr(struct xt_option_call *cb, void **datap,
+ uintmax_t value)
+{
+ const struct xt_option_entry *entry = cb->entry;
+ void *data = *datap;
+
+ if (!(entry->flags & XTOPT_PUT))
+ return;
+ if (entry->type == XTTYPE_UINT8RC)
+ *(uint8_t *)data = value;
+ else if (entry->type == XTTYPE_UINT16RC)
+ *(uint16_t *)data = value;
+ else if (entry->type == XTTYPE_UINT32RC)
+ *(uint32_t *)data = value;
+ else if (entry->type == XTTYPE_UINT64RC)
+ *(uint64_t *)data = value;
+ data += xtopt_esize_by_type(entry->type);
+ *datap = data;
+}
+
+/**
* Multiple integer parse routine.
*
* This function is capable of parsing any number of fields. Only the first
@@ -179,62 +283,46 @@ static void xtopt_parse_mint(struct xt_option_call *cb)
{
const struct xt_option_entry *entry = cb->entry;
const char *arg = cb->arg;
- size_t esize = sizeof(uint32_t);
- char *put = XTOPT_MKPTR(cb);
- unsigned int maxiter, value;
+ size_t esize = xtopt_esize_by_type(entry->type);
+ const uintmax_t lmax = xtopt_max_by_type(entry->type);
+ void *put = XTOPT_MKPTR(cb);
+ unsigned int maxiter;
+ uintmax_t value;
char *end = "";
char sep = ':';
- if (entry->type == XTTYPE_UINT8RC)
- esize = sizeof(uint8_t);
- else if (entry->type == XTTYPE_UINT16RC)
- esize = sizeof(uint16_t);
- else if (entry->type == XTTYPE_UINT64RC)
- esize = sizeof(uint64_t);
maxiter = entry->size / esize;
if (maxiter == 0)
- maxiter = 2; /* ARRAY_SIZE(cb->val.uXX_range) */
+ maxiter = ARRAY_SIZE(cb->val.u32_range);
if (entry->size % esize != 0)
xt_params->exit_err(OTHER_PROBLEM, "%s: memory block does "
"not have proper size\n", __func__);
cb->nvals = 0;
- for (arg = cb->arg; ; arg = end + 1) {
+ for (arg = cb->arg, end = (char *)arg; ; arg = end + 1) {
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 (!xtables_strtoui(arg, &end, &value, 0, UINT32_MAX))
- xt_params->exit_err(PARAMETER_PROBLEM,
- "%s: bad value for option \"--%s\", "
- "or out of range (0-%u).\n",
- cb->ext_name, entry->name, UINT32_MAX);
- if (*end != '\0' && *end != sep)
- xt_params->exit_err(PARAMETER_PROBLEM,
- "%s: Argument to \"--%s\" has unexpected "
- "characters.\n", cb->ext_name, entry->name);
- if (cb->nvals < ARRAY_SIZE(cb->val.u32_range)) {
- if (entry->type == XTTYPE_UINT8RC)
- cb->val.u8_range[cb->nvals] = value;
- else if (entry->type == XTTYPE_UINT16RC)
- cb->val.u16_range[cb->nvals] = value;
- else if (entry->type == XTTYPE_UINT32RC)
- cb->val.u32_range[cb->nvals] = value;
- else if (entry->type == XTTYPE_UINT64RC)
- cb->val.u64_range[cb->nvals] = value;
+ if (*arg == '\0' || *arg == sep) {
+ /* Default range components when field not spec'd. */
+ end = (char *)arg;
+ value = (cb->nvals == 1) ? lmax : 0;
+ } else {
+ if (!xtables_strtoul(arg, &end, &value, 0, lmax))
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "%s: bad value for option \"--%s\" near "
+ "\"%s\", or out of range (0-%ju).\n",
+ cb->ext_name, entry->name, arg, lmax);
+ if (*end != '\0' && *end != sep)
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "%s: Argument to \"--%s\" has "
+ "unexpected characters near \"%s\".\n",
+ cb->ext_name, entry->name, end);
}
+ xtopt_mint_value_to_cb(cb, value);
++cb->nvals;
- if (entry->flags & XTOPT_PUT) {
- if (entry->type == XTTYPE_UINT8RC)
- *(uint8_t *)put = value;
- else if (entry->type == XTTYPE_UINT16RC)
- *(uint16_t *)put = value;
- else if (entry->type == XTTYPE_UINT32RC)
- *(uint32_t *)put = value;
- else if (entry->type == XTTYPE_UINT64RC)
- *(uint64_t *)put = value;
- put += esize;
- }
+ xtopt_mint_value_to_ptr(cb, &put, value);
if (*end == '\0')
break;
}
@@ -509,6 +597,7 @@ static void xtopt_parse_protocol(struct xt_option_call *cb)
*/
static void xtopt_parse_port(struct xt_option_call *cb)
{
+ const struct xt_option_entry *entry = cb->entry;
int ret;
ret = xtables_getportbyname(cb->arg);
@@ -516,10 +605,10 @@ static void xtopt_parse_port(struct xt_option_call *cb)
xt_params->exit_err(PARAMETER_PROBLEM,
"Port \"%s\" does not resolve to anything.\n",
cb->arg);
+ if (entry->flags & XTOPT_NBO)
+ ret = htons(ret);
cb->val.port = ret;
- if (cb->entry->type == XTTYPE_PORT_NE)
- cb->val.port = htons(cb->val.port);
- if (cb->entry->flags & XTOPT_PUT)
+ if (entry->flags & XTOPT_PUT)
*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.port;
}
@@ -561,7 +650,7 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
xt_params->exit_err(PARAMETER_PROBLEM,
"Port \"%s\" does not resolve to "
"anything.\n", arg);
- if (entry->type == XTTYPE_PORTRC_NE)
+ if (entry->flags & XTOPT_NBO)
value = htons(value);
if (cb->nvals < ARRAY_SIZE(cb->val.port_range))
cb->val.port_range[cb->nvals] = value;
@@ -702,41 +791,12 @@ static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_HOSTMASK] = xtopt_parse_hostmask,
[XTTYPE_PROTOCOL] = xtopt_parse_protocol,
[XTTYPE_PORT] = xtopt_parse_port,
- [XTTYPE_PORT_NE] = xtopt_parse_port,
[XTTYPE_PORTRC] = xtopt_parse_mport,
- [XTTYPE_PORTRC_NE] = xtopt_parse_mport,
[XTTYPE_PLEN] = xtopt_parse_plen,
[XTTYPE_PLENMASK] = xtopt_parse_plenmask,
[XTTYPE_ETHERMAC] = xtopt_parse_ethermac,
};
-static const size_t xtopt_psize[] = {
- /*
- * All types not listed here, and thus essentially being initialized to
- * zero have zero on purpose.
- */
- [XTTYPE_UINT8] = sizeof(uint8_t),
- [XTTYPE_UINT16] = sizeof(uint16_t),
- [XTTYPE_UINT32] = sizeof(uint32_t),
- [XTTYPE_UINT64] = sizeof(uint64_t),
- [XTTYPE_UINT8RC] = sizeof(uint8_t[2]),
- [XTTYPE_UINT16RC] = sizeof(uint16_t[2]),
- [XTTYPE_UINT32RC] = sizeof(uint32_t[2]),
- [XTTYPE_UINT64RC] = sizeof(uint64_t[2]),
- [XTTYPE_DOUBLE] = sizeof(double),
- [XTTYPE_STRING] = -1,
- [XTTYPE_SYSLOGLEVEL] = sizeof(uint8_t),
- [XTTYPE_HOST] = sizeof(union nf_inet_addr),
- [XTTYPE_HOSTMASK] = sizeof(union nf_inet_addr),
- [XTTYPE_PROTOCOL] = sizeof(uint8_t),
- [XTTYPE_PORT] = sizeof(uint16_t),
- [XTTYPE_PORT_NE] = sizeof(uint16_t),
- [XTTYPE_PORTRC] = sizeof(uint16_t[2]),
- [XTTYPE_PORTRC_NE] = sizeof(uint16_t[2]),
- [XTTYPE_PLENMASK] = sizeof(union nf_inet_addr),
- [XTTYPE_ETHERMAC] = sizeof(uint8_t[6]),
-};
-
/**
* The master option parsing routine. May be used for the ".x6_parse"
* function pointer in extensions if fully automatic parsing is desired.