netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] scanner: add files in include dirs in alphabetical order.
@ 2017-06-07  8:35 Ismo Puustinen
  2017-06-07  8:35 ` [PATCH 2/3] man: add include directory documentation Ismo Puustinen
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Ismo Puustinen @ 2017-06-07  8:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Ismo Puustinen

This means that if you have a directory structure like this

    /foo
    /foo/02_rules.nft
    /foo/01_rules.nft

where *.nft files in directory /foo are nft scripts, then an include
statement in another nft script like this

    include "/foo/"

guarantees that "01_rules.nft" is loaded before "02_rules.nft".

Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com>
---
 src/scanner.l | 102 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 75 insertions(+), 27 deletions(-)

diff --git a/src/scanner.l b/src/scanner.l
index fe65e0c..4050cba 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -13,10 +13,12 @@
 #include <dirent.h>
 #include <libgen.h>
 #include <limits.h>
+#include <unistd.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <linux/types.h>
 #include <linux/netfilter.h>
+#include <sys/stat.h>
 
 #include <nftables.h>
 #include <erec.h>
@@ -668,14 +670,39 @@ int scanner_read_file(void *scanner, const char *filename,
 	return include_file(scanner, filename, loc);
 }
 
+static int directoryfilter(const struct dirent *de)
+{
+	if (strcmp(de->d_name, ".") == 0 ||
+			strcmp(de->d_name, "..") == 0)
+		return 0;
+
+	/* Accept other filenames. If we want to enable filtering based on
+	 * filename suffix (*.nft), this would be the place to do it.
+	 */
+
+	return 1;
+}
+
+static void free_scandir_des(struct dirent **des, int n_des)
+{
+	int i;
+
+	for (i = 0; i < n_des; i++) {
+		free(des[i]);
+	}
+
+	free(des);
+}
+
 static int include_directory(void *scanner, const char *dirname,
-			     DIR *directory, const struct location *loc)
+			     const struct location *loc)
 {
 	struct parser_state *state = yyget_extra(scanner);
+	struct dirent **des = NULL;
 	struct error_record *erec;
-	struct dirent *de;
+	int ret, n_des = 0, i;
+	char dirbuf[PATH_MAX];
 	FILE *f;
-	int ret;
 
 	if (!dirname[0] || dirname[strlen(dirname)-1] != '/') {
 		erec = error(loc, "Include directory name \"%s\" does not end in '/'",
@@ -684,23 +711,32 @@ static int include_directory(void *scanner, const char *dirname,
 	}
 
 	/* If the path is a directory, assume that all files there need
-	 * to be included.
+	 * to be included. Sort the file list in alphabetical order.
 	 */
-	while ((de = readdir(directory))) {
-		char dirbuf[PATH_MAX];
+	n_des = scandir(dirname, &des, directoryfilter, alphasort);
+	if (n_des < 0) {
+		erec = error(loc, "Failed to scan directory contents for \"%s\"",
+			     dirname);
+		goto err;
+	}
+	else if (n_des == 0) {
+		/* nothing to do */
+		free(des);
+		return 0;
+	}
 
+	/* We need to push the files in reverse order, so that they will be
+	 * popped in the correct order.
+	 */
+	for (i = n_des-1; i >= 0; i--) {
 		ret = snprintf(dirbuf, sizeof(dirbuf), "%s/%s", dirname,
-			       de->d_name);
+			       des[i]->d_name);
 		if (ret < 0 || ret >= PATH_MAX) {
 			erec = error(loc, "Too long file path \"%s/%s\"\n",
-				     dirname, de->d_name);
+				     dirname, des[i]->d_name);
 			goto err;
 		}
 
-		if (strcmp(de->d_name, ".") == 0 ||
-		    strcmp(de->d_name, "..") == 0)
-			continue;
-
 		f = fopen(dirbuf, "r");
 		if (f == NULL) {
 			erec = error(loc, "Could not open file \"%s\": %s\n",
@@ -708,12 +744,14 @@ static int include_directory(void *scanner, const char *dirname,
 			goto err;
 		}
 
-		erec = scanner_push_file(scanner, de->d_name, f, loc);
+		erec = scanner_push_file(scanner, des[i]->d_name, f, loc);
 		if (erec != NULL)
 			goto err;
 	}
+	free_scandir_des(des, n_des);
 	return 0;
 err:
+	free_scandir_des(des, n_des);
 	erec_queue(erec, state->msgs);
 	return -1;
 }
@@ -721,27 +759,37 @@ err:
 static int include_dentry(void *scanner, const char *filename,
 			  const struct location *loc)
 {
-	DIR *directory;
+	struct parser_state *state = yyget_extra(scanner);
+	struct error_record *erec;
+	struct stat st;
 	int ret;
 
-	/* The file can be either a simple file or a directory which
-	 * contains files.
-	 */
-	directory = opendir(filename);
-	if (directory == NULL &&
-	    errno != ENOTDIR) {
-		/* Could not access the directory or file, keep on searching.
+	/* stat the file */
+	ret = stat(filename, &st);
+
+	if (ret == -1 && errno == ENOENT)
+		/* Could not find the directory or file, keep on searching.
 		 * Return value '1' indicates to the caller that we should still
 		 * search in the next include directory.
 		 */
-		ret = 1;
-	} else if (directory != NULL) {
-		ret = include_directory(scanner, filename, directory, loc);
-		closedir(directory);
-	} else {
-		ret = include_file(scanner, filename, loc);
+		return 1;
+	else if (ret == 0) {
+		if (S_ISDIR(st.st_mode))
+			return include_directory(scanner, filename, loc);
+		else if (S_ISREG(st.st_mode))
+			return include_file(scanner, filename, loc);
+		else {
+			errno = EINVAL;
+			ret = -1;
+		}
 	}
 
+	/* Process error for failed stat and cases where the file is not a
+	 * directory or (a link to) a regular file.
+	 */
+	erec = error(loc, "Failed to access file \"%s\": %s\n",
+			filename, strerror(errno));
+	erec_queue(erec, state->msgs);
 	return ret;
 }
 
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] man: add include directory documentation.
  2017-06-07  8:35 [PATCH 1/3] scanner: add files in include dirs in alphabetical order Ismo Puustinen
@ 2017-06-07  8:35 ` Ismo Puustinen
  2017-06-07 10:09   ` Pablo Neira Ayuso
  2017-06-07  8:35 ` [PATCH 3/3] tests: added tests for ordering files in include dirs Ismo Puustinen
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Ismo Puustinen @ 2017-06-07  8:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Ismo Puustinen

