From: Otto Moerbeek Date: Mon, 14 Sep 2020 08:14:41 +0000 (+0200) Subject: Rough draft of fd passing for rec_control X-Git-Tag: dnsdist-1.6.0-alpha2~39^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed7e7c0adf214d5cfb8fb6403dcb8d10acd726a0;p=thirdparty%2Fpdns.git Rough draft of fd passing for rec_control --- diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 1f5ee52e3e..fda3a859d8 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -3898,7 +3898,7 @@ static void handleRCC(int fd, FDMultiplexer::funcparam_t& var) RecursorControlParser::func_t* command; g_log << Logger::Notice << "Received rec_control command '" << msg << "' from control socket" << endl; - string answer=rcp.getAnswer(msg, &command); + string answer=rcp.getAnswer(fd, msg, &command); // If we are inside a chroot, we need to strip if (!arg()["chroot"].empty()) { diff --git a/pdns/rec_channel.cc b/pdns/rec_channel.cc index 303b40cbfa..8e77f20a6d 100644 --- a/pdns/rec_channel.cc +++ b/pdns/rec_channel.cc @@ -144,7 +144,42 @@ void RecursorControlChannel::connect(const string& path, const string& fname) } } -void RecursorControlChannel::send(const std::string& msg, const std::string* remote, unsigned int timeout) +static void sendfd(int s, int fd, const string* remote) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct iovec io_vector[1]; + char ch = 'X'; + + io_vector[0].iov_base = &ch; + io_vector[0].iov_len = 1; + + memset(&msg, 0, sizeof(msg)); + if (remote) { + msg.msg_name = const_cast(remote->c_str()); + msg.msg_namelen = remote->length(); + } + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; + + if (sendmsg(s, &msg, 0) == -1) { + throw PDNSException("Unable to send fd message over control channel: "+stringerror()); + } +} + +void RecursorControlChannel::send(const std::string& msg, const std::string* remote, unsigned int timeout, int fd) { int ret = waitForRWData(d_fd, false, timeout, 0); if(ret == 0) { @@ -167,6 +202,10 @@ void RecursorControlChannel::send(const std::string& msg, const std::string* rem } else if(::send(d_fd, msg.c_str(), msg.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) diff --git a/pdns/rec_channel.hh b/pdns/rec_channel.hh index 2ffccdef87..7337bd93f7 100644 --- a/pdns/rec_channel.hh +++ b/pdns/rec_channel.hh @@ -51,7 +51,7 @@ public: uint64_t getStat(const std::string& name); - void send(const std::string& msg, const std::string* remote=nullptr, unsigned int timeout=5); + 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); int d_fd; @@ -68,7 +68,7 @@ public: } static void nop(void){} typedef void func_t(void); - std::string getAnswer(const std::string& question, func_t** func); + std::string 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 0bcc47238e..684eade7d5 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -293,16 +293,55 @@ static string doDumpNSSpeeds(T begin, T end) return "dumped "+std::to_string(total)+" records\n"; } +static int +getfd(int s) +{ + int fd = -1; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct iovec io_vector[1]; + char ch; + + io_vector[0].iov_base = &ch; + io_vector[0].iov_len = 1; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + msg.msg_iov = io_vector; + msg.msg_iovlen = 1; + + if (recvmsg(s, &msg, 0) == -1) + throw PDNSException("recvmsg"); + if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) + throw PDNSException("control message truncated"); + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && + cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + fd = *(int *)CMSG_DATA(cmsg); + } + } + return fd; +} + template -static string doDumpCache(T begin, T end) +static string doDumpCache(int s, T begin, T end) { + + int fd = getfd(s); + T i=begin; string fname; if(i!=end) fname=*i; - int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); if(fd < 0) return "Error opening dump file for writing: "+stringerror()+"\n"; uint64_t total = 0; @@ -1679,7 +1718,7 @@ static string clearDontThrottleNetmasks(T begin, T end) { return ret + "\n"; } -string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command) +string RecursorControlParser::getAnswer(int s, const string& question, RecursorControlParser::func_t** command) { *command=nop; vector words; @@ -1775,7 +1814,7 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP } if(cmd=="dump-cache") - return doDumpCache(begin, end); + return doDumpCache(s, begin, end); if(cmd=="dump-ednsstatus" || cmd=="dump-edns") return doDumpEDNSStatus(begin, end); diff --git a/pdns/rec_control.cc b/pdns/rec_control.cc index cf5bbecf82..08b553ecf4 100644 --- a/pdns/rec_control.cc +++ b/pdns/rec_control.cc @@ -99,12 +99,16 @@ try const vector&commands=arg().getCommands(); string command; + int fd = -1; for(unsigned int i=0; i< commands.size(); ++i) { if(i>0) command+=" "; + if (commands[i] == "dump-cache") { + fd = STDOUT_FILENO; // XXX + } command+=commands[i]; } - rccS.send(command, nullptr, arg().asNum("timeout")); + rccS.send(command, nullptr, arg().asNum("timeout"), fd); string receive=rccS.recv(0, arg().asNum("timeout")); if(receive.compare(0, 7, "Unknown") == 0) { cerr<