From: Otto Moerbeek Date: Fri, 18 Dec 2020 10:49:47 +0000 (+0100) Subject: Return command status and output as two separate items X-Git-Tag: dnsdist-1.6.0-alpha2~39^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2157aec4c1f504dab0611b6e50de3c74f8f0a43e;p=thirdparty%2Fpdns.git Return command status and output as two separate items --- diff --git a/pdns/lua-base4.cc b/pdns/lua-base4.cc index bce88d1418..d36fc1e8c0 100644 --- a/pdns/lua-base4.cc +++ b/pdns/lua-base4.cc @@ -16,13 +16,16 @@ BaseLua4::BaseLua4() { } -void BaseLua4::loadFile(const std::string &fname) { +int BaseLua4::loadFile(const std::string &fname) { + int ret = 0; std::ifstream ifs(fname); - if(!ifs) { + if (!ifs) { + ret = errno; g_log< >& operator+=(vector& operator+=(std::pair& a, const std::pair& b) +{ + a.first |= b.first; + a.second += b.second; + return a; +} + /* This function should only be called by the handler to gather metrics, wipe the cache, reload the Lua script (not the Lua config) or change the current trace regex, @@ -3884,6 +3891,7 @@ template T broadcastAccFunction(const boost::function& func) } template string broadcastAccFunction(const boost::function& fun); // explicit instantiation +template std::pair broadcastAccFunction(const boost::function*()>& fun); // explicit instantiation template uint64_t broadcastAccFunction(const boost::function& fun); // explicit instantiation template vector broadcastAccFunction(const boost::function *()>& fun); // explicit instantiation template vector > broadcastAccFunction(const boost::function > *()>& fun); // explicit instantiation @@ -3893,12 +3901,12 @@ static void handleRCC(int fd, FDMultiplexer::funcparam_t& var) { try { string remote; - string msg=s_rcc.recv(&remote); + string msg = s_rcc.recv(&remote).second; RecursorControlParser rcp; RecursorControlParser::func_t* command; g_log << Logger::Notice << "Received rec_control command '" << msg << "' from control socket" << endl; - string answer=rcp.getAnswer(fd, msg, &command); + auto answer = rcp.getAnswer(fd, msg, &command); // If we are inside a chroot, we need to strip if (!arg()["chroot"].empty()) { @@ -4109,35 +4117,40 @@ static FDMultiplexer* getMultiplexer() } -static string* doReloadLuaScript() +static std::pair* doReloadLuaScript() { string fname= ::arg()["lua-dns-script"]; try { if(fname.empty()) { t_pdl.reset(); g_log<(0, string("unloaded\n")); } else { t_pdl = std::make_shared(); - t_pdl->loadFile(fname); + int err = t_pdl->loadFile(fname); + if (err != 0) { + string msg = std::to_string(t_id) + " Retaining current script, could not read '" + fname + "': " + stringerror(err); + g_log<(1, msg + "\n"); + } } } catch(std::exception& e) { g_log<(1, string("retaining current script, error from '"+fname+"': "+e.what()+"\n")); } g_log<(0, string("(re)loaded '"+fname+"'\n")); } -string doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end) +std::pair doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end) { if(begin != end) ::arg().set("lua-dns-script") = *begin; - return broadcastAccFunction(doReloadLuaScript); + return broadcastAccFunction>(doReloadLuaScript); } static string* pleaseUseNewTraceRegex(const std::string& newRegex) diff --git a/pdns/rec_channel.cc b/pdns/rec_channel.cc index 8e77f20a6d..3d95e5b772 100644 --- a/pdns/rec_channel.cc +++ b/pdns/rec_channel.cc @@ -179,7 +179,7 @@ static void sendfd(int s, int fd, const string* remote) } } -void RecursorControlChannel::send(const std::string& msg, const std::string* remote, unsigned int timeout, int fd) +void RecursorControlChannel::send(const std::pair& msg, const std::string* remote, unsigned int timeout, int fd) { int ret = waitForRWData(d_fd, false, timeout, 0); if(ret == 0) { @@ -197,34 +197,45 @@ void RecursorControlChannel::send(const std::string& msg, const std::string* rem strncpy(remoteaddr.sun_path, remote->c_str(), sizeof(remoteaddr.sun_path)-1); remoteaddr.sun_path[sizeof(remoteaddr.sun_path)-1] = '\0'; - if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0) + if(::sendto(d_fd, &msg.first, sizeof(msg.first), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0) + throw PDNSException("Unable to send message over control channel '"+string(remoteaddr.sun_path)+"': "+stringerror()); + if(::sendto(d_fd, msg.second.c_str(), msg.second.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0) throw PDNSException("Unable to send message over control channel '"+string(remoteaddr.sun_path)+"': "+stringerror()); } - else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0) - throw PDNSException("Unable to send message over control channel: "+stringerror()); - + else { + if(::send(d_fd, &msg.first, sizeof(msg.first), 0) < 0) + throw PDNSException("Unable to send message over control channel: "+stringerror()); + if(::send(d_fd, msg.second.c_str(), msg.second.length(), 0) < 0) + throw PDNSException("Unable to send message over control channel: "+stringerror()); + } if (fd != -1) { sendfd(d_fd, fd, remote); } } -string RecursorControlChannel::recv(std::string* remote, unsigned int timeout) +std::pair RecursorControlChannel::recv(std::string* remote, unsigned int timeout) { char buffer[16384]; ssize_t len; struct sockaddr_un remoteaddr; - socklen_t addrlen=sizeof(remoteaddr); - - int ret=waitForData(d_fd, timeout, 0); - if(ret==0) + socklen_t addrlen = sizeof(remoteaddr); + + int ret = waitForData(d_fd, timeout, 0); + if (ret == 0) { throw PDNSException("Timeout waiting for answer from control channel"); - - if( ret < 0 || (len=::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0) + } + int err; + if (ret < 0 || ::recvfrom(d_fd, &err, sizeof(err), 0, (struct sockaddr*)&remoteaddr, &addrlen) < 0) { + throw PDNSException("Unable to receive return status over control channel: " + stringerror()); + } + if (ret < 0 || (len = ::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0) { throw PDNSException("Unable to receive message over control channel: "+stringerror()); + } - if(remote) + if(remote) { *remote=remoteaddr.sun_path; + } - return string(buffer, buffer+len); + return make_pair(err, string(buffer, buffer+len)); } diff --git a/pdns/rec_channel.hh b/pdns/rec_channel.hh index 7337bd93f7..2a03b44666 100644 --- a/pdns/rec_channel.hh +++ b/pdns/rec_channel.hh @@ -51,8 +51,8 @@ public: uint64_t getStat(const std::string& name); - void send(const std::string& msg, const std::string* remote=nullptr, unsigned int timeout=5, int fd = -1); - std::string recv(std::string* remote=0, unsigned int timeout=5); + void send(const std::pair&, const std::string* remote=nullptr, unsigned int timeout=5, int fd = -1); + std::pair recv(std::string* remote=0, unsigned int timeout=5); int d_fd; static volatile sig_atomic_t stop; @@ -68,7 +68,7 @@ public: } static void nop(void){} typedef void func_t(void); - std::string getAnswer(int s, const std::string& question, func_t** func); + pair getAnswer(int s, const std::string& question, func_t** func); }; enum class StatComponent { API, Carbon, RecControl, SNMP }; diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index e9fb0fc425..b67796292e 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -1711,21 +1711,22 @@ static string clearDontThrottleNetmasks(T begin, T end) { return ret + "\n"; } -string RecursorControlParser::getAnswer(int s, const string& question, RecursorControlParser::func_t** command) + +std::pair RecursorControlParser::getAnswer(int s, const string& question, RecursorControlParser::func_t** command) { *command=nop; vector words; stringtok(words, question); if(words.empty()) - return "invalid command\n"; + return make_pair(1, "invalid command\n"); string cmd=toLower(words[0]); vector::const_iterator begin=words.begin()+1, end=words.end(); // should probably have a smart dispatcher here, like auth has if(cmd=="help") - return + return make_pair(0, "add-dont-throttle-names [N...] add names that are not allowed to be throttled\n" "add-dont-throttle-netmasks [N...]\n" " add netmasks that are not allowed to be throttled\n" @@ -1781,64 +1782,59 @@ string RecursorControlParser::getAnswer(int s, const string& question, RecursorC "unload-lua-script unload Lua script\n" "version return Recursor version number\n" "wipe-cache domain0 [domain1] .. wipe domain data from cache\n" -"wipe-cache-typed type domain0 [domain1] .. wipe domain data with qtype from cache\n"; - - if(cmd=="get-all") - return getAllStats(); - - if(cmd=="get") - return doGet(begin, end); +"wipe-cache-typed type domain0 [domain1] .. wipe domain data with qtype from cache\n"); - if(cmd=="get-parameter") - return doGetParameter(begin, end); - - if(cmd=="quit") { + if (cmd == "get-all") { + return make_pair(0, getAllStats()); + } + if (cmd == "get") { + return make_pair(0, doGet(begin, end)); + } + if (cmd == "get-parameter") { + return make_pair(0, doGetParameter(begin, end)); + } + if (cmd == "quit") { *command=&doExit; - return "bye\n"; + return make_pair(0, "bye\n"); } - - if(cmd=="version") { - return getPDNSVersion()+"\n"; + if (cmd == "version") { + return make_pair(0, getPDNSVersion()+"\n"); } - - if(cmd=="quit-nicely") { + if (cmd == "quit-nicely") { *command=&doExitNicely; - return "bye nicely\n"; + return make_pair(0, "bye nicely\n"); } - - if(cmd=="dump-cache") - return doDumpCache(s); - - if(cmd=="dump-ednsstatus" || cmd=="dump-edns") - return doDumpEDNSStatus(begin, end); - - if(cmd=="dump-nsspeeds") - return doDumpNSSpeeds(begin, end); - - if(cmd=="dump-failedservers") - return doDumpFailedServers(begin, end); - - if(cmd=="dump-rpz") { - return doDumpRPZ(begin, end); + if (cmd == "dump-cache") { + return make_pair(0, doDumpCache(s)); } - - if(cmd=="dump-throttlemap") - return doDumpThrottleMap(begin, end); - - if(cmd=="wipe-cache" || cmd=="flushname") - return doWipeCache(begin, end, 0xffff); - - if(cmd=="wipe-cache-typed") { + if (cmd == "dump-ednsstatus" || cmd == "dump-edns") { + return make_pair(0, doDumpEDNSStatus(begin, end)); + } + if (cmd == "dump-nsspeeds") { + return make_pair(0, doDumpNSSpeeds(begin, end)); + } + if (cmd == "dump-failedservers") { + return make_pair(0, doDumpFailedServers(begin, end)); + } + if (cmd == "dump-rpz") { + return make_pair(0, doDumpRPZ(begin, end)); + } + if (cmd == "dump-throttlemap") { + return make_pair(0, doDumpThrottleMap(begin, end)); + } + if (cmd == "wipe-cache" || cmd == "flushname") { + return make_pair(0, doWipeCache(begin, end, 0xffff)); + } + if (cmd == "wipe-cache-typed") { uint16_t qtype = QType::chartocode(begin->c_str()); ++begin; - return doWipeCache(begin, end, qtype); + return make_pair(0, doWipeCache(begin, end, qtype)); } - - if(cmd=="reload-lua-script") + if (cmd == "reload-lua-script") { return doQueueReloadLuaScript(begin, end); - - if(cmd=="reload-lua-config") { - if(begin != end) + } + if (cmd == "reload-lua-config") { + if (begin != end) ::arg().set("lua-config-file") = *begin; try { @@ -1846,170 +1842,145 @@ string RecursorControlParser::getAnswer(int s, const string& question, RecursorC loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads); startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation); g_log< empty; empty.push_back(string()); return doQueueReloadLuaScript(empty.begin(), empty.end()); } - - if(cmd=="reload-acls") { - if(!::arg()["chroot"].empty()) { + if (cmd == "reload-acls") { + if (!::arg()["chroot"].empty()) { g_log<(nopFunction); + if (cmd == "top-remotes") { + return make_pair(0, doGenericTopRemotes(pleaseGetRemotes)); } - - if(cmd=="reload-zones") { - if(!::arg()["chroot"].empty()) { + if (cmd == "top-queries") { + return make_pair(0, doGenericTopQueries(pleaseGetQueryRing)); + } + if (cmd == "top-pub-queries") { + return make_pair(0, doGenericTopQueries(pleaseGetQueryRing, getRegisteredName)); + } + if (cmd == "top-servfail-queries") { + return make_pair(0, doGenericTopQueries(pleaseGetServfailQueryRing)); + } + if (cmd == "top-pub-servfail-queries") { + return make_pair(0, doGenericTopQueries(pleaseGetServfailQueryRing, getRegisteredName)); + } + if (cmd == "top-bogus-queries") { + return make_pair(0, doGenericTopQueries(pleaseGetBogusQueryRing)); + } + if (cmd == "top-pub-bogus-queries") { + return make_pair(0, doGenericTopQueries(pleaseGetBogusQueryRing, getRegisteredName)); + } + if (cmd == "top-servfail-remotes") { + return make_pair(0, doGenericTopRemotes(pleaseGetServfailRemotes)); + } + if (cmd == "top-bogus-remotes") { + return make_pair(0, doGenericTopRemotes(pleaseGetBogusRemotes)); + } + if (cmd == "top-largeanswer-remotes") { + return make_pair(0, doGenericTopRemotes(pleaseGetLargeAnswerRemotes)); + } + if (cmd == "top-timeouts") { + return make_pair(0, doGenericTopRemotes(pleaseGetTimeouts)); + } + if (cmd == "current-queries") { + return make_pair(0, doCurrentQueries()); + } + if (cmd == "ping") { + return make_pair(0, broadcastAccFunction(nopFunction)); + } + if (cmd == "reload-zones") { + if (!::arg()["chroot"].empty()) { g_log<&commands=arg().getCommands(); - string command; - int fd = -1; - for(unsigned int i=0; i< commands.size(); ++i) { - if(i>0) - command+=" "; - command+=commands[i]; - if (commands[i] == "dump-cache" && i+1 < commands.size()) { - ++i; - if (commands[i] == "stdout") { - fd = STDOUT_FILENO; - } else { - fd = open(commands[i].c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); - } - if (fd == -1) { - int err = errno; - throw PDNSException("Error opening dump file for writing: " + stringerror(err)); + try { + initArguments(argc, argv); + RecursorControlChannel rccS; + string sockname="pdns_recursor"; + + if (arg()["config-name"] != "") + sockname+="-"+arg()["config-name"]; + + if(!arg()["process"].empty()) + sockname+="."+arg()["process"]; + + sockname.append(".controlsocket"); + + rccS.connect(arg()["socket-dir"], sockname); + + const vector&commands=arg().getCommands(); + string command; + int fd = -1; + for(unsigned int i=0; i< commands.size(); ++i) { + if(i>0) + command+=" "; + command+=commands[i]; + if (commands[i] == "dump-cache" && i+1 < commands.size()) { + ++i; + if (commands[i] == "stdout") { + fd = STDOUT_FILENO; + } else { + fd = open(commands[i].c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + } + if (fd == -1) { + int err = errno; + throw PDNSException("Error opening dump file for writing: " + stringerror(err)); + } } } + + auto timeout = arg().asNum("timeout"); + rccS.send(make_pair(0, command), nullptr, timeout, fd); + + auto receive = rccS.recv(0, timeout); + if (receive.first != 0) { + cerr << receive.second; + } else { + cout << receive.second; + } + return receive.first; } - rccS.send(command, nullptr, arg().asNum("timeout"), fd); - string receive=rccS.recv(0, arg().asNum("timeout")); - if(receive.compare(0, 7, "Unknown") == 0) { - cerr< t_servfailremotes, t_largeans extern thread_local std::unique_ptr > > t_queryring, t_servfailqueryring, t_bogusqueryring; extern thread_local std::shared_ptr t_allowFrom; -string doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end); +std::pair doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end); string doTraceRegex(vector::const_iterator begin, vector::const_iterator end); void parseACLs(); extern RecursorStats g_stats;