]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
libnftables: include canonical path to avoid duplicates
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 12 Dec 2024 21:41:52 +0000 (22:41 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 2 Jan 2025 18:58:11 +0000 (19:58 +0100)
A recent commit adds base directory of -f/--filename to include paths by
default to address a silly use of -I/--include to make this work:

  # nft -I /path/to -f /path/to/main.nft

instead users can simply invoke:

  # nft -f /path/to/main.nft

because /path/to/ is added at the end of the list of include paths.

This example above assumes main.nft includes more files that are
contained in /path/to/.

However, globbing can cause duplicates after this recent update, eg.

  # cat test/main
  table inet test {
        chain test {
                include "include/*";
        }
  }
  # nft -I /tmp/test/ -f test/main

because /tmp/test and test/ twice refer to the same directory and both
are added to the list of include path.

Use realpath() to canonicalize include paths. Then, search and skip
duplicated include paths.

Fixes: 302e9f8b3a13 ("libnftables: add base directory of -f/--filename to include path")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/libnftables.c
src/main.c
tests/shell/testcases/include/dumps/glob_duplicated_include.nft [new file with mode: 0644]
tests/shell/testcases/include/glob_duplicated_include [new file with mode: 0755]

index 1df22b3cb57d953c025a32b92fd80d52a1e9c5fd..c8293f77677fa9a224e089749ccfbfddda99c395 100644 (file)
@@ -167,8 +167,19 @@ void nft_ctx_clear_vars(struct nft_ctx *ctx)
        ctx->vars = NULL;
 }
 
-EXPORT_SYMBOL(nft_ctx_add_include_path);
-int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
+static bool nft_ctx_find_include_path(struct nft_ctx *ctx, const char *path)
+{
+       unsigned int i;
+
+       for (i = 0; i < ctx->num_include_paths; i++) {
+               if (!strcmp(ctx->include_paths[i], path))
+                       return true;
+       }
+
+       return false;
+}
+
+static int __nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
 {
        char **tmp;
        int pcount = ctx->num_include_paths;
@@ -184,6 +195,20 @@ int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
        return 0;
 }
 
+EXPORT_SYMBOL(nft_ctx_add_include_path);
+int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
+{
+       char canonical_path[PATH_MAX];
+
+       if (!realpath(path, canonical_path))
+               return -1;
+
+       if (nft_ctx_find_include_path(ctx, canonical_path))
+               return 0;
+
+       return __nft_ctx_add_include_path(ctx, canonical_path);
+}
+
 EXPORT_SYMBOL(nft_ctx_clear_include_paths);
 void nft_ctx_clear_include_paths(struct nft_ctx *ctx)
 {
index d3491cda7f8db164a31f1584caa5a4aad03d55b2..d13952ccb16b5ba44d718a8cbcad0f6da69b4ddf 100644 (file)
@@ -423,9 +423,8 @@ int main(int argc, char * const *argv)
                case OPT_INCLUDEPATH:
                        if (nft_ctx_add_include_path(nft, optarg)) {
                                fprintf(stderr,
-                                       "Failed to add include path '%s'\n",
+                                       "Warning: Cannot include path '%s'\n",
                                        optarg);
-                               goto out_fail;
                        }
                        break;
                case OPT_NUMERIC:
diff --git a/tests/shell/testcases/include/dumps/glob_duplicated_include.nft b/tests/shell/testcases/include/dumps/glob_duplicated_include.nft
new file mode 100644 (file)
index 0000000..8e316e9
--- /dev/null
@@ -0,0 +1,6 @@
+table inet test {
+       chain test {
+               tcp dport 22 accept
+               tcp dport 25 accept
+       }
+}
diff --git a/tests/shell/testcases/include/glob_duplicated_include b/tests/shell/testcases/include/glob_duplicated_include
new file mode 100755 (executable)
index 0000000..4507f5d
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+trap "rm -rf $tmpdir" EXIT
+
+tmpdir=$(mktemp -d)
+mkdir -p $tmpdir/test/include
+cat > $tmpdir/test/main << EOF
+table inet test {
+        chain test {
+                include "include/*";
+        }
+}
+EOF
+echo "tcp dport 22 accept;" > $tmpdir/test/include/one
+echo "tcp dport 25 accept;" > $tmpdir/test/include/two
+
+$NFT -I $tmpdir/test/ -f $tmpdir/test/main