summaryrefslogtreecommitdiffstats
path: root/xtables.c
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2010-10-29 18:57:42 +0200
committerPatrick McHardy <kaber@trash.net>2010-10-29 18:57:42 +0200
commit600f38db82548a683775fd89b6e136673e924097 (patch)
treec97526e59daddebe70288aeabb67e702e141e569 /xtables.c
parent81defdb2c3ad0e461f6487dc75abb8d4fc77519b (diff)
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 <fw@strlen.de> Signed-off-by: Jan Engelhardt <jengelh@medozas.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'xtables.c')
-rw-r--r--xtables.c50
1 files changed, 28 insertions, 22 deletions
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;
}