Short include directory introduction is added to the man page.

Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com>
---
 doc/nft.xml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/doc/nft.xml b/doc/nft.xml
index f613f69..9364133 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -209,6 +209,10 @@ vi:ts=4 sw=4
 				The directories to be searched for include files can be specified using
 				the <option>-I/--includepath</option> option.
 			</para>
+			<para>
+				If the <literal>filename</literal> parameter is a directory, then all files in
+				the directory are loaded in alphabetical order.
+			</para>
 		</refsect2>
 		<refsect2>
 			<title>Symbolic variables</title>
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] tests: added tests for ordering files in include dirs.
  2017-06-07  8:35 [PATCH 1/3] scanner: add files in include dirs in alphabetical order Ismo Puustinen
  2017-06-07  8:35 ` [PATCH 2/3] man: add include directory documentation Ismo Puustinen
@ 2017-06-07  8:35 ` Ismo Puustinen
  2017-06-07 10:09 ` [PATCH 1/3] scanner: add files in include dirs in alphabetical order Pablo Neira Ayuso
  2017-06-07 19:40 ` Arturo Borrero Gonzalez
  3 siblings, 0 replies; 9+ messages in thread
From: Ismo Puustinen @ 2017-06-07  8:35 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Ismo Puustinen

Test that the files are ordered properly by introducing included files
which have internal dependencies.

Signed-off-by: Ismo Puustinen <ismo.puustinen@intel.com>
---
 tests/shell/testcases/include/0011dir_dependency_0 | 48 ++++++++++++++++++++
 tests/shell/testcases/include/0012dir_dependency_1 | 51 ++++++++++++++++++++++
 2 files changed, 99 insertions(+)
 create mode 100755 tests/shell/testcases/include/0011dir_dependency_0
 create mode 100755 tests/shell/testcases/include/0012dir_dependency_1

