summaryrefslogtreecommitdiffstats
path: root/libxtables
diff options
context:
space:
mode:
authorSerhey Popovych <serhe.popovych@gmail.com>2018-03-07 11:10:42 +0200
committerFlorian Westphal <fw@strlen.de>2018-04-27 18:56:26 +0200
commit1197c5e35c16ab9a6be7d6a0c2283a213430ce16 (patch)
tree8c5aad299b1e16698f2c97a56fe5d989fa07a9cf /libxtables
parente3bb24cbaacd308c0f0b7840f092e230f77e9587 (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>
Diffstat (limited to 'libxtables')
-rw-r--r--libxtables/xtables.c95
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;