From 1197c5e35c16ab9a6be7d6a0c2283a213430ce16 Mon Sep 17 00:00:00 2001 From: Serhey Popovych Date: Wed, 7 Mar 2018 11:10:42 +0200 Subject: 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 Signed-off-by: Florian Westphal --- libxtables/xtables.c | 95 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 24 deletions(-) (limited to 'libxtables') 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; -- cgit v1.2.3