diff --git a/tests/shell/testcases/include/0011dir_dependency_0 b/tests/shell/testcases/include/0011dir_dependency_0
new file mode 100755
index 0000000..8ee193f
--- /dev/null
+++ b/tests/shell/testcases/include/0011dir_dependency_0
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+        echo "Failed to create tmp directory" >&2
+        exit 0
+fi
+
+tmpfile1="$tmpdir/01_file.nft"
+touch $tmpfile1
+if [ ! -w $tmpfile1 ] ; then
+        echo "Failed to create tmp file" >&2
+        exit 0
+fi
+
+tmpfile2="$tmpdir/02_file.nft"
+touch $tmpfile2
+if [ ! -w $tmpfile2 ] ; then
+        echo "Failed to create tmp file" >&2
+        exit 0
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+        echo "Failed to create tmp file" >&2
+        exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 && rmdir $tmpdir" EXIT
+
+# add interdependent rulesets
+RULESET1="add table x"
+RULESET2="add chain x y"
+RULESET3="include \"$tmpdir/\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+echo "$RULESET3" > $tmpfile3
+
+$NFT -f $tmpfile3
+
+if [ $? -ne 0 ] ; then
+        echo "E: unable to load good ruleset" >&2
+        exit 1
+fi
diff --git a/tests/shell/testcases/include/0012dir_dependency_1 b/tests/shell/testcases/include/0012dir_dependency_1
new file mode 100755
index 0000000..bd27e2a
--- /dev/null
+++ b/tests/shell/testcases/include/0012dir_dependency_1
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+        echo "Failed to create tmp directory" >&2
+        exit 0
+fi
+
+tmpfile1="$tmpdir/01_file.nft"
+touch $tmpfile1
+if [ ! -w $tmpfile1 ] ; then
+        echo "Failed to create tmp file" >&2
+        exit 0
+fi
+
+tmpfile2="$tmpdir/02_file.nft"
+touch $tmpfile2
+if [ ! -w $tmpfile2 ] ; then
+        echo "Failed to create tmp file" >&2
+        exit 0
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+        echo "Failed to create tmp file" >&2
+        exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 && rmdir $tmpdir" EXIT
+
+# add interdependent rulesets
+RULESET1="add table x"
+RULESET2="add chain x y"
+RULESET3="include \"$tmpdir/\""
+
+# Note different order when compared with 0011dir_depencency_0. The idea
+# here is to introduce wrong order to get the loading fail.
+echo "$RULESET1" > $tmpfile2
+echo "$RULESET2" > $tmpfile1
+echo "$RULESET3" > $tmpfile3
+
+$NFT -f $tmpfile3
+
+if [ $? -eq 0 ] ; then
+        echo "E: did not catch wrong file order in include directory" >&2
+        exit 1
+fi
+
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] scanner: add files in include dirs in alphabetical order.
  2017-06-07  8:35 [PATCH 1/3] scanner: add files in include dirs in alphabetical order Ismo Puustinen
  2017-06-07  8:35 ` [PATCH 2/3] man: add include directory documentation Ismo Puustinen
  2017-06-07  8:35 ` [PATCH 3/3] tests: added tests for ordering files in include dirs Ismo Puustinen
@ 2017-06-07 10:09 ` Pablo Neira Ayuso
  2017-06-07 19:40 ` Arturo Borrero Gonzalez
  3 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2017-06-07 10:09 UTC (permalink / raw)
  To: Ismo Puustinen; +Cc: netfilter-devel

On Wed, Jun 07, 2017 at 11:35:57AM +0300, Ismo Puustinen wrote:
> This means that if you have a directory structure like this
> 
>     /foo
>     /foo/02_rules.nft
>     /foo/01_rules.nft
> 
> where *.nft files in directory /foo are nft scripts, then an include
> statement in another nft script like this
> 
>     include "/foo/"
> 
> guarantees that "01_rules.nft" is loaded before "02_rules.nft".

OK, that was fast.

Applied with comestic coding style changes, thanks Ismo!

