diff options
Diffstat (limited to 'libxtables')
-rw-r--r-- | libxtables/xtables.c | 135 | ||||
-rw-r--r-- | libxtables/xtoptions.c | 160 |
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; |