Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions doc/userguide/configuration/includes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ is the equivalent of::
address-groups:
HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"

Glob Patterns
-------------

Filenames in ``include`` may contain shell-style glob metacharacters
(``*``, ``?``, ``[...]``). Patterns are expanded at startup via
``glob(3)`` and each matching file is loaded in lexicographic order. A

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the 3 mean in glob(3) ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

man 3 glob
image

pattern that matches no files is logged as a warning and is not treated
as an error, which allows drop-in ``conf.d/``-style directories to be
empty.

::

include:
- /etc/suricata/conf.d/*.yaml

Relative patterns are resolved against the directory of the top-level
configuration file, the same as literal includes.

.. note:: Suricata versions less than 7 required multiple ``include``
statements to be specified to include more than one file. While
Suricata 7.0 still supports this it will issue a deprecation
Expand Down
79 changes: 64 additions & 15 deletions src/conf-yaml-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
#include "conf.h"
#include "conf-yaml-loader.h"
#include <yaml.h>
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#include "util-path.h"
#include "util-debug.h"
#include "util-unittest.h"
Expand Down Expand Up @@ -104,18 +107,17 @@ ConfYamlSetConfDirname(const char *filename)
}

/**
* \brief Include a file in the configuration.
* \brief Include a single resolved file in the configuration.
*
* \param parent The configuration node the included configuration will be
* placed at.
* \param filename The filename to include.
* \param filename The fully resolved filename to include.
*
* \retval 0 on success, -1 on failure.
*/
int SCConfYamlHandleInclude(SCConfNode *parent, const char *filename)
static int ConfYamlHandleIncludeOne(SCConfNode *parent, const char *filename)
{
yaml_parser_t parser;
char include_filename[PATH_MAX];
FILE *file = NULL;
int ret = -1;

Expand All @@ -124,18 +126,9 @@ int SCConfYamlHandleInclude(SCConfNode *parent, const char *filename)
return -1;
}

if (PathIsAbsolute(filename)) {
strlcpy(include_filename, filename, sizeof(include_filename));
}
else {
snprintf(include_filename, sizeof(include_filename), "%s/%s",
conf_dirname, filename);
}

file = fopen(include_filename, "r");
file = fopen(filename, "r");
if (file == NULL) {
SCLogError("Failed to open configuration include file %s: %s", include_filename,
strerror(errno));
SCLogError("Failed to open configuration include file %s: %s", filename, strerror(errno));
goto done;
}

Expand All @@ -157,6 +150,62 @@ int SCConfYamlHandleInclude(SCConfNode *parent, const char *filename)
return ret;
}

/**
* \brief Include a file or glob pattern in the configuration.
*
* Relative paths are resolved against the directory of the top-level config
* file. If the input contains glob metacharacters (\c *, \c ?, \c [) the
* pattern is expanded via glob(3) and each match is included in lexicographic
* order. A pattern that matches no files is logged as a warning and not
* treated as an error, to support drop-in `conf.d/` directories.
*
* \param parent The configuration node the included configuration will be
* placed at.
* \param filename The filename or glob pattern to include.
*
* \retval 0 on success, -1 on failure.
*/
int SCConfYamlHandleInclude(SCConfNode *parent, const char *filename)
{
char include_filename[PATH_MAX];

if (PathIsAbsolute(filename)) {
strlcpy(include_filename, filename, sizeof(include_filename));
} else {
snprintf(include_filename, sizeof(include_filename), "%s/%s", conf_dirname, filename);
}

#ifdef HAVE_GLOB_H
if (strpbrk(filename, "*?[") != NULL) {
glob_t globbuf;
int gret = glob(include_filename, 0, NULL, &globbuf);

if (gret == GLOB_NOMATCH) {
SCLogWarning("No files match include pattern %s", include_filename);
return 0;
} else if (gret != 0) {
SCLogError(
"Failed to expand include pattern %s: %s", include_filename, strerror(errno));
return -1;
}

int ret = 0;
for (size_t i = 0; i < (size_t)globbuf.gl_pathc; i++) {
const char *path = globbuf.gl_pathv[i];
SCLogInfo("Including configuration file %s (matched %s).", path, filename);
if (ConfYamlHandleIncludeOne(parent, path) != 0) {
ret = -1;
break;
}
}
globfree(&globbuf);
return ret;
}
#endif

return ConfYamlHandleIncludeOne(parent, include_filename);
}

/**
* \brief Parse a YAML layer.
*
Expand Down
Loading