From: Remi Gacogne Date: Mon, 27 Mar 2023 15:03:43 +0000 (+0200) Subject: dnsdist: Add an option to write `grepq`'s output to a file X-Git-Tag: dnsdist-1.9.0-alpha0~1^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b2e8ead56feaf9da6380468017a1b536694873b;p=thirdparty%2Fpdns.git dnsdist: Add an option to write `grepq`'s output to a file --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index 86647243ad..7eff465774 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -548,7 +548,7 @@ const std::vector g_consoleKeywords{ { "getTLSFrontend", true, "n", "returns the TLS frontend with index n" }, { "getTLSFrontendCount", true, "", "returns the number of DoT listeners" }, { "getVerbose", true, "", "get whether log messages at the verbose level will be logged" }, - { "grepq", true, "Netmask|DNS Name|100ms|{\"::1\", \"powerdns.com\", \"100ms\"} [, n]", "shows the last n queries and responses matching the specified client address or range (Netmask), or the specified DNS Name, or slower than 100ms" }, + { "grepq", true, "Netmask|DNS Name|100ms|{\"::1\", \"powerdns.com\", \"100ms\"} [, n] [,options]", "shows the last n queries and responses matching the specified client address or range (Netmask), or the specified DNS Name, or slower than 100ms" }, { "hashPassword", true, "password [, workFactor]", "Returns a hashed and salted version of the supplied password, usable with 'setWebserverConfig()'"}, { "HTTPHeaderRule", true, "name, regex", "matches DoH queries with a HTTP header 'name' whose content matches the regular expression 'regex'"}, { "HTTPPathRegexRule", true, "regex", "matches DoH queries whose HTTP path matches 'regex'"}, diff --git a/pdns/dnsdist-lua-inspection.cc b/pdns/dnsdist-lua-inspection.cc index 86b3e0b591..b1f7ac0e09 100644 --- a/pdns/dnsdist-lua-inspection.cc +++ b/pdns/dnsdist-lua-inspection.cc @@ -19,6 +19,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include + #include "dnsdist.hh" #include "dnsdist-lua.hh" #include "dnsdist-dynblocks.hh" @@ -408,11 +410,28 @@ void setupLuaInspection(LuaContext& luaCtx) } }); - luaCtx.writeFunction("grepq", [](LuaTypeOrArrayOf inp, boost::optional limit) { + luaCtx.writeFunction("grepq", [](LuaTypeOrArrayOf inp, boost::optional limit, boost::optional> options) { setLuaNoSideEffect(); boost::optional nm; boost::optional dn; int msec=-1; + std::unique_ptr outputFile{nullptr, fclose}; + + if (options) { + if (options->count("outputFile")) { + const std::string& outputFileName = options->at("outputFile"); + int fd = open(outputFileName.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0600); + if (fd < 0) { + g_outputBuffer = "Error opening dump file for writing: " + stringerror() + "\n"; + return; + } + outputFile = std::unique_ptr(fdopen(fd, "w"), fclose); + if (outputFile == nullptr) { + g_outputBuffer = "Error opening dump file for writing: " + stringerror() + "\n"; + return; + } + } + } vector vec; auto str=boost::get(&inp); @@ -477,8 +496,13 @@ void setupLuaInspection(LuaContext& luaCtx) std::multimap out; - boost::format fmt("%-7.1f %-47s %-12s %-12s %-5d %-25s %-5s %-6.1f %-2s %-2s %-2s %-s\n"); - g_outputBuffer+= (fmt % "Time" % "Client" % "Protocol" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str(); + boost::format fmt("%-7.1f %-47s %-12s %-12s %-5d %-25s %-5s %-6.1f %-2s %-2s %-2s %-s\n"); + if (!outputFile) { + g_outputBuffer += (fmt % "Time" % "Client" % "Protocol" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str(); + } + else { + fprintf(outputFile.get(), "%s", (fmt % "Time" % "Client" % "Protocol" % "Server" % "ID" % "Name" % "Type" % "Lat." % "TC" % "RD" % "AA" % "Rcode").str().c_str()); + } if(msec==-1) { for(const auto& c : qr) { @@ -556,8 +580,13 @@ void setupLuaInspection(LuaContext& luaCtx) } } - for(const auto& p : out) { - g_outputBuffer+=p.second; + for (const auto& p : out) { + if (!outputFile) { + g_outputBuffer += p.second; + } + else { + fprintf(outputFile.get(), "%s", p.second.c_str()); + } } }); diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index d7c41e7317..d67c0b1c41 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -1138,8 +1138,11 @@ Status, Statistics and More :param int top: How many rules to return. Default is 10. -.. function:: grepq(selector[, num]) - grepq(selectors[, num]) +.. function:: grepq(selector[, num [, options]]) + grepq(selectors[, num [, options]]) + + .. versionchanged:: 1.9.0 + ``options`` optional parameter table added. Prints the last ``num`` queries and responses matching ``selector`` or ``selectors``. Queries and responses are accounted in separate ring buffers, and answers from the packet cache are not stored in the response ring buffer. @@ -1154,6 +1157,11 @@ Status, Statistics and More :param str selector: Select queries based on this property. :param {str} selectors: A lua table of selectors. Only queries matching all selectors are shown :param int num: Show a maximum of ``num`` recent queries+responses, default is 10. + :param table options: A table with key: value pairs with options described below. + + Options: + + * ``outputFile=path``: string - Write the output of the command to the supplied file, instead of the standard output. .. function:: setVerbose(verbose)