From 600f38db82548a683775fd89b6e136673e924097 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 29 Oct 2010 18:57:42 +0200 Subject: libxtables: change option precedence order to be intuitive When using `-m mark --mark 2 -m connmark --mark 2`, the user currently gets an error about the (libxt_mark) --mark option being used twice. This is because libxt_connmark's option table does not override any previous options. This patch changes this behavior, since the current behavior does not allow connmark's option to be used at all, which is illogical. Cc: Florian Westphal Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- xtables.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'xtables.c') diff --git a/xtables.c b/xtables.c index 47a0d9cb..7658038c 100644 --- a/xtables.c +++ b/xtables.c @@ -73,44 +73,50 @@ void basic_exit_err(enum xtables_exittype status, const char *msg, ...) exit(status); } - -void xtables_free_opts(int reset_offset) +void xtables_free_opts(int unused) { - if (xt_params->opts != xt_params->orig_opts) { - free(xt_params->opts); - xt_params->opts = xt_params->orig_opts; - if (reset_offset) - xt_params->option_offset = 0; - } + free(xt_params->opts); } -struct option *xtables_merge_options(struct option *oldopts, +struct option *xtables_merge_options(struct option *orig_opts, + struct option *oldopts, const struct option *newopts, unsigned int *option_offset) { - unsigned int num_old, num_new, i; - struct option *merge; + unsigned int num_oold = 0, num_old = 0, num_new = 0, i; + struct option *merge, *mp; if (newopts == NULL) return oldopts; - for (num_old = 0; oldopts[num_old].name; num_old++) ; + for (num_oold = 0; orig_opts[num_oold].name; num_oold++) ; + if (oldopts != NULL) + for (num_old = 0; oldopts[num_old].name; num_old++) ; for (num_new = 0; newopts[num_new].name; num_new++) ; + merge = malloc(sizeof(*mp) * (num_oold + 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_oold); + mp = merge + num_oold; + + /* Second, the new options */ xt_params->option_offset += 256; *option_offset = xt_params->option_offset; + memcpy(mp, newopts, sizeof(*mp) * num_new); - merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); - if (merge == NULL) - return NULL; - memcpy(merge, oldopts, num_old * sizeof(struct option)); - xtables_free_opts(0); /* Release any old options merged */ - for (i = 0; i < num_new; i++) { - merge[num_old + i] = newopts[i]; - merge[num_old + i].val += *option_offset; - } - memset(merge + num_old + num_new, 0, sizeof(struct option)); + for (i = 0; i < num_new; ++i, ++mp) + mp->val += *option_offset; + + /* Third, the old options */ + memcpy(mp, oldopts, sizeof(*mp) * num_old); + mp += num_old; + xtables_free_opts(0); + /* Clear trailing entry */ + memset(mp, 0, sizeof(*mp)); return merge; } -- cgit v1.2.3