Do not hesitate to follow up in case of any fallout from this update.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] man: add include directory documentation.
  2017-06-07  8:35 ` [PATCH 2/3] man: add include directory documentation Ismo Puustinen
@ 2017-06-07 10:09   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2017-06-07 10:09 UTC (permalink / raw)
  To: Ismo Puustinen; +Cc: netfilter-devel

On Wed, Jun 07, 2017 at 11:35:58AM +0300, Ismo Puustinen wrote:
> Short include directory introduction is added to the man page.

Also applied.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] scanner: add files in include dirs in alphabetical order.
  2017-06-07  8:35 [PATCH 1/3] scanner: add files in include dirs in alphabetical order Ismo Puustinen
                   ` (2 preceding siblings ...)
  2017-06-07 10:09 ` [PATCH 1/3] scanner: add files in include dirs in alphabetical order Pablo Neira Ayuso
@ 2017-06-07 19:40 ` Arturo Borrero Gonzalez
  2017-06-08 10:17   ` Pablo Neira Ayuso
  3 siblings, 1 reply; 9+ messages in thread
From: Arturo Borrero Gonzalez @ 2017-06-07 19:40 UTC (permalink / raw)
  To: Ismo Puustinen; +Cc: Netfilter Development Mailing list

On 7 June 2017 at 10:35, Ismo Puustinen <ismo.puustinen@intel.com> wrote:
>
> +static int directoryfilter(const struct dirent *de)
> +{
> +       if (strcmp(de->d_name, ".") == 0 ||
> +                       strcmp(de->d_name, "..") == 0)
> +               return 0;
> +
> +       /* Accept other filenames. If we want to enable filtering based on
> +        * filename suffix (*.nft), this would be the place to do it.
> +        */
> +

This filter by suffix is good to have IMHO.
I guess that forcing users to explicitly create a file for nftables
(or at least give a specific suffix) reduces chances for user errors.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] scanner: add files in include dirs in alphabetical order.
  2017-06-07 19:40 ` Arturo Borrero Gonzalez
@ 2017-06-08 10:17   ` Pablo Neira Ayuso
  2017-06-08 16:37     ` Arturo Borrero Gonzalez
  0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2017-06-08 10:17 UTC (permalink / raw)
  To: Arturo Borrero Gonzalez
  Cc: Ismo Puustinen, Netfilter Development Mailing list

On Wed, Jun 07, 2017 at 09:40:53PM +0200, Arturo Borrero Gonzalez wrote:
> On 7 June 2017 at 10:35, Ismo Puustinen <ismo.puustinen@intel.com> wrote:
> >
> > +static int directoryfilter(const struct dirent *de)
> > +{
> > +       if (strcmp(de->d_name, ".") == 0 ||
> > +                       strcmp(de->d_name, "..") == 0)
> > +               return 0;
> > +
> > +       /* Accept other filenames. If we want to enable filtering based on
> > +        * filename suffix (*.nft), this would be the place to do it.
> > +        */
> > +
> 
> This filter by suffix is good to have IMHO.
> I guess that forcing users to explicitly create a file for nftables
> (or at least give a specific suffix) reduces chances for user errors.

You mean, this new include directory feature just takes *.nft files,
right?

Then, to keep it consistent, we should also display a warning in
include file with no .nft postfix. At deprecate the existing behaviour
at some point, ie. bail out if you include a file that has no trailing
.nft in its name.

If we follow this path, all ruleset file will end up using .nft as
a trailer in the name.

Is there any other similar software following this approach? How is
'ferm' doing this?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] scanner: add files in include dirs in alphabetical order.
  2017-06-08 10:17   ` Pablo Neira Ayuso
@ 2017-06-08 16:37     ` Arturo Borrero Gonzalez
  2017-06-12  8:10       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 9+ messages in thread
From: Arturo Borrero Gonzalez @ 2017-06-08 16:37 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Ismo Puustinen, Netfilter Development Mailing list

