From 954b76c317f641b7faf33cc26931d45585cc0dea Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 27 Sep 2012 21:36:35 +0200 Subject: libxtables: consolidate preference logic Alias support will require testing for more conditions, so move the revision comparison code into a separate function where it can be shared between matches and targets. Signed-off-by: Jan Engelhardt --- libxtables/xtables.c | 69 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 16 deletions(-) (limited to 'libxtables/xtables.c') diff --git a/libxtables/xtables.c b/libxtables/xtables.c index d8185796..7f0d3ccb 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -862,14 +862,58 @@ void xtables_register_match(struct xtables_match *me) xtables_pending_matches = me; } +/** + * Compare two actions for their preference + * @a: one action + * @b: another + * + * Like strcmp, returns a negative number if @a is less preferred than @b, + * positive number if @a is more preferred than @b, or zero if equally + * preferred. + */ +static int +xtables_mt_prefer(unsigned int a_rev, unsigned int a_fam, + unsigned int b_rev, unsigned int b_fam) +{ + /* Higher revision ranks higher. */ + if (a_rev < b_rev) + return -1; + if (a_rev > b_rev) + return 1; + + /* NFPROTO_ ranks higher than NFPROTO_UNSPEC. */ + if (a_fam == NFPROTO_UNSPEC && b_fam != NFPROTO_UNSPEC) + return -1; + if (a_fam != NFPROTO_UNSPEC && b_fam == NFPROTO_UNSPEC) + return 1; + + /* Must be the same thing. */ + return 0; +} + +static int xtables_match_prefer(const struct xtables_match *a, + const struct xtables_match *b) +{ + return xtables_mt_prefer(a->revision, a->family, + b->revision, b->family); +} + +static int xtables_target_prefer(const struct xtables_target *a, + const struct xtables_target *b) +{ + return xtables_mt_prefer(a->revision, a->family, + b->revision, b->family); +} + static void xtables_fully_register_pending_match(struct xtables_match *me) { struct xtables_match **i, *old; + int compare; old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); if (old) { - if (old->revision == me->revision && - old->family == me->family) { + compare = xtables_match_prefer(old, me); + if (compare == 0) { fprintf(stderr, "%s: match `%s' already registered.\n", xt_params->program_name, me->name); @@ -877,18 +921,14 @@ static void xtables_fully_register_pending_match(struct xtables_match *me) } /* Now we have two (or more) options, check compatibility. */ - if (compatible_match_revision(old->name, old->revision) - && old->revision > me->revision) + if (compare > 0 && + compatible_match_revision(old->name, old->revision)) return; /* See if new match can be used. */ if (!compatible_match_revision(me->name, me->revision)) return; - /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */ - if (old->revision == me->revision && me->family == AF_UNSPEC) - return; - /* Delete old one. */ for (i = &xtables_matches; *i!=old; i = &(*i)->next); *i = old->next; @@ -962,13 +1002,14 @@ void xtables_register_target(struct xtables_target *me) static void xtables_fully_register_pending_target(struct xtables_target *me) { struct xtables_target *old; + int compare; old = xtables_find_target(me->name, XTF_DURING_LOAD); if (old) { struct xtables_target **i; - if (old->revision == me->revision && - old->family == me->family) { + compare = xtables_target_prefer(old, me); + if (compare == 0) { fprintf(stderr, "%s: target `%s' already registered.\n", xt_params->program_name, me->name); @@ -976,18 +1017,14 @@ static void xtables_fully_register_pending_target(struct xtables_target *me) } /* Now we have two (or more) options, check compatibility. */ - if (compatible_target_revision(old->name, old->revision) - && old->revision > me->revision) + if (compare > 0 && + compatible_target_revision(old->name, old->revision)) return; /* See if new target can be used. */ if (!compatible_target_revision(me->name, me->revision)) return; - /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */ - if (old->revision == me->revision && me->family == AF_UNSPEC) - return; - /* Delete old one. */ for (i = &xtables_targets; *i!=old; i = &(*i)->next); *i = old->next; -- cgit v1.2.3 From cd2f9bdbb7f9b737e5d640aafeb78bcd8e3a7adf Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 4 Sep 2012 05:24:47 +0200 Subject: iptables: support for target aliases This patch allows for target names listed on the command line to be rewritten to new names and revisions. As before, we will pick a revision that is supported by the kernel - now including real_name in the search. This gives us the possibility to test for many action names. Signed-off-by: Jan Engelhardt --- libxtables/xtables.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'libxtables/xtables.c') diff --git a/libxtables/xtables.c b/libxtables/xtables.c index 7f0d3ccb..a2b24c5a 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -872,9 +872,18 @@ void xtables_register_match(struct xtables_match *me) * preferred. */ static int -xtables_mt_prefer(unsigned int a_rev, unsigned int a_fam, - unsigned int b_rev, unsigned int b_fam) +xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam, + bool b_alias, unsigned int b_rev, unsigned int b_fam) { + /* + * Alias ranks higher than no alias. + * (We want the new action to be used whenever possible.) + */ + if (!a_alias && b_alias) + return -1; + if (a_alias && !b_alias) + return 1; + /* Higher revision ranks higher. */ if (a_rev < b_rev) return -1; @@ -894,14 +903,21 @@ xtables_mt_prefer(unsigned int a_rev, unsigned int a_fam, static int xtables_match_prefer(const struct xtables_match *a, const struct xtables_match *b) { - return xtables_mt_prefer(a->revision, a->family, - b->revision, b->family); + return xtables_mt_prefer(false, a->revision, a->family, + false, b->revision, b->family); } static int xtables_target_prefer(const struct xtables_target *a, const struct xtables_target *b) { - return xtables_mt_prefer(a->revision, a->family, + /* + * Note that if x->real_name==NULL, it will be set to x->name in + * xtables_register_*; the direct pointer comparison here is therefore + * legitimate to detect an alias. + */ + return xtables_mt_prefer(a->name != a->real_name, + a->revision, a->family, + b->name != b->real_name, b->revision, b->family); } @@ -985,6 +1001,8 @@ void xtables_register_target(struct xtables_target *me) exit(1); } + if (me->real_name == NULL) + me->real_name = me->name; if (me->x6_options != NULL) xtables_option_metavalidate(me->name, me->x6_options); if (me->extra_opts != NULL) @@ -1018,11 +1036,11 @@ static void xtables_fully_register_pending_target(struct xtables_target *me) /* Now we have two (or more) options, check compatibility. */ if (compare > 0 && - compatible_target_revision(old->name, old->revision)) + compatible_target_revision(old->real_name, old->revision)) return; /* See if new target can be used. */ - if (!compatible_target_revision(me->name, me->revision)) + if (!compatible_target_revision(me->real_name, me->revision)) return; /* Delete old one. */ -- cgit v1.2.3 From c436dad7cfdd80ca4a05ceed556c39babc266f55 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 27 Sep 2012 23:48:25 +0200 Subject: iptables: support for match aliases This patch allows for match names listed on the command line to be rewritten to new names and revisions, like we did for targets before. Signed-off-by: Jan Engelhardt --- libxtables/xtables.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'libxtables/xtables.c') diff --git a/libxtables/xtables.c b/libxtables/xtables.c index a2b24c5a..82c3643b 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -848,6 +848,8 @@ void xtables_register_match(struct xtables_match *me) exit(1); } + if (me->real_name == NULL) + me->real_name = me->name; if (me->x6_options != NULL) xtables_option_metavalidate(me->name, me->x6_options); if (me->extra_opts != NULL) @@ -903,8 +905,10 @@ xtables_mt_prefer(bool a_alias, unsigned int a_rev, unsigned int a_fam, static int xtables_match_prefer(const struct xtables_match *a, const struct xtables_match *b) { - return xtables_mt_prefer(false, a->revision, a->family, - false, b->revision, b->family); + return xtables_mt_prefer(a->name != a->real_name, + a->revision, a->family, + b->name != b->real_name, + b->revision, b->family); } static int xtables_target_prefer(const struct xtables_target *a, @@ -938,11 +942,11 @@ static void xtables_fully_register_pending_match(struct xtables_match *me) /* Now we have two (or more) options, check compatibility. */ if (compare > 0 && - compatible_match_revision(old->name, old->revision)) + compatible_match_revision(old->real_name, old->revision)) return; /* See if new match can be used. */ - if (!compatible_match_revision(me->name, me->revision)) + if (!compatible_match_revision(me->real_name, me->revision)) return; /* Delete old one. */ -- cgit v1.2.3