diff options
author | Serhey Popovych <serhe.popovych@gmail.com> | 2018-03-07 11:10:43 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2018-04-27 18:56:27 +0200 |
commit | 12a52ff9cc9944345204d3e429dd4414448fbcd2 (patch) | |
tree | 9867a87e5f90e7dbd804e64febf535188f9acf96 /iptables | |
parent | 1197c5e35c16ab9a6be7d6a0c2283a213430ce16 (diff) |
xtables: Fix rules print/save after iptables update
Updating iptables from 1.4.x to 1.6.x brokes rules print/save output
and causes rules load after reboot to fail. Here is example from
iptables-save(8) output after update:
-A CHAIN1 -m set [unsupported revision] -j DROP
-A CHAIN1 -m set [unsupported revision] -j DROP
Similar output could be obtained via iptables -L CHAIN1. While issue
reproduced with xt_set match it is not specific to any match or
target module: it is related on how xtables handles revisions.
In this particular case we have following situation:
1) Kernel supports revisions from 1 to 4.
2) Rules configured with iptables 1.4.x supporting only
revisions from 1 to 3. Choosen highest possible revision 3.
3) Rules printed/saved with iptables 1.6.x supporting revisions
from 1 to 4.
4) Xtables registers matches/targets with highest supported
revision by the kernel. This is 4 in our case after update to
iptables 1.6.x.
5) When printing/saving kernel submits match/target with revision
it is configured (3), while iptables thinks that rules configured
with highest supported (4). That's causes revision mismatch in
during print and "[unsupported revision]" output.
To fix this issue we now store all supported by kernel and xtables
revisions in xt_matches/xt_targets list sorted in descending order.
Introduce helper routines to find match/target with given revision
and use them to find right revision to print submitted by kernel
entry.
Signed-off-by: Serhey Popovych <serhe.popovych@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'iptables')
-rw-r--r-- | iptables/ip6tables.c | 66 | ||||
-rw-r--r-- | iptables/iptables.c | 66 |
2 files changed, 86 insertions, 46 deletions
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c index 49bd006f..6954c252 100644 --- a/iptables/ip6tables.c +++ b/iptables/ip6tables.c @@ -518,19 +518,23 @@ print_match(const struct xt_entry_match *m, const struct ip6t_ip6 *ip, int numeric) { - const struct xtables_match *match = - xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL); + const char *name = m->u.user.name; + const int revision = m->u.user.revision; + struct xtables_match *match, *mt; + match = xtables_find_match(name, XTF_TRY_LOAD, NULL); if (match) { - if (match->print && m->u.user.revision == match->revision) - match->print(ip, m, numeric); + mt = xtables_find_match_revision(name, XTF_TRY_LOAD, + match, revision); + if (mt && mt->print) + mt->print(ip, m, numeric); else if (match->print) printf("%s%s ", match->name, unsupported_rev); else printf("%s ", match->name); } else { - if (m->u.user.name[0]) - printf("UNKNOWN match `%s' ", m->u.user.name); + if (name[0]) + printf("UNKNOWN match `%s' ", name); } /* Don't stop iterating. */ return 0; @@ -544,7 +548,7 @@ print_firewall(const struct ip6t_entry *fw, unsigned int format, struct xtc_handle *const handle) { - const struct xtables_target *target = NULL; + struct xtables_target *target, *tg; const struct xt_entry_target *t; char buf[BUFSIZ]; @@ -651,9 +655,13 @@ print_firewall(const struct ip6t_entry *fw, IP6T_MATCH_ITERATE(fw, print_match, &fw->ipv6, format & FMT_NUMERIC); if (target) { - if (target->print && t->u.user.revision == target->revision) + const int revision = t->u.user.revision; + + tg = xtables_find_target_revision(targname, XTF_TRY_LOAD, + target, revision); + if (tg && tg->print) /* Print the target information. */ - target->print(&fw->ipv6, t, format & FMT_NUMERIC); + tg->print(&fw->ipv6, t, format & FMT_NUMERIC); else if (target->print) printf(" %s%s", target->name, unsupported_rev); } else if (t->u.target_size != sizeof(*t)) @@ -1035,23 +1043,28 @@ static void print_proto(uint16_t proto, int invert) static int print_match_save(const struct xt_entry_match *e, const struct ip6t_ip6 *ip) { - const struct xtables_match *match = - xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL); + const char *name = e->u.user.name; + const int revision = e->u.user.revision; + struct xtables_match *match, *mt, *mt2; + match = xtables_find_match(name, XTF_TRY_LOAD, NULL); if (match) { - printf(" -m %s", - match->alias ? match->alias(e) : e->u.user.name); + mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, + match, revision); + if (!mt2) + mt2 = match; + printf(" -m %s", mt2->alias ? mt2->alias(e) : name); /* some matches don't provide a save function */ - if (match->save && e->u.user.revision == match->revision) - match->save(ip, e); + if (mt && mt->save) + mt->save(ip, e); else if (match->save) printf(unsupported_rev); } else { if (e->u.match_size) { fprintf(stderr, "Can't find library for match `%s'\n", - e->u.user.name); + name); exit(1); } } @@ -1136,18 +1149,25 @@ void print_rule6(const struct ip6t_entry *e, target_name = ip6tc_get_target(e, h); t = ip6t_get_target((struct ip6t_entry *)e); if (t->u.user.name[0]) { - struct xtables_target *target = - xtables_find_target(t->u.user.name, XTF_TRY_LOAD); + const char *name = t->u.user.name; + const int revision = t->u.user.revision; + struct xtables_target *target, *tg, *tg2; + target = xtables_find_target(name, XTF_TRY_LOAD); if (!target) { fprintf(stderr, "Can't find library for target `%s'\n", - t->u.user.name); + name); exit(1); } - printf(" -j %s", target->alias ? target->alias(t) : target_name); - if (target->save && t->u.user.revision == target->revision) - target->save(&e->ipv6, t); + tg = tg2 = xtables_find_target_revision(name, XTF_TRY_LOAD, + target, revision); + if (!tg2) + tg2 = target; + printf(" -j %s", tg2->alias ? tg2->alias(t) : target_name); + + if (tg && tg->save) + tg->save(&e->ipv6, t); else if (target->save) printf(unsupported_rev); else { @@ -1158,7 +1178,7 @@ void print_rule6(const struct ip6t_entry *e, sizeof(struct xt_entry_target)) { fprintf(stderr, "Target `%s' is missing " "save function\n", - t->u.user.name); + name); exit(1); } } diff --git a/iptables/iptables.c b/iptables/iptables.c index 69d19fec..acacf182 100644 --- a/iptables/iptables.c +++ b/iptables/iptables.c @@ -502,19 +502,23 @@ print_match(const struct xt_entry_match *m, const struct ipt_ip *ip, int numeric) { - const struct xtables_match *match = - xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL); + const char *name = m->u.user.name; + const int revision = m->u.user.revision; + struct xtables_match *match, *mt; + match = xtables_find_match(name, XTF_TRY_LOAD, NULL); if (match) { - if (match->print && m->u.user.revision == match->revision) - match->print(ip, m, numeric); + mt = xtables_find_match_revision(name, XTF_TRY_LOAD, + match, revision); + if (mt && mt->print) + mt->print(ip, m, numeric); else if (match->print) printf("%s%s ", match->name, unsupported_rev); else printf("%s ", match->name); } else { - if (m->u.user.name[0]) - printf("UNKNOWN match `%s' ", m->u.user.name); + if (name[0]) + printf("UNKNOWN match `%s' ", name); } /* Don't stop iterating. */ return 0; @@ -528,7 +532,7 @@ print_firewall(const struct ipt_entry *fw, unsigned int format, struct xtc_handle *const handle) { - const struct xtables_target *target = NULL; + struct xtables_target *target, *tg; const struct xt_entry_target *t; uint8_t flags; char buf[BUFSIZ]; @@ -635,9 +639,13 @@ print_firewall(const struct ipt_entry *fw, IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC); if (target) { - if (target->print && t->u.user.revision == target->revision) + const int revision = t->u.user.revision; + + tg = xtables_find_target_revision(targname, XTF_TRY_LOAD, + target, revision); + if (tg && tg->print) /* Print the target information. */ - target->print(&fw->ip, t, format & FMT_NUMERIC); + tg->print(&fw->ip, t, format & FMT_NUMERIC); else if (target->print) printf(" %s%s", target->name, unsupported_rev); } else if (t->u.target_size != sizeof(*t)) @@ -1025,23 +1033,28 @@ print_iface(char letter, const char *iface, const unsigned char *mask, static int print_match_save(const struct xt_entry_match *e, const struct ipt_ip *ip) { - const struct xtables_match *match = - xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL); + const char *name = e->u.user.name; + const int revision = e->u.user.revision; + struct xtables_match *match, *mt, *mt2; + match = xtables_find_match(name, XTF_TRY_LOAD, NULL); if (match) { - printf(" -m %s", - match->alias ? match->alias(e) : e->u.user.name); + mt = mt2 = xtables_find_match_revision(name, XTF_TRY_LOAD, + match, revision); + if (!mt2) + mt2 = match; + printf(" -m %s", mt2->alias ? mt2->alias(e) : name); /* some matches don't provide a save function */ - if (match->save && e->u.user.revision == match->revision) - match->save(ip, e); + if (mt && mt->save) + mt->save(ip, e); else if (match->save) printf(unsupported_rev); } else { if (e->u.match_size) { fprintf(stderr, "Can't find library for match `%s'\n", - e->u.user.name); + name); exit(1); } } @@ -1125,18 +1138,25 @@ void print_rule4(const struct ipt_entry *e, target_name = iptc_get_target(e, h); t = ipt_get_target((struct ipt_entry *)e); if (t->u.user.name[0]) { - const struct xtables_target *target = - xtables_find_target(t->u.user.name, XTF_TRY_LOAD); + const char *name = t->u.user.name; + const int revision = t->u.user.revision; + struct xtables_target *target, *tg, *tg2; + target = xtables_find_target(name, XTF_TRY_LOAD); if (!target) { fprintf(stderr, "Can't find library for target `%s'\n", - t->u.user.name); + name); exit(1); } - printf(" -j %s", target->alias ? target->alias(t) : target_name); - if (target->save && t->u.user.revision == target->revision) - target->save(&e->ip, t); + tg = tg2 = xtables_find_target_revision(name, XTF_TRY_LOAD, + target, revision); + if (!tg2) + tg2 = target; + printf(" -j %s", tg2->alias ? tg2->alias(t) : target_name); + + if (tg && tg->save) + tg->save(&e->ip, t); else if (target->save) printf(unsupported_rev); else { @@ -1147,7 +1167,7 @@ void print_rule4(const struct ipt_entry *e, sizeof(struct xt_entry_target)) { fprintf(stderr, "Target `%s' is missing " "save function\n", - t->u.user.name); + name); exit(1); } } |