On 8 June 2017 at 12:17, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Wed, Jun 07, 2017 at 09:40:53PM +0200, Arturo Borrero Gonzalez wrote:
>> On 7 June 2017 at 10:35, Ismo Puustinen <ismo.puustinen@intel.com> wrote:
>> >
>> > +static int directoryfilter(const struct dirent *de)
>> > +{
>> > +       if (strcmp(de->d_name, ".") == 0 ||
>> > +                       strcmp(de->d_name, "..") == 0)
>> > +               return 0;
>> > +
>> > +       /* Accept other filenames. If we want to enable filtering based on
>> > +        * filename suffix (*.nft), this would be the place to do it.
>> > +        */
>> > +
>>
>> This filter by suffix is good to have IMHO.
>> I guess that forcing users to explicitly create a file for nftables
>> (or at least give a specific suffix) reduces chances for user errors.
>
> You mean, this new include directory feature just takes *.nft files,
> right?
>

Yes,

> Then, to keep it consistent, we should also display a warning in
> include file with no .nft postfix. At deprecate the existing behaviour
> at some point, ie. bail out if you include a file that has no trailing
> .nft in its name.
>
> If we follow this path, all ruleset file will end up using .nft as
> a trailer in the name.
>

but perhaps it makes sense to differentiate two cases:
 * include a single file: accept arbitrary names
 * include a whole dir: accept only files ending in .nft

This seems to be what sysctl(8) does when loading a single file vs a directory.
I'm thinking in a case where you have a README in the directory or
other unrelated file.

If the idea is to allow drop files (a good idea indeed), then being
explicit is a good approach.

> Is there any other similar software following this approach? How is
> 'ferm' doing this?

ferm seems to load arbitrary files. In the docs they suggest using
.ferm files but the code
seems to allow whatever.
However, they have a set of regexp hardcoded to avoid loading things
like backups file an the like.
So, yes, probably forcing to .nft is sensible.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] scanner: add files in include dirs in alphabetical order.
  2017-06-08 16:37     ` Arturo Borrero Gonzalez
@ 2017-06-12  8:10       ` Pablo Neira Ayuso
  0 siblings, 0 replies; 9+ messages in thread
From: Pablo Neira Ayuso @ 2017-06-12  8:10 UTC (permalink / raw)
  To: Arturo Borrero Gonzalez
  Cc: Ismo Puustinen, Netfilter Development Mailing list

On Thu, Jun 08, 2017 at 06:37:57PM +0200, Arturo Borrero Gonzalez wrote:
> On 8 June 2017 at 12:17, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
[...]
> > Then, to keep it consistent, we should also display a warning in
> > include file with no .nft postfix. At deprecate the existing behaviour
> > at some point, ie. bail out if you include a file that has no trailing
> > .nft in its name.
> >
> > If we follow this path, all ruleset file will end up using .nft as
> > a trailer in the name.
> >
> 
> but perhaps it makes sense to differentiate two cases:
>  * include a single file: accept arbitrary names
>  * include a whole dir: accept only files ending in .nft
> 
> This seems to be what sysctl(8) does when loading a single file vs a directory.
> I'm thinking in a case where you have a README in the directory or
> other unrelated file.

I see, it makes sense indeed to have a way to skip files you don't
want. But I still would like this behaviour is consistent.

> If the idea is to allow drop files (a good idea indeed), then being
> explicit is a good approach.
> 
> > Is there any other similar software following this approach? How is
> > 'ferm' doing this?
> 
> ferm seems to load arbitrary files. In the docs they suggest using
> .ferm files but the code
> seems to allow whatever.
> However, they have a set of regexp hardcoded to avoid loading things
> like backups file an the like.
> So, yes, probably forcing to .nft is sensible.

I would go for glob support, ie.

include ./nft-ruleset-files/*.nft

so you can explicit indicate what file pattern you want to load.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2017-06-12  8:10 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-06-07  8:35 [PATCH 1/3] scanner: add files in include dirs in alphabetical order Ismo Puustinen
2017-06-07  8:35 ` [PATCH 2/3] man: add include directory documentation Ismo Puustinen
2017-06-07 10:09   ` Pablo Neira Ayuso
2017-06-07  8:35 ` [PATCH 3/3] tests: added tests for ordering files in include dirs Ismo Puustinen
2017-06-07 10:09 ` [PATCH 1/3] scanner: add files in include dirs in alphabetical order Pablo Neira Ayuso
2017-06-07 19:40 ` Arturo Borrero Gonzalez
2017-06-08 10:17   ` Pablo Neira Ayuso
2017-06-08 16:37     ` Arturo Borrero Gonzalez
2017-06-12  8:10       ` Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).