diff options
author | Serhey Popovych <serhe.popovych@gmail.com> | 2018-03-07 11:10:42 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2018-04-27 18:56:26 +0200 |
commit | 1197c5e35c16ab9a6be7d6a0c2283a213430ce16 (patch) | |
tree | 8c5aad299b1e16698f2c97a56fe5d989fa07a9cf | |
parent | e3bb24cbaacd308c0f0b7840f092e230f77e9587 (diff) |
xtables: Register all match/target revisions supported by us and kernel
Keep the order of matches by appending them; keep order between
revisions of same match from most to least recent. All of this
keeps xtables_find_match() happy to find most recent supported
by kernel revision in the given order.
Apply the same for targets, except prepend targets; order between
revisions preserved too.
All this needed to fix nasty bug related to iptables package update
and broken print/save output.
After this change all supported revisions of match/target stored
in corresponding list with following pattern:
xt_matches xt_targets
========== ==========
m1 m2 m3 mN tN t1 t2 t3
+-----+--+---+---~~~---+ +---~~~---+---+----+--+
|43210|10|210|revisions| |revisions|210|3210|10|
+-----+--+---+---~~~---+ +---~~~---+---+----+--+
Where new [m]atches added to the list tail and new [t]argets added
to the list head to preserve previous behaviour. Multiple revisions
of single match/target type are grouped together and sorted in
descending order. Both this ensures xtables_find_match() and
xtables_find_target() behaviour remains the same after change: find
highest supported match/target revision given by it's name.
Signed-off-by: Serhey Popovych <serhe.popovych@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
-rw-r--r-- | libxtables/xtables.c | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 857da8a6..ebdcc512 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -963,7 +963,7 @@ static int xtables_target_prefer(const struct xtables_target *a, static bool xtables_fully_register_pending_match(struct xtables_match *me) { - struct xtables_match **i, *old; + struct xtables_match **i, *old, *pos = NULL; const char *rn; int compare; @@ -973,7 +973,7 @@ static bool xtables_fully_register_pending_match(struct xtables_match *me) return false; old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); - if (old) { + while (old) { compare = xtables_match_prefer(old, me); if (compare == 0) { fprintf(stderr, @@ -984,18 +984,41 @@ static bool xtables_fully_register_pending_match(struct xtables_match *me) /* Now we have two (or more) options, check compatibility. */ rn = (old->real_name != NULL) ? old->real_name : old->name; - if (compare > 0 && - compatible_match_revision(rn, old->revision)) - return true; + if (compare > 0) { + /* Kernel tells old isn't compatible anymore??? */ + if (!compatible_match_revision(rn, old->revision)) { + /* Delete old one. */ + for (i = &xtables_matches; *i != old;) + i = &(*i)->next; + *i = old->next; + } + pos = old; + old = old->next; + if (!old) + break; + if (!extension_cmp(me->name, old->name, old->family)) + break; + continue; + } - /* Delete old one. */ - for (i = &xtables_matches; *i!=old; i = &(*i)->next); - *i = old->next; + /* Found right old */ + pos = old; + break; + } + + if (!pos) { + /* Append to list. */ + for (i = &xtables_matches; *i; i = &(*i)->next); + } else if (compare < 0) { + /* Prepend it */ + for (i = &xtables_matches; *i != pos; i = &(*i)->next); + } else if (compare > 0) { + /* Append it */ + i = &pos->next; + pos = pos->next; } - /* Append to list. */ - for (i = &xtables_matches; *i; i = &(*i)->next); - me->next = NULL; + me->next = pos; *i = me; me->m = NULL; @@ -1069,7 +1092,7 @@ void xtables_register_target(struct xtables_target *me) static bool xtables_fully_register_pending_target(struct xtables_target *me) { - struct xtables_target *old; + struct xtables_target **i, *old, *pos = NULL; const char *rn; int compare; @@ -1081,9 +1104,7 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me) } old = xtables_find_target(me->name, XTF_DURING_LOAD); - if (old) { - struct xtables_target **i; - + while (old) { compare = xtables_target_prefer(old, me); if (compare == 0) { fprintf(stderr, @@ -1094,18 +1115,44 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me) /* Now we have two (or more) options, check compatibility. */ rn = (old->real_name != NULL) ? old->real_name : old->name; - if (compare > 0 && - compatible_target_revision(rn, old->revision)) - return true; + if (compare > 0) { + /* Kernel tells old isn't compatible anymore??? */ + if (!compatible_target_revision(rn, old->revision)) { + /* Delete old one. */ + for (i = &xtables_targets; *i != old;) + i = &(*i)->next; + *i = old->next; + } + pos = old; + old = old->next; + if (!old) + break; + if (!extension_cmp(me->name, old->name, old->family)) + break; + continue; + } - /* Delete old one. */ - for (i = &xtables_targets; *i!=old; i = &(*i)->next); - *i = old->next; + /* Found right old */ + pos = old; + break; } - /* Prepend to list. */ - me->next = xtables_targets; - xtables_targets = me; + if (!pos) { + /* Prepend to list. */ + i = &xtables_targets; + pos = xtables_targets; + } else if (compare < 0) { + /* Prepend it */ + for (i = &xtables_targets; *i != pos; i = &(*i)->next); + } else if (compare > 0) { + /* Append it */ + i = &pos->next; + pos = pos->next; + } + + me->next = pos; + *i = me; + me->t = NULL; me->tflags = 0; |