From 51b720ce21368ab8e6a60cb51358dac969a90f3d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Thu, 28 Jan 2021 16:10:49 +0000 Subject: [PATCH] import iptables-1.8.4-17.el8 --- ...sure-extensions-register-in-revision.patch | 128 ++++++++++ ...plify-pending-extension-registration.patch | 241 ++++++++++++++++++ ...ter-multiple-extensions-in-ascending.patch | 52 ++++ ...est-for-fixed-extension-registration.patch | 53 ++++ ...ipt_icmp-Fix-translation-of-type-any.patch | 52 ++++ ...libxt_CT-add-translation-for-NOTRACK.patch | 66 +++++ ...mand-name-in-ip6tables-error-message.patch | 45 ++++ ...l-Merge-and-extend-return-codes-test.patch | 206 +++++++++++++++ ...sions-dccp-Fix-for-DCCP-type-INVALID.patch | 177 +++++++++++++ SPECS/iptables.spec | 22 +- 10 files changed, 1041 insertions(+), 1 deletion(-) create mode 100644 SOURCES/0035-libxtables-Make-sure-extensions-register-in-revision.patch create mode 100644 SOURCES/0036-libxtables-Simplify-pending-extension-registration.patch create mode 100644 SOURCES/0037-libxtables-Register-multiple-extensions-in-ascending.patch create mode 100644 SOURCES/0038-tests-shell-Test-for-fixed-extension-registration.patch create mode 100644 SOURCES/0039-extensions-libipt_icmp-Fix-translation-of-type-any.patch create mode 100644 SOURCES/0040-extensions-libxt_CT-add-translation-for-NOTRACK.patch create mode 100644 SOURCES/0041-nft-Fix-command-name-in-ip6tables-error-message.patch create mode 100644 SOURCES/0042-tests-shell-Merge-and-extend-return-codes-test.patch create mode 100644 SOURCES/0043-extensions-dccp-Fix-for-DCCP-type-INVALID.patch diff --git a/SOURCES/0035-libxtables-Make-sure-extensions-register-in-revision.patch b/SOURCES/0035-libxtables-Make-sure-extensions-register-in-revision.patch new file mode 100644 index 0000000..9ab85d2 --- /dev/null +++ b/SOURCES/0035-libxtables-Make-sure-extensions-register-in-revision.patch @@ -0,0 +1,128 @@ +From e6eede725bbd395fb8b385aec4d0a32ce99e842c Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Mon, 21 Sep 2020 13:42:06 +0200 +Subject: [PATCH] libxtables: Make sure extensions register in revision order + +Insert extensions into pending lists in ordered fashion: Group by +extension name (and, for matches, family) and order groups by descending +revision number. + +This allows to simplify the later full registration considerably. Since +that involves kernel compatibility checks, the extra cycles here pay off +eventually. + +Signed-off-by: Phil Sutter +(cherry picked from commit b3ac87038f4e45141831d9ab485a2f627daba3f1) +Signed-off-by: Phil Sutter +--- + libxtables/xtables.c | 71 +++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 64 insertions(+), 7 deletions(-) + +diff --git a/libxtables/xtables.c b/libxtables/xtables.c +index 777c2b08e9896..13139d7f8ad62 100644 +--- a/libxtables/xtables.c ++++ b/libxtables/xtables.c +@@ -902,8 +902,14 @@ static void xtables_check_options(const char *name, const struct option *opt) + } + } + ++static int xtables_match_prefer(const struct xtables_match *a, ++ const struct xtables_match *b); ++ + void xtables_register_match(struct xtables_match *me) + { ++ struct xtables_match **pos; ++ bool seen_myself = false; ++ + if (me->next) { + fprintf(stderr, "%s: match \"%s\" already registered\n", + xt_params->program_name, me->name); +@@ -955,10 +961,34 @@ void xtables_register_match(struct xtables_match *me) + if (me->extra_opts != NULL) + xtables_check_options(me->name, me->extra_opts); + +- +- /* place on linked list of matches pending full registration */ +- me->next = xtables_pending_matches; +- xtables_pending_matches = me; ++ /* order into linked list of matches pending full registration */ ++ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) { ++ /* group by name and family */ ++ if (strcmp(me->name, (*pos)->name) || ++ me->family != (*pos)->family) { ++ if (seen_myself) ++ break; /* end of own group, append to it */ ++ continue; ++ } ++ /* found own group */ ++ seen_myself = true; ++ if (xtables_match_prefer(me, *pos) >= 0) ++ break; /* put preferred items first in group */ ++ } ++ /* if own group was not found, prepend item */ ++ if (!*pos && !seen_myself) ++ pos = &xtables_pending_matches; ++ ++ me->next = *pos; ++ *pos = me; ++#ifdef DEBUG ++ printf("%s: inserted match %s (family %d, revision %d):\n", ++ __func__, me->name, me->family, me->revision); ++ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) { ++ printf("%s:\tmatch %s (family %d, revision %d)\n", __func__, ++ (*pos)->name, (*pos)->family, (*pos)->revision); ++ } ++#endif + } + + /** +@@ -1097,6 +1127,9 @@ void xtables_register_matches(struct xtables_match *match, unsigned int n) + + void xtables_register_target(struct xtables_target *me) + { ++ struct xtables_target **pos; ++ bool seen_myself = false; ++ + if (me->next) { + fprintf(stderr, "%s: target \"%s\" already registered\n", + xt_params->program_name, me->name); +@@ -1152,9 +1185,33 @@ void xtables_register_target(struct xtables_target *me) + if (me->family != afinfo->family && me->family != AF_UNSPEC) + return; + +- /* place on linked list of targets pending full registration */ +- me->next = xtables_pending_targets; +- xtables_pending_targets = me; ++ /* order into linked list of targets pending full registration */ ++ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) { ++ /* group by name */ ++ if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) { ++ if (seen_myself) ++ break; /* end of own group, append to it */ ++ continue; ++ } ++ /* found own group */ ++ seen_myself = true; ++ if (xtables_target_prefer(me, *pos) >= 0) ++ break; /* put preferred items first in group */ ++ } ++ /* if own group was not found, prepend item */ ++ if (!*pos && !seen_myself) ++ pos = &xtables_pending_targets; ++ ++ me->next = *pos; ++ *pos = me; ++#ifdef DEBUG ++ printf("%s: inserted target %s (family %d, revision %d):\n", ++ __func__, me->name, me->family, me->revision); ++ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) { ++ printf("%s:\ttarget %s (family %d, revision %d)\n", __func__, ++ (*pos)->name, (*pos)->family, (*pos)->revision); ++ } ++#endif + } + + static bool xtables_fully_register_pending_target(struct xtables_target *me) +-- +2.28.0 + diff --git a/SOURCES/0036-libxtables-Simplify-pending-extension-registration.patch b/SOURCES/0036-libxtables-Simplify-pending-extension-registration.patch new file mode 100644 index 0000000..9b527a5 --- /dev/null +++ b/SOURCES/0036-libxtables-Simplify-pending-extension-registration.patch @@ -0,0 +1,241 @@ +From 1a842fb1cfb3b36f3081aee37c5fdd4a897d77d5 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 18 Sep 2020 18:48:14 +0200 +Subject: [PATCH] libxtables: Simplify pending extension registration + +Assuming that pending extensions are sorted by first name and family, +then descending revision, the decision where to insert a newly +registered extension may be simplified by memorizing the previous +registration (which obviously is of same name and family and higher +revision). + +As a side-effect, fix for unsupported old extension revisions lingering +in pending extension list forever and being retried with every use of +the given extension. Any revision being rejected by the kernel may +safely be dropped iff a previous (read: higher) revision was accepted +already. + +Yet another side-effect of this change is the removal of an unwanted +recursion by xtables_fully_register_pending_*() into itself via +xtables_find_*(). + +Signed-off-by: Phil Sutter +(cherry picked from commit a1eaaceb0460b338294e40bdd5bc5186320a478c) +Signed-off-by: Phil Sutter +--- + libxtables/xtables.c | 128 +++++++++++-------------------------------- + 1 file changed, 33 insertions(+), 95 deletions(-) + +diff --git a/libxtables/xtables.c b/libxtables/xtables.c +index 13139d7f8ad62..409128333e0e6 100644 +--- a/libxtables/xtables.c ++++ b/libxtables/xtables.c +@@ -203,8 +203,10 @@ struct xtables_match *xtables_matches; + struct xtables_target *xtables_targets; + + /* Fully register a match/target which was previously partially registered. */ +-static bool xtables_fully_register_pending_match(struct xtables_match *me); +-static bool xtables_fully_register_pending_target(struct xtables_target *me); ++static bool xtables_fully_register_pending_match(struct xtables_match *me, ++ struct xtables_match *prev); ++static bool xtables_fully_register_pending_target(struct xtables_target *me, ++ struct xtables_target *prev); + + void xtables_init(void) + { +@@ -616,6 +618,7 @@ struct xtables_match * + xtables_find_match(const char *name, enum xtables_tryload tryload, + struct xtables_rule_match **matches) + { ++ struct xtables_match *prev = NULL; + struct xtables_match **dptr; + struct xtables_match *ptr; + const char *icmp6 = "icmp6"; +@@ -637,8 +640,12 @@ xtables_find_match(const char *name, enum xtables_tryload tryload, + if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { + ptr = *dptr; + *dptr = (*dptr)->next; +- if (xtables_fully_register_pending_match(ptr)) ++ if (xtables_fully_register_pending_match(ptr, prev)) { ++ prev = ptr; + continue; ++ } else if (prev) { ++ continue; ++ } + *dptr = ptr; + } + dptr = &((*dptr)->next); +@@ -732,6 +739,7 @@ xtables_find_match_revision(const char *name, enum xtables_tryload tryload, + struct xtables_target * + xtables_find_target(const char *name, enum xtables_tryload tryload) + { ++ struct xtables_target *prev = NULL; + struct xtables_target **dptr; + struct xtables_target *ptr; + +@@ -748,8 +756,12 @@ xtables_find_target(const char *name, enum xtables_tryload tryload) + if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) { + ptr = *dptr; + *dptr = (*dptr)->next; +- if (xtables_fully_register_pending_target(ptr)) ++ if (xtables_fully_register_pending_target(ptr, prev)) { ++ prev = ptr; + continue; ++ } else if (prev) { ++ continue; ++ } + *dptr = ptr; + } + dptr = &((*dptr)->next); +@@ -1052,64 +1064,27 @@ static int xtables_target_prefer(const struct xtables_target *a, + b->revision, b->family); + } + +-static bool xtables_fully_register_pending_match(struct xtables_match *me) ++static bool xtables_fully_register_pending_match(struct xtables_match *me, ++ struct xtables_match *prev) + { +- struct xtables_match **i, *old, *pos = NULL; ++ struct xtables_match **i; + const char *rn; +- int compare; + + /* See if new match can be used. */ + rn = (me->real_name != NULL) ? me->real_name : me->name; + if (!compatible_match_revision(rn, me->revision)) + return false; + +- old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); +- while (old) { +- compare = xtables_match_prefer(old, me); +- if (compare == 0) { +- fprintf(stderr, +- "%s: match `%s' already registered.\n", +- xt_params->program_name, me->name); +- exit(1); +- } +- +- /* Now we have two (or more) options, check compatibility. */ +- rn = (old->real_name != NULL) ? old->real_name : old->name; +- 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; +- } +- +- /* Found right old */ +- pos = old; +- break; +- } +- +- if (!pos) { ++ if (!prev) { + /* 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) { ++ } else { + /* Append it */ +- i = &pos->next; +- pos = pos->next; ++ i = &prev->next; ++ prev = prev->next; + } + +- me->next = pos; ++ me->next = prev; + *i = me; + + me->m = NULL; +@@ -1214,11 +1189,11 @@ void xtables_register_target(struct xtables_target *me) + #endif + } + +-static bool xtables_fully_register_pending_target(struct xtables_target *me) ++static bool xtables_fully_register_pending_target(struct xtables_target *me, ++ struct xtables_target *prev) + { +- struct xtables_target **i, *old, *pos = NULL; ++ struct xtables_target **i; + const char *rn; +- int compare; + + if (strcmp(me->name, "standard") != 0) { + /* See if new target can be used. */ +@@ -1227,54 +1202,17 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me) + return false; + } + +- old = xtables_find_target(me->name, XTF_DURING_LOAD); +- while (old) { +- compare = xtables_target_prefer(old, me); +- if (compare == 0) { +- fprintf(stderr, +- "%s: target `%s' already registered.\n", +- xt_params->program_name, me->name); +- exit(1); +- } +- +- /* Now we have two (or more) options, check compatibility. */ +- rn = (old->real_name != NULL) ? old->real_name : old->name; +- 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; +- } +- +- /* Found right old */ +- pos = old; +- break; +- } +- +- if (!pos) { ++ if (!prev) { + /* 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) { ++ prev = xtables_targets; ++ } else { + /* Append it */ +- i = &pos->next; +- pos = pos->next; ++ i = &prev->next; ++ prev = prev->next; + } + +- me->next = pos; ++ me->next = prev; + *i = me; + + me->t = NULL; +-- +2.28.0 + diff --git a/SOURCES/0037-libxtables-Register-multiple-extensions-in-ascending.patch b/SOURCES/0037-libxtables-Register-multiple-extensions-in-ascending.patch new file mode 100644 index 0000000..1146305 --- /dev/null +++ b/SOURCES/0037-libxtables-Register-multiple-extensions-in-ascending.patch @@ -0,0 +1,52 @@ +From cfcafd3638cdc06a8b4a1d267e58b5ad1e35922c Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 22 Sep 2020 20:01:15 +0200 +Subject: [PATCH] libxtables: Register multiple extensions in ascending order + +The newly introduced ordered insert algorithm in +xtables_register_{match,target}() works best if extensions of same name +are passed in ascending revisions. Since this is the case in about all +extensions' arrays, iterate over them from beginning to end. + +Signed-off-by: Phil Sutter +(cherry picked from commit b5f1a3beac1d1f2b96c8be8ebec450f5ea758090) +Signed-off-by: Phil Sutter +--- + libxtables/xtables.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/libxtables/xtables.c b/libxtables/xtables.c +index 409128333e0e6..28ffffedd8147 100644 +--- a/libxtables/xtables.c ++++ b/libxtables/xtables.c +@@ -1095,9 +1095,10 @@ static bool xtables_fully_register_pending_match(struct xtables_match *me, + + void xtables_register_matches(struct xtables_match *match, unsigned int n) + { +- do { +- xtables_register_match(&match[--n]); +- } while (n > 0); ++ int i; ++ ++ for (i = 0; i < n; i++) ++ xtables_register_match(&match[i]); + } + + void xtables_register_target(struct xtables_target *me) +@@ -1223,9 +1224,10 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me, + + void xtables_register_targets(struct xtables_target *target, unsigned int n) + { +- do { +- xtables_register_target(&target[--n]); +- } while (n > 0); ++ int i; ++ ++ for (i = 0; i < n; i++) ++ xtables_register_target(&target[i]); + } + + /* receives a list of xtables_rule_match, release them */ +-- +2.28.0 + diff --git a/SOURCES/0038-tests-shell-Test-for-fixed-extension-registration.patch b/SOURCES/0038-tests-shell-Test-for-fixed-extension-registration.patch new file mode 100644 index 0000000..7a5cca6 --- /dev/null +++ b/SOURCES/0038-tests-shell-Test-for-fixed-extension-registration.patch @@ -0,0 +1,53 @@ +From f5185f4efad409fc7ec4ae05267b642ee4103a6c Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 4 Dec 2020 17:44:51 +0100 +Subject: [PATCH] tests/shell: Test for fixed extension registration + +Use strace to look at iptables-restore behaviour with typically +problematic input (conntrack revision 0 is no longer supported by +current kernels) to make sure the fix in commit a1eaaceb0460b +("libxtables: Simplify pending extension registration") is still +effective. + +Signed-off-by: Phil Sutter +(cherry picked from commit 93d0c97e8b6713f51ba679e01a1338d4f9076e7c) +Signed-off-by: Phil Sutter +--- + .../0017-pointless-compat-checks_0 | 25 +++++++++++++++++++ + 1 file changed, 25 insertions(+) + create mode 100755 iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 + +diff --git a/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 +new file mode 100755 +index 0000000000000..cf73de32df409 +--- /dev/null ++++ b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 +@@ -0,0 +1,25 @@ ++#!/bin/bash ++ ++# A bug in extension registration would leave unsupported older extension ++# revisions in pending list and get compatibility checked again for each rule ++# using them. With SELinux enabled, the resulting socket() call per rule leads ++# to significant slowdown (~50% performance in worst cases). ++ ++set -e ++ ++strace --version >/dev/null || { echo "skip for missing strace"; exit 0; } ++ ++RULESET="$( ++ echo "*filter" ++ for ((i = 0; i < 100; i++)); do ++ echo "-A FORWARD -m conntrack --ctstate NEW" ++ done ++ echo "COMMIT" ++)" ++ ++cmd="$XT_MULTI iptables-restore" ++socketcount=$(strace -esocket $cmd <<< "$RULESET" 2>&1 | wc -l) ++ ++# unpatched iptables-restore would open 111 sockets, ++# patched only 12 but keep a certain margin for future changes ++[[ $socketcount -lt 20 ]] +-- +2.28.0 + diff --git a/SOURCES/0039-extensions-libipt_icmp-Fix-translation-of-type-any.patch b/SOURCES/0039-extensions-libipt_icmp-Fix-translation-of-type-any.patch new file mode 100644 index 0000000..c1c430d --- /dev/null +++ b/SOURCES/0039-extensions-libipt_icmp-Fix-translation-of-type-any.patch @@ -0,0 +1,52 @@ +From 6adcdca2aaf8cba6ee452c88f41ad8695bebdcfc Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Tue, 6 Oct 2020 19:07:19 +0200 +Subject: [PATCH] extensions: libipt_icmp: Fix translation of type 'any' + +By itself, '-m icmp --icmp-type any' is a noop, it matches any icmp +types. Yet nft_ipv4_xlate() does not emit an 'ip protocol' match if +there's an extension with same name present in the rule. Luckily, legacy +iptables demands icmp match to be prepended by '-p icmp', so we can +assume this is present and just emit the 'ip protocol' match from icmp +xlate callback. + +Fixes: aa158ca0fda65 ("extensions: libipt_icmp: Add translation to nft") +Signed-off-by: Phil Sutter +Reviewed-by: Florian Westphal +(cherry picked from commit ad4b17b98bbedf93d2182a4dc9a37e9cf3adfe1b) +Signed-off-by: Phil Sutter +--- + extensions/libipt_icmp.c | 5 +++++ + extensions/libipt_icmp.txlate | 3 +++ + 2 files changed, 8 insertions(+) + +diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c +index e76257c54708c..e5e236613f39f 100644 +--- a/extensions/libipt_icmp.c ++++ b/extensions/libipt_icmp.c +@@ -256,6 +256,11 @@ static int icmp_xlate(struct xt_xlate *xl, + if (!type_xlate_print(xl, info->type, info->code[0], + info->code[1])) + return 0; ++ } else { ++ /* '-m icmp --icmp-type any' is a noop by itself, ++ * but it eats a (mandatory) previous '-p icmp' so ++ * emit it here */ ++ xt_xlate_add(xl, "ip protocol icmp"); + } + return 1; + } +diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate +index 434f8cc4eb1ae..a2aec8e26df75 100644 +--- a/extensions/libipt_icmp.txlate ++++ b/extensions/libipt_icmp.txlate +@@ -6,3 +6,6 @@ nft add rule ip filter INPUT icmp type destination-unreachable counter accept + + iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT + nft add rule ip filter INPUT icmp type != destination-unreachable counter accept ++ ++iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT ++nft add rule ip filter INPUT ip protocol icmp counter accept +-- +2.28.0 + diff --git a/SOURCES/0040-extensions-libxt_CT-add-translation-for-NOTRACK.patch b/SOURCES/0040-extensions-libxt_CT-add-translation-for-NOTRACK.patch new file mode 100644 index 0000000..ca1316b --- /dev/null +++ b/SOURCES/0040-extensions-libxt_CT-add-translation-for-NOTRACK.patch @@ -0,0 +1,66 @@ +From 1695f552d3947299e54978bcd5bc1cdc3a5c14f7 Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Wed, 15 Apr 2020 18:16:41 +0200 +Subject: [PATCH] extensions: libxt_CT: add translation for NOTRACK + +Signed-off-by: Pablo Neira Ayuso +(cherry picked from commit f3d4a3ddbcfca15a00dd9758f481420038f6de10) +Signed-off-by: Phil Sutter +--- + extensions/libxt_CT.c | 16 ++++++++++++++++ + extensions/libxt_NOTRACK.txlate | 2 ++ + 2 files changed, 18 insertions(+) + create mode 100644 extensions/libxt_NOTRACK.txlate + +diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c +index 371b21766c56c..fbbbe2660e9fc 100644 +--- a/extensions/libxt_CT.c ++++ b/extensions/libxt_CT.c +@@ -348,6 +348,20 @@ static void notrack_ct2_tg_init(struct xt_entry_target *target) + info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS; + } + ++static int xlate_ct1_tg(struct xt_xlate *xl, ++ const struct xt_xlate_tg_params *params) ++{ ++ struct xt_ct_target_info_v1 *info = ++ (struct xt_ct_target_info_v1 *)params->target->data; ++ ++ if (info->flags & XT_CT_NOTRACK) ++ xt_xlate_add(xl, "notrack"); ++ else ++ return 0; ++ ++ return 1; ++} ++ + static struct xtables_target ct_target_reg[] = { + { + .family = NFPROTO_UNSPEC, +@@ -387,6 +401,7 @@ static struct xtables_target ct_target_reg[] = { + .alias = ct_print_name_alias, + .x6_parse = ct_parse_v1, + .x6_options = ct_opts_v1, ++ .xlate = xlate_ct1_tg, + }, + { + .family = NFPROTO_UNSPEC, +@@ -418,6 +433,7 @@ static struct xtables_target ct_target_reg[] = { + .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), + .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), + .init = notrack_ct2_tg_init, ++ .xlate = xlate_ct1_tg, + }, + { + .family = NFPROTO_UNSPEC, +diff --git a/extensions/libxt_NOTRACK.txlate b/extensions/libxt_NOTRACK.txlate +new file mode 100644 +index 0000000000000..9d35619d3dbdd +--- /dev/null ++++ b/extensions/libxt_NOTRACK.txlate +@@ -0,0 +1,2 @@ ++iptables-translate -A PREROUTING -t raw -j NOTRACK ++nft add rule ip raw PREROUTING counter notrack +-- +2.28.0 + diff --git a/SOURCES/0041-nft-Fix-command-name-in-ip6tables-error-message.patch b/SOURCES/0041-nft-Fix-command-name-in-ip6tables-error-message.patch new file mode 100644 index 0000000..3a57697 --- /dev/null +++ b/SOURCES/0041-nft-Fix-command-name-in-ip6tables-error-message.patch @@ -0,0 +1,45 @@ +From 6d8a390bd13bac294ff9de225a49fe9e4de2d6e5 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Fri, 7 Aug 2020 13:48:28 +0200 +Subject: [PATCH] nft: Fix command name in ip6tables error message + +Upon errors, ip6tables-nft would prefix its error messages with +'iptables:' instead of 'ip6tables:'. Turns out the command name was +hard-coded, use 'progname' variable instead. +While being at it, merge the two mostly identical fprintf() calls into +one. + +Signed-off-by: Phil Sutter +Acked-by: Pablo Neira Ayuso +(cherry picked from commit 3be40dcfb5af1438b6abdbda45a1e3b59c104e13) +Signed-off-by: Phil Sutter +--- + iptables/xtables-standalone.c | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c +index 022d5dd44abbf..b5b7ccaf4e660 100644 +--- a/iptables/xtables-standalone.c ++++ b/iptables/xtables-standalone.c +@@ -74,14 +74,10 @@ xtables_main(int family, const char *progname, int argc, char *argv[]) + nft_fini(&h); + + if (!ret) { +- if (errno == EINVAL) { +- fprintf(stderr, "iptables: %s. " +- "Run `dmesg' for more information.\n", +- nft_strerror(errno)); +- } else { +- fprintf(stderr, "iptables: %s.\n", +- nft_strerror(errno)); +- } ++ fprintf(stderr, "%s: %s.%s\n", progname, nft_strerror(errno), ++ (errno == EINVAL ? ++ " Run `dmesg' for more information." : "")); ++ + if (errno == EAGAIN) + exit(RESOURCE_PROBLEM); + } +-- +2.28.0 + diff --git a/SOURCES/0042-tests-shell-Merge-and-extend-return-codes-test.patch b/SOURCES/0042-tests-shell-Merge-and-extend-return-codes-test.patch new file mode 100644 index 0000000..93ce99a --- /dev/null +++ b/SOURCES/0042-tests-shell-Merge-and-extend-return-codes-test.patch @@ -0,0 +1,206 @@ +From c5f07a7d718f812f916686926567adbac6c1b125 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 6 Aug 2020 18:52:34 +0200 +Subject: [PATCH] tests: shell: Merge and extend return codes test + +Merge scripts for iptables and ip6tables, they were widely identical. +Also extend the test by one check (removing a non-existent rule with +valid chain and target) and quote the error messages where differences +are deliberately ignored. + +Signed-off-by: Phil Sutter +Acked-by: Pablo Neira Ayuso +(cherry picked from commit cd3e83d1b04fd2683f0fb06e496ee5be08a96b4f) + +Conflicts: + iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 + iptables/tests/shell/testcases/iptables/0004-return-codes_0 +-> Missing upstream commit a7f1e208cdf9c ("nft: split parsing from + netlink commands") which added a few tests to both files. + +Signed-off-by: Phil Sutter +--- + .../testcases/ip6tables/0004-return-codes_0 | 38 ------- + .../testcases/iptables/0004-return-codes_0 | 104 ++++++++++-------- + 2 files changed, 58 insertions(+), 84 deletions(-) + delete mode 100755 iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 + +diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 +deleted file mode 100755 +index f023b7915498e..0000000000000 +--- a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 ++++ /dev/null +@@ -1,38 +0,0 @@ +-#!/bin/sh +- +-# make sure error return codes are as expected useful cases +-# (e.g. commands to check ruleset state) +- +-global_rc=0 +- +-cmd() { # (rc, cmd, [args ...]) +- rc_exp=$1; shift +- +- $XT_MULTI "$@" +- rc=$? +- +- [ $rc -eq $rc_exp ] || { +- echo "---> expected $rc_exp, got $rc for command '$@'" +- global_rc=1 +- } +-} +- +-# test chain creation +-cmd 0 ip6tables -N foo +-cmd 1 ip6tables -N foo +-# iptables-nft allows this - bug or feature? +-#cmd 2 ip6tables -N "invalid name" +- +-# test rule adding +-cmd 0 ip6tables -A INPUT -j ACCEPT +-cmd 1 ip6tables -A noexist -j ACCEPT +- +-# test rule checking +-cmd 0 ip6tables -C INPUT -j ACCEPT +-cmd 1 ip6tables -C FORWARD -j ACCEPT +-cmd 1 ip6tables -C nonexist -j ACCEPT +-cmd 2 ip6tables -C INPUT -j foobar +-cmd 2 ip6tables -C INPUT -m foobar -j ACCEPT +-cmd 3 ip6tables -t foobar -C INPUT -j ACCEPT +- +-exit $global_rc +diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 +index ce02e0bcb128b..67f1698945753 100755 +--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 ++++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0 +@@ -13,69 +13,81 @@ cmd() { # (rc, msg, cmd, [args ...]) + msg_exp="$1"; shift + } + +- msg="$($XT_MULTI "$@" 2>&1 >/dev/null)" +- rc=$? ++ for ipt in iptables ip6tables; do ++ msg="$($XT_MULTI $ipt "$@" 2>&1 >/dev/null)" ++ rc=$? + +- [ $rc -eq $rc_exp ] || { +- echo "---> expected return code $rc_exp, got $rc for command '$@'" +- global_rc=1 +- } ++ [ $rc -eq $rc_exp ] || { ++ echo "---> expected return code $rc_exp, got $rc for command '$ipt $@'" ++ global_rc=1 ++ } + +- [ -n "$msg_exp" ] || return +- grep -q "$msg_exp" <<< $msg || { +- echo "---> expected error message '$msg_exp', got '$msg' for command '$@'" +- global_rc=1 +- } ++ [ -n "$msg_exp" ] || continue ++ msg_exp_full="${ipt}$msg_exp" ++ grep -q "$msg_exp_full" <<< $msg || { ++ echo "---> expected error message '$msg_exp_full', got '$msg' for command '$ipt $@'" ++ global_rc=1 ++ } ++ done + } + +-EEXIST_F="File exists." +-EEXIST="Chain already exists." +-ENOENT="No chain/target/match by that name." +-E2BIG_I="Index of insertion too big." +-E2BIG_D="Index of deletion too big." +-E2BIG_R="Index of replacement too big." +-EBADRULE="Bad rule (does a matching rule exist in that chain?)." +-ENOTGT="Couldn't load target \`foobar':No such file or directory" +-ENOMTH="Couldn't load match \`foobar':No such file or directory" +-ENOTBL="can't initialize iptables table \`foobar': Table does not exist" ++EEXIST_F=": File exists." ++EEXIST=": Chain already exists." ++ENOENT=": No chain/target/match by that name." ++E2BIG_I=": Index of insertion too big." ++E2BIG_D=": Index of deletion too big." ++E2BIG_R=": Index of replacement too big." ++EBADRULE=": Bad rule (does a matching rule exist in that chain?)." ++#ENOTGT=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory" ++ENOMTH=" v[0-9\.]* [^ ]*: Couldn't load match \`foobar':No such file or directory" ++ENOTBL=": can't initialize iptables table \`foobar': Table does not exist" + + # test chain creation +-cmd 0 iptables -N foo +-cmd 1 "$EEXIST" iptables -N foo ++cmd 0 -N foo ++cmd 1 "$EEXIST" -N foo + # iptables-nft allows this - bug or feature? +-#cmd 2 iptables -N "invalid name" ++#cmd 2 -N "invalid name" + + # test chain flushing/zeroing +-cmd 0 iptables -F foo +-cmd 0 iptables -Z foo +-cmd 1 "$ENOENT" iptables -F bar +-cmd 1 "$ENOENT" iptables -Z bar ++cmd 0 -F foo ++cmd 0 -Z foo ++cmd 1 "$ENOENT" -F bar ++cmd 1 "$ENOENT" -Z bar + + # test chain rename +-cmd 0 iptables -E foo bar +-cmd 1 "$EEXIST_F" iptables -E foo bar ++cmd 0 -E foo bar ++cmd 1 "$EEXIST_F" -E foo bar + + # test rule adding +-cmd 0 iptables -A INPUT -j ACCEPT +-cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT ++cmd 0 -A INPUT -j ACCEPT ++cmd 1 "$ENOENT" -A noexist -j ACCEPT ++# next three differ: ++# legacy: Couldn't load target `foobar':No such file or directory ++# nft: Chain 'foobar' does not exist ++cmd 2 "" -I INPUT -j foobar ++cmd 2 "" -R INPUT 1 -j foobar ++cmd 2 "" -D INPUT -j foobar ++cmd 1 "$EBADRULE" -D INPUT -p tcp --dport 22 -j ACCEPT + + # test rulenum commands +-cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT +-cmd 1 "$E2BIG_D" iptables -D INPUT 23 +-cmd 1 "$E2BIG_R" iptables -R INPUT 23 -j ACCEPT +-cmd 1 "$ENOENT" iptables -I nonexist 23 -j ACCEPT +-cmd 1 "$ENOENT" iptables -D nonexist 23 +-cmd 1 "$ENOENT" iptables -R nonexist 23 -j ACCEPT ++cmd 1 "$E2BIG_I" -I INPUT 23 -j ACCEPT ++cmd 1 "$E2BIG_D" -D INPUT 23 ++cmd 1 "$E2BIG_R" -R INPUT 23 -j ACCEPT ++cmd 1 "$ENOENT" -I nonexist 23 -j ACCEPT ++cmd 1 "$ENOENT" -D nonexist 23 ++cmd 1 "$ENOENT" -R nonexist 23 -j ACCEPT + + # test rule checking +-cmd 0 iptables -C INPUT -j ACCEPT +-cmd 1 "$EBADRULE" iptables -C FORWARD -j ACCEPT +-cmd 1 "$BADRULE" iptables -C nonexist -j ACCEPT +-cmd 2 "$ENOMTH" iptables -C INPUT -m foobar -j ACCEPT ++cmd 0 -C INPUT -j ACCEPT ++cmd 1 "$EBADRULE" -C FORWARD -j ACCEPT ++cmd 1 "$BADRULE" -C nonexist -j ACCEPT ++cmd 2 "$ENOMTH" -C INPUT -m foobar -j ACCEPT + # messages of those don't match, but iptables-nft ones are actually nicer. +-#cmd 2 "$ENOTGT" iptables -C INPUT -j foobar +-#cmd 3 "$ENOTBL" iptables -t foobar -C INPUT -j ACCEPT +-cmd 2 "" iptables -C INPUT -j foobar +-cmd 3 "" iptables -t foobar -C INPUT -j ACCEPT ++# legacy: Couldn't load target `foobar':No such file or directory ++# nft: Chain 'foobar' does not exist ++cmd 2 "" -C INPUT -j foobar ++# legacy: can't initialize ip6tables table `foobar': Table does not exist (do you need to insmod?) ++# nft: table 'foobar' does not exist ++cmd 3 "" -t foobar -C INPUT -j ACCEPT + + exit $global_rc +-- +2.28.0 + diff --git a/SOURCES/0043-extensions-dccp-Fix-for-DCCP-type-INVALID.patch b/SOURCES/0043-extensions-dccp-Fix-for-DCCP-type-INVALID.patch new file mode 100644 index 0000000..bf463a2 --- /dev/null +++ b/SOURCES/0043-extensions-dccp-Fix-for-DCCP-type-INVALID.patch @@ -0,0 +1,177 @@ +From 98794894774a39927bc975921fc9e40f00db937b Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Wed, 2 Dec 2020 13:37:06 +0100 +Subject: [PATCH] extensions: dccp: Fix for DCCP type 'INVALID' + +Support for matching on invalid DCCP type field values was pretty +broken: While RFC4340 declares any type value from 10 to 15 invalid, the +extension's type name 'INVALID' mapped to type value 10 only. Fix this +by introduction of INVALID_OTHER_TYPE_MASK which has the remaining +invalid type's bits set and apply it if bit 10 is set after parsing the +type list. When printing, stop searching type names after printing +'INVALID' - unless numeric output was requested. The latter prints all +actual type values. Since parsing types in numeric form is not +supported, changing the output should not break existing scripts. + +When translating into nftables syntax, the code returned prematurely if +'INVALID' was among the list of types - thereby emitting invalid syntax. +Instead print a real match for invalid types by use of a range +expression. + +While being at it, fix syntax of translator output: If only +'--dccp-types' was translated, the output contained an extra 'dccp'. On +the other hand, if '--sport' and '--dport' was present, a required +'dccp' between the translations of both was missing. + +Fixes: e40b11d7ef827 ("add support for new 'dccp' protocol match") +Fixes: c94a998724143 ("extensions: libxt_dccp: Add translation to nft") +Signed-off-by: Phil Sutter +(cherry picked from commit 4bcbc8e11a2764f4537dc405962f83cd072cccfe) +Signed-off-by: Phil Sutter +--- + extensions/libxt_dccp.c | 58 ++++++++++++++++++++++-------------- + extensions/libxt_dccp.txlate | 12 ++++++-- + 2 files changed, 45 insertions(+), 25 deletions(-) + +diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c +index 5e67c264db2a9..aea3e20be4818 100644 +--- a/extensions/libxt_dccp.c ++++ b/extensions/libxt_dccp.c +@@ -76,6 +76,9 @@ static const char *const dccp_pkt_types[] = { + [DCCP_PKT_INVALID] = "INVALID", + }; + ++/* Bits for type values 11-15 */ ++#define INVALID_OTHER_TYPE_MASK 0xf800 ++ + static uint16_t + parse_dccp_types(const char *typestring) + { +@@ -95,6 +98,9 @@ parse_dccp_types(const char *typestring) + xtables_error(PARAMETER_PROBLEM, + "Unknown DCCP type `%s'", ptr); + } ++ if (typemask & (1 << DCCP_PKT_INVALID)) ++ typemask |= INVALID_OTHER_TYPE_MASK; ++ + + free(buffer); + return typemask; +@@ -193,9 +199,13 @@ print_types(uint16_t types, int inverted, int numeric) + + if (numeric) + printf("%u", i); +- else ++ else { + printf("%s", dccp_pkt_types[i]); + ++ if (i == DCCP_PKT_INVALID) ++ break; ++ } ++ + types &= ~(1 << i); + } + } +@@ -288,6 +298,7 @@ static const char *const dccp_pkt_types_xlate[] = { + [DCCP_PKT_RESET] = "reset", + [DCCP_PKT_SYNC] = "sync", + [DCCP_PKT_SYNCACK] = "syncack", ++ [DCCP_PKT_INVALID] = "10-15", + }; + + static int dccp_type_xlate(const struct xt_dccp_info *einfo, +@@ -296,10 +307,10 @@ static int dccp_type_xlate(const struct xt_dccp_info *einfo, + bool have_type = false, set_need = false; + uint16_t types = einfo->typemask; + +- if (types & (1 << DCCP_PKT_INVALID)) +- return 0; +- +- xt_xlate_add(xl, " dccp type%s ", einfo->invflags ? " !=" : ""); ++ if (types & INVALID_OTHER_TYPE_MASK) { ++ types &= ~INVALID_OTHER_TYPE_MASK; ++ types |= 1 << DCCP_PKT_INVALID; ++ } + + if ((types != 0) && !(types == (types & -types))) { + xt_xlate_add(xl, "{"); +@@ -335,34 +346,37 @@ static int dccp_xlate(struct xt_xlate *xl, + char *space = ""; + int ret = 1; + +- xt_xlate_add(xl, "dccp "); +- + if (einfo->flags & XT_DCCP_SRC_PORTS) { ++ xt_xlate_add(xl, "dccp sport%s %u", ++ einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "", ++ einfo->spts[0]); ++ + if (einfo->spts[0] != einfo->spts[1]) +- xt_xlate_add(xl, "sport%s %u-%u", +- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "", +- einfo->spts[0], einfo->spts[1]); +- else +- xt_xlate_add(xl, "sport%s %u", +- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "", +- einfo->spts[0]); ++ xt_xlate_add(xl, "-%u", einfo->spts[1]); ++ + space = " "; + } + + if (einfo->flags & XT_DCCP_DEST_PORTS) { ++ xt_xlate_add(xl, "%sdccp dport%s %u", space, ++ einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "", ++ einfo->dpts[0]); ++ + if (einfo->dpts[0] != einfo->dpts[1]) +- xt_xlate_add(xl, "%sdport%s %u-%u", space, +- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "", +- einfo->dpts[0], einfo->dpts[1]); +- else +- xt_xlate_add(xl, "%sdport%s %u", space, +- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "", +- einfo->dpts[0]); ++ xt_xlate_add(xl, "-%u", einfo->dpts[1]); ++ ++ space = " "; + } + +- if (einfo->flags & XT_DCCP_TYPE) ++ if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) { ++ xt_xlate_add(xl, "%sdccp type%s ", space, ++ einfo->invflags & XT_DCCP_TYPE ? " !=" : ""); + ret = dccp_type_xlate(einfo, xl); + ++ space = " "; ++ } ++ ++ /* FIXME: no dccp option support in nftables yet */ + if (einfo->flags & XT_DCCP_OPTION) + ret = 0; + +diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate +index b47dc65f5bc4f..ea853f6acf627 100644 +--- a/extensions/libxt_dccp.txlate ++++ b/extensions/libxt_dccp.txlate +@@ -7,8 +7,14 @@ nft add rule ip filter INPUT dccp dport 100-200 counter + iptables-translate -A INPUT -p dccp -m dccp ! --dport 100 + nft add rule ip filter INPUT dccp dport != 100 counter + +-iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK +-nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack} counter ++iptables-translate -A INPUT -p dccp -m dccp --dccp-types CLOSE ++nft add rule ip filter INPUT dccp type close counter ++ ++iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID ++nft add rule ip filter INPUT dccp type 10-15 counter ++ ++iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID ++nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15} counter + + iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100 +-nft add rule ip filter INPUT dccp sport 200 dport 100 counter ++nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter +-- +2.28.0 + diff --git a/SPECS/iptables.spec b/SPECS/iptables.spec index 50145cc..87f721b 100644 --- a/SPECS/iptables.spec +++ b/SPECS/iptables.spec @@ -17,7 +17,7 @@ Name: iptables Summary: Tools for managing Linux kernel packet filtering capabilities URL: http://www.netfilter.org/projects/iptables Version: 1.8.4 -Release: 16%{?dist} +Release: 17%{?dist} Source: %{url}/files/%{name}-%{version}.tar.bz2 Source1: iptables.init Source2: iptables-config @@ -68,6 +68,15 @@ Patch31: 0031-nft-Fix-for-broken-address-mask-match-detection.patch Patch32: 0032-nft-Optimize-class-based-IP-prefix-matches.patch Patch33: 0033-ebtables-Optimize-masked-MAC-address-matches.patch Patch34: 0034-tests-shell-Add-test-for-bitwise-avoidance-fixes.patch +Patch35: 0035-libxtables-Make-sure-extensions-register-in-revision.patch +Patch36: 0036-libxtables-Simplify-pending-extension-registration.patch +Patch37: 0037-libxtables-Register-multiple-extensions-in-ascending.patch +Patch38: 0038-tests-shell-Test-for-fixed-extension-registration.patch +Patch39: 0039-extensions-libipt_icmp-Fix-translation-of-type-any.patch +Patch40: 0040-extensions-libxt_CT-add-translation-for-NOTRACK.patch +Patch41: 0041-nft-Fix-command-name-in-ip6tables-error-message.patch +Patch42: 0042-tests-shell-Merge-and-extend-return-codes-test.patch +Patch43: 0043-extensions-dccp-Fix-for-DCCP-type-INVALID.patch # pf.os: ISC license # iptables-apply: Artistic Licence 2.0 @@ -476,6 +485,17 @@ done %doc %{_mandir}/man8/ebtables*.8* %changelog +* Thu Dec 10 2020 Phil Sutter - 1.8.4-17 +- extensions: dccp: Fix for DCCP type 'INVALID' +- tests: shell: Merge and extend return codes test +- nft: Fix command name in ip6tables error message +- extensions: libxt_CT: add translation for NOTRACK +- extensions: libipt_icmp: Fix translation of type 'any' +- tests/shell: Test for fixed extension registration +- libxtables: Register multiple extensions in ascending order +- libxtables: Simplify pending extension registration +- libxtables: Make sure extensions register in revision order + * Wed Oct 28 2020 Phil Sutter - 1.8.4-16 - tests/shell: Add test for bitwise avoidance fixes - ebtables: Optimize masked MAC address matches