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.popov...@gmail.com>
---
 libxtables/xtables.c |   95 +++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 71 insertions(+), 24 deletions(-)

diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 33fc158..5a115ff 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;
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to