summaryrefslogtreecommitdiffstats
path: root/libxtables
diff options
context:
space:
mode:
Diffstat (limited to 'libxtables')
-rw-r--r--libxtables/xtables.c135
-rw-r--r--libxtables/xtoptions.c160
2 files changed, 189 insertions, 106 deletions
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index dc645162..7b370d48 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -111,10 +111,8 @@ void basic_exit_err(enum xtables_exittype status, const char *msg, ...)
void xtables_free_opts(int unused)
{
- if (xt_params->opts != xt_params->orig_opts) {
- free(xt_params->opts);
- xt_params->opts = NULL;
- }
+ free(xt_params->opts);
+ xt_params->opts = NULL;
}
struct option *xtables_merge_options(struct option *orig_opts,
@@ -481,14 +479,9 @@ static char *get_modprobe(void)
char *ret;
int count;
- procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
+ procfile = open(PROC_SYS_MODPROBE, O_RDONLY | O_CLOEXEC);
if (procfile < 0)
return NULL;
- if (fcntl(procfile, F_SETFD, FD_CLOEXEC) == -1) {
- fprintf(stderr, "Could not set close on exec: %s\n",
- strerror(errno));
- exit(1);
- }
ret = malloc(PATH_MAX);
if (ret) {
@@ -585,23 +578,23 @@ int xtables_load_ko(const char *modprobe, bool quiet)
}
/**
- * xtables_strtou{i,l} - string to number conversion
+ * xtables_strtoul_base - string to number conversion
* @s: input string
* @end: like strtoul's "end" pointer
* @value: pointer for result
* @min: minimum accepted value
* @max: maximum accepted value
+ * @base: assumed base of value
*
* If @end is NULL, we assume the caller wants a "strict strtoul", and hence
* "15a" is rejected.
* In either case, the value obtained is compared for min-max compliance.
- * Base is always 0, i.e. autodetect depending on @s.
*
* Returns true/false whether number was accepted. On failure, *value has
* undefined contents.
*/
-bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
- uintmax_t min, uintmax_t max)
+bool xtables_strtoul_base(const char *s, char **end, uintmax_t *value,
+ uintmax_t min, uintmax_t max, unsigned int base)
{
uintmax_t v;
const char *p;
@@ -613,7 +606,7 @@ bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
;
if (*p == '-')
return false;
- v = strtoumax(s, &my_end, 0);
+ v = strtoumax(s, &my_end, base);
if (my_end == s)
return false;
if (end != NULL)
@@ -630,6 +623,12 @@ bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
return false;
}
+bool xtables_strtoul(const char *s, char **end, uintmax_t *value,
+ uintmax_t min, uintmax_t max)
+{
+ return xtables_strtoul_base(s, end, value, min, max, 0);
+}
+
bool xtables_strtoui(const char *s, char **end, unsigned int *value,
unsigned int min, unsigned int max)
{
@@ -776,6 +775,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
bool found = false;
+ bool seen = false;
if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -794,6 +794,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
+ seen = true;
if (!found &&
xtables_fully_register_pending_match(ptr, prev)) {
found = true;
@@ -807,6 +808,11 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
dptr = &((*dptr)->next);
}
+ if (seen && !found)
+ fprintf(stderr,
+ "Warning: Extension %s is not supported, missing kernel module?\n",
+ name);
+
for (ptr = xtables_matches; ptr; ptr = ptr->next) {
if (extension_cmp(name, ptr->name, ptr->family)) {
struct xtables_match *clone;
@@ -899,6 +905,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
struct xtables_target **dptr;
struct xtables_target *ptr;
bool found = false;
+ bool seen = false;
/* Standard target? */
if (strcmp(name, "") == 0
@@ -917,6 +924,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
+ seen = true;
if (!found &&
xtables_fully_register_pending_target(ptr, prev)) {
found = true;
@@ -930,6 +938,11 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
dptr = &((*dptr)->next);
}
+ if (seen && !found)
+ fprintf(stderr,
+ "Warning: Extension %s is not supported, missing kernel module?\n",
+ name);
+
for (ptr = xtables_targets; ptr; ptr = ptr->next) {
if (extension_cmp(name, ptr->name, ptr->family)) {
struct xtables_target *clone;
@@ -1009,7 +1022,7 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
socklen_t s = sizeof(rev);
int max_rev, sockfd;
- sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);
+ sockfd = socket(afinfo->family, SOCK_RAW | SOCK_CLOEXEC, IPPROTO_RAW);
if (sockfd < 0) {
if (errno == EPERM) {
/* revision 0 is always supported. */
@@ -1025,12 +1038,6 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
exit(1);
}
- if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
- fprintf(stderr, "Could not set close on exec: %s\n",
- strerror(errno));
- exit(1);
- }
-
xtables_load_ko(xtables_modprobe_program, true);
strncpy(rev.name, name, XT_EXTENSION_MAXNAMELEN - 1);
@@ -1411,6 +1418,10 @@ void xtables_rule_matches_free(struct xtables_rule_match **matches)
free(matchp->match->m);
matchp->match->m = NULL;
}
+ if (matchp->match->udata_size) {
+ free(matchp->match->udata);
+ matchp->match->udata = NULL;
+ }
if (matchp->match == matchp->match->next) {
free(matchp->match);
matchp->match = NULL;
@@ -1502,11 +1513,9 @@ void xtables_param_act(unsigned int status, const char *p1, ...)
const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
{
- static char buf[16];
- const unsigned char *bytep = (const void *)&addrp->s_addr;
+ static char buf[INET_ADDRSTRLEN];
- sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
- return buf;
+ return inet_ntop(AF_INET, addrp, buf, sizeof(buf));
}
static const char *ipaddr_to_host(const struct in_addr *addr)
@@ -1566,13 +1575,14 @@ int xtables_ipmask_to_cidr(const struct in_addr *mask)
const char *xtables_ipmask_to_numeric(const struct in_addr *mask)
{
- static char buf[20];
+ static char buf[INET_ADDRSTRLEN + 1];
uint32_t cidr;
cidr = xtables_ipmask_to_cidr(mask);
if (cidr == (unsigned int)-1) {
/* mask was not a decent combination of 1's and 0's */
- sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
+ buf[0] = '/';
+ inet_ntop(AF_INET, mask, buf + 1, sizeof(buf) - 1);
return buf;
} else if (cidr == 32) {
/* we don't want to see "/32" */
@@ -1852,9 +1862,8 @@ void xtables_ipparse_any(const char *name, struct in_addr **addrpp,
const char *xtables_ip6addr_to_numeric(const struct in6_addr *addrp)
{
- /* 0000:0000:0000:0000:0000:0000:000.000.000.000
- * 0000:0000:0000:0000:0000:0000:0000:0000 */
- static char buf[50+1];
+ static char buf[INET6_ADDRSTRLEN];
+
return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
}
@@ -1912,12 +1921,12 @@ int xtables_ip6mask_to_cidr(const struct in6_addr *k)
const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
{
- static char buf[50+2];
+ static char buf[INET6_ADDRSTRLEN + 1];
int l = xtables_ip6mask_to_cidr(addrp);
if (l == -1) {
strcpy(buf, "/");
- strcat(buf, xtables_ip6addr_to_numeric(addrp));
+ inet_ntop(AF_INET6, addrp, buf + 1, sizeof(buf) - 1);
return buf;
}
/* we don't want to see "/128" */
@@ -2192,6 +2201,8 @@ const struct xtables_pprot xtables_chain_protos[] = {
{"mobility-header", IPPROTO_MH},
{"ipv6-mh", IPPROTO_MH},
{"mh", IPPROTO_MH},
+ {"dccp", IPPROTO_DCCP},
+ {"ipcomp", IPPROTO_COMP},
{"all", 0},
{NULL},
};
@@ -2476,16 +2487,39 @@ void xt_xlate_free(struct xt_xlate *xl)
free(xl);
}
+static bool isbrace(char c)
+{
+ switch (c) {
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ return true;
+ }
+ return false;
+}
+
static void __xt_xlate_add(struct xt_xlate *xl, enum xt_xlate_type type,
- const char *fmt, va_list ap)
+ bool space, const char *fmt, va_list ap)
{
struct xt_xlate_buf *buf = &xl->buf[type];
+ char tmpbuf[1024] = "";
int len;
- len = vsnprintf(buf->data + buf->off, buf->rem, fmt, ap);
- if (len < 0 || len >= buf->rem)
+ len = vsnprintf(tmpbuf, 1024, fmt, ap);
+ if (len < 0 || len >= buf->rem - 1)
xtables_error(RESOURCE_PROBLEM, "OOM");
+ if (space && buf->off &&
+ !isspace(buf->data[buf->off - 1]) &&
+ (isalnum(tmpbuf[0]) || isbrace(tmpbuf[0]))) {
+ buf->data[buf->off] = ' ';
+ buf->off++;
+ buf->rem--;
+ }
+ sprintf(buf->data + buf->off, "%s", tmpbuf);
buf->rem -= len;
buf->off += len;
}
@@ -2495,7 +2529,16 @@ void xt_xlate_rule_add(struct xt_xlate *xl, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- __xt_xlate_add(xl, XT_XLATE_RULE, fmt, ap);
+ __xt_xlate_add(xl, XT_XLATE_RULE, true, fmt, ap);
+ va_end(ap);
+}
+
+void xt_xlate_rule_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_RULE, false, fmt, ap);
va_end(ap);
}
@@ -2504,7 +2547,16 @@ void xt_xlate_set_add(struct xt_xlate *xl, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- __xt_xlate_add(xl, XT_XLATE_SET, fmt, ap);
+ __xt_xlate_add(xl, XT_XLATE_SET, true, fmt, ap);
+ va_end(ap);
+}
+
+void xt_xlate_set_add_nospc(struct xt_xlate *xl, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __xt_xlate_add(xl, XT_XLATE_SET, false, fmt, ap);
va_end(ap);
}
@@ -2531,7 +2583,12 @@ uint8_t xt_xlate_get_family(struct xt_xlate *xl)
const char *xt_xlate_get(struct xt_xlate *xl)
{
- return xl->buf[XT_XLATE_RULE].data;
+ struct xt_xlate_buf *buf = &xl->buf[XT_XLATE_RULE];
+
+ while (buf->off && isspace(buf->data[buf->off - 1]))
+ buf->data[--buf->off] = '\0';
+
+ return buf->data;
}
const char *xt_xlate_set_get(struct xt_xlate *xl)
diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c
index 8174a560..774d0ee6 100644
--- a/libxtables/xtoptions.c
+++ b/libxtables/xtoptions.c
@@ -57,7 +57,6 @@ static const size_t xtopt_psize[] = {
[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]),
@@ -66,6 +65,20 @@ static const size_t xtopt_psize[] = {
};
/**
+ * Return a sanitized afinfo->family value, covering for NFPROTO_ARP
+ */
+static uint8_t afinfo_family(void)
+{
+ switch (afinfo->family) {
+ case NFPROTO_ARP:
+ case NFPROTO_BRIDGE:
+ return NFPROTO_IPV4;
+ default:
+ return afinfo->family;
+ }
+}
+
+/**
* Creates getopt options from the x6-style option map, and assigns each a
* getopt id.
*/
@@ -73,56 +86,22 @@ struct option *
xtables_options_xfrm(struct option *orig_opts, struct option *oldopts,
const struct xt_option_entry *entry, unsigned int *offset)
{
- unsigned int num_orig, num_old = 0, num_new, i;
+ int num_new, i;
struct option *merge, *mp;
- if (entry == NULL)
- return oldopts;
- for (num_orig = 0; orig_opts[num_orig].name != NULL; ++num_orig)
- ;
- if (oldopts != NULL)
- for (num_old = 0; oldopts[num_old].name != NULL; ++num_old)
- ;
for (num_new = 0; entry[num_new].name != NULL; ++num_new)
;
- /*
- * Since @oldopts also has @orig_opts already (and does so at the
- * start), skip these entries.
- */
- if (oldopts != NULL) {
- oldopts += num_orig;
- num_old -= num_orig;
- }
-
- merge = malloc(sizeof(*mp) * (num_orig + num_old + num_new + 1));
- if (merge == NULL)
- return NULL;
-
- /* Let the base options -[ADI...] have precedence over everything */
- memcpy(merge, orig_opts, sizeof(*mp) * num_orig);
- mp = merge + num_orig;
-
- /* Second, the new options */
- xt_params->option_offset += XT_OPTION_OFFSET_SCALE;
- *offset = xt_params->option_offset;
-
- for (i = 0; i < num_new; ++i, ++mp, ++entry) {
- mp->name = entry->name;
- mp->has_arg = entry->type != XTTYPE_NONE;
- mp->flag = NULL;
- mp->val = entry->id + *offset;
+ mp = xtables_calloc(num_new + 1, sizeof(*mp));
+ for (i = 0; i < num_new; i++) {
+ mp[i].name = entry[i].name;
+ mp[i].has_arg = entry[i].type != XTTYPE_NONE;
+ mp[i].val = entry[i].id;
}
- /* Third, the old options */
- if (oldopts != NULL) {
- memcpy(mp, oldopts, sizeof(*mp) * num_old);
- mp += num_old;
- }
- xtables_free_opts(0);
+ merge = xtables_merge_options(orig_opts, oldopts, mp, offset);
- /* Clear trailing entry */
- memset(mp, 0, sizeof(*mp));
+ free(mp);
return merge;
}
@@ -169,6 +148,14 @@ static size_t xtopt_esize_by_type(enum xt_option_type type)
}
}
+static uint64_t htonll(uint64_t val)
+{
+ uint32_t high = val >> 32;
+ uint32_t low = val & UINT32_MAX;
+
+ return (uint64_t)htonl(low) << 32 | htonl(high);
+}
+
/**
* Require a simple integer.
*/
@@ -183,7 +170,8 @@ static void xtopt_parse_int(struct xt_option_call *cb)
if (cb->entry->max != 0)
lmax = cb->entry->max;
- if (!xtables_strtoul(cb->arg, NULL, &value, lmin, lmax))
+ if (!xtables_strtoul_base(cb->arg, NULL, &value,
+ lmin, lmax, cb->entry->base))
xt_params->exit_err(PARAMETER_PROBLEM,
"%s: bad value for option \"--%s\", "
"or out of range (%ju-%ju).\n",
@@ -195,14 +183,20 @@ static void xtopt_parse_int(struct xt_option_call *cb)
*(uint8_t *)XTOPT_MKPTR(cb) = cb->val.u8;
} else if (entry->type == XTTYPE_UINT16) {
cb->val.u16 = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u16 = htons(cb->val.u16);
if (entry->flags & XTOPT_PUT)
*(uint16_t *)XTOPT_MKPTR(cb) = cb->val.u16;
} else if (entry->type == XTTYPE_UINT32) {
cb->val.u32 = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u32 = htonl(cb->val.u32);
if (entry->flags & XTOPT_PUT)
*(uint32_t *)XTOPT_MKPTR(cb) = cb->val.u32;
} else if (entry->type == XTTYPE_UINT64) {
cb->val.u64 = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u64 = htonll(cb->val.u64);
if (entry->flags & XTOPT_PUT)
*(uint64_t *)XTOPT_MKPTR(cb) = cb->val.u64;
}
@@ -237,17 +231,25 @@ static void xtopt_parse_float(struct xt_option_call *cb)
static void xtopt_mint_value_to_cb(struct xt_option_call *cb, uintmax_t value)
{
const struct xt_option_entry *entry = cb->entry;
+ uint8_t i = cb->nvals;
- if (cb->nvals >= ARRAY_SIZE(cb->val.u32_range))
+ if (i >= 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;
+ if (entry->type == XTTYPE_UINT8RC) {
+ cb->val.u8_range[i] = value;
+ } else if (entry->type == XTTYPE_UINT16RC) {
+ cb->val.u16_range[i] = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u16_range[i] = htons(cb->val.u16_range[i]);
+ } else if (entry->type == XTTYPE_UINT32RC) {
+ cb->val.u32_range[i] = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u32_range[i] = htonl(cb->val.u32_range[i]);
+ } else if (entry->type == XTTYPE_UINT64RC) {
+ cb->val.u64_range[i] = value;
+ if (entry->flags & XTOPT_NBO)
+ cb->val.u64_range[i] = htonll(cb->val.u64_range[i]);
+ }
}
/**
@@ -287,13 +289,16 @@ static void xtopt_parse_mint(struct xt_option_call *cb)
const struct xt_option_entry *entry = cb->entry;
const char *arg;
size_t esize = xtopt_esize_by_type(entry->type);
- const uintmax_t lmax = xtopt_max_by_type(entry->type);
+ uintmax_t lmax = xtopt_max_by_type(entry->type);
+ uintmax_t value, lmin = entry->min;
void *put = XTOPT_MKPTR(cb);
unsigned int maxiter;
- uintmax_t value;
char *end = "";
char sep = ':';
+ if (entry->max && entry->max < lmax)
+ lmax = entry->max;
+
maxiter = entry->size / esize;
if (maxiter == 0)
maxiter = ARRAY_SIZE(cb->val.u32_range);
@@ -310,18 +315,19 @@ static void xtopt_parse_mint(struct xt_option_call *cb)
if (*arg == '\0' || *arg == sep) {
/* Default range components when field not spec'd. */
end = (char *)arg;
- value = (cb->nvals == 1) ? lmax : 0;
+ value = (cb->nvals == 1) ? lmax : lmin;
} else {
- if (!xtables_strtoul(arg, &end, &value, 0, lmax))
+ if (!xtables_strtoul(arg, &end, &value, lmin, 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);
+ "\"%s\", or out of range (%ju-%ju).\n",
+ cb->ext_name, entry->name, arg, lmin, 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);
+ lmin = value;
}
xtopt_mint_value_to_cb(cb, value);
++cb->nvals;
@@ -496,7 +502,7 @@ static socklen_t xtables_sa_hostlen(unsigned int afproto)
*/
static void xtopt_parse_host(struct xt_option_call *cb)
{
- struct addrinfo hints = {.ai_family = afinfo->family};
+ struct addrinfo hints = {.ai_family = afinfo_family()};
unsigned int adcount = 0;
struct addrinfo *res, *p;
int ret;
@@ -507,7 +513,7 @@ static void xtopt_parse_host(struct xt_option_call *cb)
"getaddrinfo: %s\n", gai_strerror(ret));
memset(&cb->val.hmask, 0xFF, sizeof(cb->val.hmask));
- cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
+ cb->val.hlen = (afinfo_family() == NFPROTO_IPV4) ? 32 : 128;
for (p = res; p != NULL; p = p->ai_next) {
if (adcount == 0) {
@@ -601,7 +607,7 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
const struct xt_option_entry *entry = cb->entry;
char *lo_arg, *wp_arg, *arg;
unsigned int maxiter;
- int value;
+ int value, prev = 0;
wp_arg = lo_arg = xtables_strdup(cb->arg);
@@ -631,6 +637,11 @@ 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 (value < prev)
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "Port range %d-%d is negative.\n",
+ prev, value);
+ prev = value;
if (entry->flags & XTOPT_NBO)
value = htons(value);
if (cb->nvals < ARRAY_SIZE(cb->val.port_range))
@@ -650,7 +661,7 @@ static void xtopt_parse_mport(struct xt_option_call *cb)
static int xtopt_parse_mask(struct xt_option_call *cb)
{
- struct addrinfo hints = {.ai_family = afinfo->family,
+ struct addrinfo hints = {.ai_family = afinfo_family(),
.ai_flags = AI_NUMERICHOST };
struct addrinfo *res;
int ret;
@@ -662,7 +673,7 @@ static int xtopt_parse_mask(struct xt_option_call *cb)
memcpy(&cb->val.hmask, xtables_sa_host(res->ai_addr, res->ai_family),
xtables_sa_hostlen(res->ai_family));
- switch(afinfo->family) {
+ switch(afinfo_family()) {
case AF_INET:
cb->val.hlen = xtables_ipmask_to_cidr(&cb->val.hmask.in);
break;
@@ -684,7 +695,7 @@ static void xtopt_parse_plen(struct xt_option_call *cb)
const struct xt_option_entry *entry = cb->entry;
unsigned int prefix_len = 128; /* happiness is a warm gcc */
- cb->val.hlen = (afinfo->family == NFPROTO_IPV4) ? 32 : 128;
+ cb->val.hlen = (afinfo_family() == NFPROTO_IPV4) ? 32 : 128;
if (!xtables_strtoui(cb->arg, NULL, &prefix_len, 0, cb->val.hlen)) {
/* Is this mask expressed in full format? e.g. 255.255.255.0 */
if (xtopt_parse_mask(cb))
@@ -711,6 +722,10 @@ static void xtopt_parse_plenmask(struct xt_option_call *cb)
xtopt_parse_plen(cb);
+ /* may not be convertible to CIDR notation */
+ if (cb->val.hlen == (uint8_t)-1)
+ goto out_put;
+
memset(mask, 0xFF, sizeof(union nf_inet_addr));
/* This shifting is AF-independent. */
if (cb->val.hlen == 0) {
@@ -731,6 +746,7 @@ static void xtopt_parse_plenmask(struct xt_option_call *cb)
mask[1] = htonl(mask[1]);
mask[2] = htonl(mask[2]);
mask[3] = htonl(mask[3]);
+out_put:
if (entry->flags & XTOPT_PUT)
memcpy(XTOPT_MKPTR(cb), mask, sizeof(union nf_inet_addr));
}
@@ -785,6 +801,15 @@ static void xtopt_parse_ethermac(struct xt_option_call *cb)
xt_params->exit_err(PARAMETER_PROBLEM, "Invalid MAC address specified.");
}
+static void xtopt_parse_ethermacmask(struct xt_option_call *cb)
+{
+ memset(cb->val.ethermacmask, 0xff, ETH_ALEN);
+ if (xtables_parse_mac_and_mask(cb->arg, cb->val.ethermac,
+ cb->val.ethermacmask))
+ xt_params->exit_err(PARAMETER_PROBLEM,
+ "Invalid MAC/mask address specified.");
+}
+
static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_UINT8] = xtopt_parse_int,
[XTTYPE_UINT16] = xtopt_parse_int,
@@ -807,6 +832,7 @@ static void (*const xtopt_subparse[])(struct xt_option_call *) = {
[XTTYPE_PLEN] = xtopt_parse_plen,
[XTTYPE_PLENMASK] = xtopt_parse_plenmask,
[XTTYPE_ETHERMAC] = xtopt_parse_ethermac,
+ [XTTYPE_ETHERMACMASK]= xtopt_parse_ethermacmask,
};
/**
@@ -924,7 +950,7 @@ void xtables_option_tpcall(unsigned int c, char **argv, bool invert,
cb.entry = xtables_option_lookup(t->x6_options, c);
if (cb.entry == NULL)
xtables_error(OTHER_PROBLEM,
- "Extension does not know id %u\n", c);
+ "Extension does not know id %u", c);
cb.arg = optarg;
cb.invert = invert;
cb.ext_name = t->name;
@@ -960,7 +986,7 @@ void xtables_option_mpcall(unsigned int c, char **argv, bool invert,
cb.entry = xtables_option_lookup(m->x6_options, c);
if (cb.entry == NULL)
xtables_error(OTHER_PROBLEM,
- "Extension does not know id %u\n", c);
+ "Extension does not know id %u", c);
cb.arg = optarg;
cb.invert = invert;
cb.ext_name = m->name;