From: phonedph1 Date: Fri, 20 Dec 2019 17:05:11 +0000 (+0000) Subject: LogResponseAction X-Git-Tag: auth-4.3.0-beta1~49^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b62c160bc4063fe91d9d307e740109c521ce2939;p=thirdparty%2Fpdns.git LogResponseAction --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index c6a9b8132a..e53cf8d611 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -422,6 +422,7 @@ const std::vector g_consoleKeywords{ { "KeyValueStoreLookupRule", true, "kvs, lookupKey", "matches queries if the key is found in the specified Key Value store" }, { "leastOutstanding", false, "", "Send traffic to downstream server with least outstanding queries, with the lowest 'order', and within that the lowest recent latency"}, { "LogAction", true, "[filename], [binary], [append], [buffered]", "Log a line for each query, to the specified file if any, to the console (require verbose) otherwise. When logging to a file, the `binary` optional parameter specifies whether we log in binary form (default) or in textual form, the `append` optional parameter specifies whether we open the file for appending or truncate each time (default), and the `buffered` optional parameter specifies whether writes to the file are buffered (default) or not." }, + { "LogResponseAction", true, "[filename], [append], [buffered]", "Log a line for each response, to the specified file if any, to the console (require verbose) otherwise. The `append` optional parameter specifies whether we open the file for appending or truncate each time (default), and the `buffered` optional parameter specifies whether writes to the file are buffered (default) or not." }, { "LuaAction", true, "function", "Invoke a Lua function that accepts a DNSQuestion" }, { "LuaResponseAction", true, "function", "Invoke a Lua function that accepts a DNSResponse" }, { "MacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action" }, diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index 8312af301c..0c3ae18a07 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -629,6 +629,64 @@ private: bool d_includeTimestamp{false}; }; +class LogResponseAction : public DNSResponseAction, public boost::noncopyable +{ +public: + LogResponseAction(): d_fp(nullptr, fclose) + { + } + + LogResponseAction(const std::string& str, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp) + { + if(str.empty()) + return; + if(append) + d_fp = std::unique_ptr(fopen(str.c_str(), "a+"), fclose); + else + d_fp = std::unique_ptr(fopen(str.c_str(), "w"), fclose); + if(!d_fp) + throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror()); + if(!buffered) + setbuf(d_fp.get(), 0); + } + + DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override + { + if (!d_fp) { + if (!d_verboseOnly || g_verbose) { + if (d_includeTimestamp) { + infolog("[%u.%u] Answer to %s for %s %s (%s) with id %d", static_cast(dr->queryTime->tv_sec), static_cast(dr->queryTime->tv_nsec), dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id); + } + else { + infolog("Answer to %s for %s %s (%s) with id %d", dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id); + } + } + } + else { + if (d_includeTimestamp) { + fprintf(d_fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %d\n", static_cast(dr->queryTime->tv_sec), static_cast(dr->queryTime->tv_nsec), dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id); + } + else { + fprintf(d_fp.get(), "Answer to %s for %s %s (%s) with id %d\n", dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id); + } + } + return Action::None; + } + + std::string toString() const override + { + if (!d_fname.empty()) { + return "log to " + d_fname; + } + return "log"; + } +private: + std::string d_fname; + std::unique_ptr d_fp{nullptr, fclose}; + bool d_verboseOnly{true}; + bool d_includeTimestamp{false}; +}; + class DisableValidationAction : public DNSAction { @@ -1324,6 +1382,10 @@ void setupLuaActions() return std::shared_ptr(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); }); + g_lua.writeFunction("LogResponseAction", [](boost::optional fname, boost::optional append, boost::optional buffered, boost::optional verboseOnly, boost::optional includeTimestamp) { + return std::shared_ptr(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false)); + }); + g_lua.writeFunction("RCodeAction", [](uint8_t rcode) { return std::shared_ptr(new RCodeAction(rcode)); });