thread_local std::shared_ptr<RecursorLua4> t_pdl;
thread_local std::shared_ptr<Regex> t_traceRegex;
+thread_local int t_tracefd = -1;
thread_local ProtobufServersInfo t_protobufServers;
thread_local ProtobufServersInfo t_outgoingProtobufServers;
}
#endif // HAVE_FSTRM
+static void dumpTrace(const string& trace)
+{
+ if (trace.empty()) {
+ return;
+ }
+ int traceFd = dup(t_tracefd);
+ if (traceFd == -1) {
+ int err = errno;
+ SLOG(g_log << Logger::Error << "Could not dup trace file: " << stringerror(err) << endl,
+ g_slog->withName("trace")->error(Logr::Error, err, "Could not dup trace file"));
+ return;
+ }
+ auto filep = std::unique_ptr<FILE, decltype(&fclose)>(fdopen(traceFd, "a"), &fclose);
+ if (!filep) {
+ int err = errno;
+ SLOG(g_log << Logger::Error << "Could not write to trace file: " << stringerror(err) << endl,
+ g_slog->withName("trace")->error(Logr::Error, err, "Could not write to trace file"));
+ close(traceFd);
+ return;
+ }
+ vector<string> lines;
+ boost::split(lines, trace, boost::is_any_of("\n"));
+ int count = 0;
+ for (const string& line : lines) {
+ if (!line.empty())
+ fprintf(filep.get(), "%04d %s\n", ++count, line.c_str());
+ }
+ fprintf(filep.get(), "\n");
+ // fclose by unique_ptr does implicit flush
+}
+
void startDoResolve(void* p)
{
auto dc = std::unique_ptr<DNSComboWriter>(reinterpret_cast<DNSComboWriter*>(p));
haveAnswer:;
if (tracedQuery || res == -1 || res == RCode::ServFail || pw.getHeader()->rcode == RCode::ServFail) {
- string trace(sr.getTrace());
- if (!trace.empty()) {
- vector<string> lines;
- boost::split(lines, trace, boost::is_any_of("\n"));
- for (const string& line : lines) {
- if (!line.empty())
- g_log << Logger::Warning << line << endl;
- }
- }
+ dumpTrace(sr.getTrace());
}
if (res == -1) {
return broadcastAccFunction<RecursorControlChannel::Answer>(doReloadLuaScript);
}
-static string* pleaseUseNewTraceRegex(const std::string& newRegex)
-try {
- if (newRegex.empty()) {
- t_traceRegex.reset();
- return new string("unset\n");
- }
- else {
+static string* pleaseUseNewTraceRegex(const std::string& newRegex, int file)
+{
+ try {
+ if (newRegex.empty()) {
+ t_traceRegex.reset();
+ close(t_tracefd);
+ t_tracefd = -1;
+ return new string("unset\n");
+ }
+ if (file == -1) {
+ return new string("could not dup file\n");
+ }
+ if (t_tracefd != -1) {
+ close(t_tracefd);
+ }
t_traceRegex = std::make_shared<Regex>(newRegex);
+ t_tracefd = file;
return new string("ok\n");
}
-}
-catch (PDNSException& ae) {
- return new string(ae.reason + "\n");
+ catch (PDNSException& ae) {
+ return new string(ae.reason + "\n");
+ }
}
-string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end)
+string doTraceRegex(FDWrapper file, vector<string>::const_iterator begin, vector<string>::const_iterator end)
{
- return broadcastAccFunction<string>([=] { return pleaseUseNewTraceRegex(begin != end ? *begin : ""); });
+ int fileno = dup(file);
+ // Potential dup failure handled in pleaseUseNewTraceRegex()
+ return broadcastAccFunction<string>([=] { return pleaseUseNewTraceRegex(begin != end ? *begin : "", fileno); });
}
static uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree, uint16_t qtype)
extern std::shared_ptr<NetmaskGroup> g_initialAllowNotifyFrom; // new threads need this to be setup
extern std::shared_ptr<notifyset_t> g_initialAllowNotifyFor; // new threads need this to be setup
extern thread_local std::shared_ptr<Regex> t_traceRegex;
+extern thread_local int t_tracefd;
extern string g_programname;
extern string g_pidfname;
extern RecursorControlChannel g_rcc; // only active in the handler thread
void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t&);
void makeUDPServerSockets(deferredAdd_t& deferredAdds, Logr::log_t);
+string doTraceRegex(FDWrapper file, vector<string>::const_iterator begin, vector<string>::const_iterator end);
#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10"
#define LOCAL_NETS_INVERSE "!127.0.0.0/8, !10.0.0.0/8, !100.64.0.0/10, !169.254.0.0/16, !192.168.0.0/16, !172.16.0.0/12, !::1/128, !fc00::/7, !fe80::/10"
return {0, doSetCarbonServer(begin, end)};
}
if (cmd == "trace-regex") {
- return {0, doTraceRegex(begin, end)};
+ return {0, doTraceRegex(begin == end ? FDWrapper(-1) : getfd(s), begin, end)};
}
if (cmd == "unload-lua-script") {
vector<string> empty;
"dump-non-resolving",
"dump-saved-parent-ns-sets",
"dump-dot-probe-map",
+ "trace-regex",
};
try {
initArguments(argc, argv);
command += " ";
}
command += commands[i];
- if (fileCommands.count(commands[i]) > 0) {
+
+ // special case: trace-regex with no arguments is clear regex
+ auto traceregexClear = command == "trace-regex" && commands.size() == 1;
+
+ if (fileCommands.count(commands[i]) > 0 && !traceregexClear) {
if (i + 1 < commands.size()) {
// dump-rpz is different, it also has a zonename as argument
- if (commands[i] == "dump-rpz") {
+ // trace-regex is different, it also has a regexp as argument
+ if (commands[i] == "dump-rpz" || commands[i] == "trace-regex") {
if (i + 2 < commands.size()) {
++i;
- command += " " + commands[i]; // add rpzname and continue with filename
+ command += " ";
+ command += commands[i]; // add rpzname/regex and continue with filename
}
else {
- throw PDNSException("Command needs a zone and file argument");
+ throw PDNSException("Command needs two arguments");
}
}
++i;
extern thread_local std::unique_ptr<boost::circular_buffer<pair<DNSName, uint16_t>>> t_queryring, t_servfailqueryring, t_bogusqueryring;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowFrom;
extern thread_local std::shared_ptr<NetmaskGroup> t_allowNotifyFrom;
-string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end);
extern unsigned int g_networkTimeoutMsec;
extern uint16_t g_outgoingEDNSBufsize;
extern std::atomic<uint32_t> g_maxCacheEntries, g_maxPacketCacheEntries;