1 /*
2  * This file is part of PowerDNS or dnsdist.
3  * Copyright -- PowerDNS.COM B.V. and its contributors
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * In addition, for the avoidance of any doubt, permission is granted to
10  * link this program with OpenSSL and to (re)distribute the binaries
11  * produced as the result of such linking.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 #pragma once
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 
26 #include <string>
27 #include "pdns/arguments.hh"
28 #include "pdns/dns.hh"
29 #include "pdns/dnsbackend.hh"
30 #include "pdns/dnspacket.hh"
31 #include "pdns/logger.hh"
32 #include "pdns/namespaces.hh"
33 #include "pdns/pdnsexception.hh"
34 #include "pdns/sstuff.hh"
35 #include "pdns/json.hh"
36 #include "pdns/lock.hh"
37 #include "yahttp/yahttp.hpp"
38 
39 #ifdef REMOTEBACKEND_ZEROMQ
40 #include <zmq.h>
41 
42 // If the available ZeroMQ library version is < 2.x, create macros for the zmq_msg_send/recv functions
43 #ifndef HAVE_ZMQ_MSG_SEND
44 #define zmq_msg_send(msg, socket, flags) zmq_send(socket, msg, flags)
45 #define zmq_msg_recv(msg, socket, flags) zmq_recv(socket, msg, flags)
46 #endif
47 #endif
48 
49 using json11::Json;
50 
51 class Connector
52 {
53 public:
~Connector()54   virtual ~Connector(){};
55   bool send(Json& value);
56   bool recv(Json& value);
57   virtual int send_message(const Json& input) = 0;
58   virtual int recv_message(Json& output) = 0;
59 
60 protected:
asString(const Json & value)61   string asString(const Json& value)
62   {
63     if (value.is_number())
64       return std::to_string(value.int_value());
65     if (value.is_bool())
66       return (value.bool_value() ? "1" : "0");
67     if (value.is_string())
68       return value.string_value();
69     throw JsonException("Json value not convertible to String");
70   };
71 };
72 
73 // fwd declarations
74 class UnixsocketConnector : public Connector
75 {
76 public:
77   UnixsocketConnector(std::map<std::string, std::string> options);
78   virtual ~UnixsocketConnector();
79   virtual int send_message(const Json& input);
80   virtual int recv_message(Json& output);
81 
82 private:
83   ssize_t read(std::string& data);
84   ssize_t write(const std::string& data);
85   void reconnect();
86   std::map<std::string, std::string> options;
87   int fd;
88   std::string path;
89   bool connected;
90   int timeout;
91 };
92 
93 class HTTPConnector : public Connector
94 {
95 public:
96   HTTPConnector(std::map<std::string, std::string> options);
97   ~HTTPConnector();
98 
99   virtual int send_message(const Json& input);
100   virtual int recv_message(Json& output);
101 
102 private:
103   std::string d_url;
104   std::string d_url_suffix;
105   std::string d_data;
106   int timeout;
107   bool d_post;
108   bool d_post_json;
109   void restful_requestbuilder(const std::string& method, const Json& parameters, YaHTTP::Request& req);
110   void post_requestbuilder(const Json& input, YaHTTP::Request& req);
111   void addUrlComponent(const Json& parameters, const string& element, std::stringstream& ss);
112   std::string buildMemberListArgs(std::string prefix, const Json& args);
113   std::unique_ptr<Socket> d_socket;
114   ComboAddress d_addr;
115   std::string d_host;
116   uint16_t d_port;
117 };
118 
119 #ifdef REMOTEBACKEND_ZEROMQ
120 class ZeroMQConnector : public Connector
121 {
122 public:
123   ZeroMQConnector(std::map<std::string, std::string> options);
124   virtual ~ZeroMQConnector();
125   virtual int send_message(const Json& input);
126   virtual int recv_message(Json& output);
127 
128 private:
129   void connect();
130   std::string d_endpoint;
131   int d_timeout;
132   int d_timespent;
133   std::map<std::string, std::string> d_options;
134   std::unique_ptr<void, int (*)(void*)> d_ctx;
135   std::unique_ptr<void, int (*)(void*)> d_sock;
136 };
137 #endif
138 
139 class PipeConnector : public Connector
140 {
141 public:
142   PipeConnector(std::map<std::string, std::string> options);
143   ~PipeConnector();
144 
145   virtual int send_message(const Json& input);
146   virtual int recv_message(Json& output);
147 
148 private:
149   void launch();
150   bool checkStatus();
151 
152   std::string command;
153   std::map<std::string, std::string> options;
154 
155   int d_fd1[2], d_fd2[2];
156   int d_pid;
157   int d_timeout;
158   std::unique_ptr<FILE, int (*)(FILE*)> d_fp{nullptr, fclose};
159 };
160 
161 class RemoteBackend : public DNSBackend
162 {
163 public:
164   RemoteBackend(const std::string& suffix = "");
165   ~RemoteBackend();
166 
167   void lookup(const QType& qtype, const DNSName& qdomain, int zoneId = -1, DNSPacket* pkt_p = nullptr) override;
168   bool get(DNSResourceRecord& rr) override;
169   bool list(const DNSName& target, int domain_id, bool include_disabled = false) override;
170 
171   bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string>>& meta) override;
172   bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override;
173   bool getDomainKeys(const DNSName& name, std::vector<DNSBackend::KeyData>& keys) override;
174   bool getTSIGKey(const DNSName& name, DNSName* algorithm, std::string* content) override;
175   bool getBeforeAndAfterNamesAbsolute(uint32_t id, const DNSName& qname, DNSName& unhashed, DNSName& before, DNSName& after) override;
176   bool setDomainMetadata(const DNSName& name, const string& kind, const std::vector<std::basic_string<char>>& meta) override;
177   bool removeDomainKey(const DNSName& name, unsigned int id) override;
178   bool addDomainKey(const DNSName& name, const KeyData& key, int64_t& id) override;
179   bool activateDomainKey(const DNSName& name, unsigned int id) override;
180   bool deactivateDomainKey(const DNSName& name, unsigned int id) override;
181   bool publishDomainKey(const DNSName& name, unsigned int id) override;
182   bool unpublishDomainKey(const DNSName& name, unsigned int id) override;
183   bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getSerial = true) override;
184   void setNotified(uint32_t id, uint32_t serial) override;
185   bool doesDNSSEC() override;
186   bool superMasterBackend(const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string* nameserver, string* account, DNSBackend** ddb) override;
187   bool createSlaveDomain(const string& ip, const DNSName& domain, const string& nameserver, const string& account) override;
188   bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset) override;
189   bool feedRecord(const DNSResourceRecord& r, const DNSName& ordername, bool ordernameIsNSEC3 = false) override;
190   bool feedEnts(int domain_id, map<DNSName, bool>& nonterm) override;
191   bool feedEnts3(int domain_id, const DNSName& domain, map<DNSName, bool>& nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) override;
192   bool startTransaction(const DNSName& domain, int domain_id) override;
193   bool commitTransaction() override;
194   bool abortTransaction() override;
195   bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) override;
196   bool deleteTSIGKey(const DNSName& name) override;
197   bool getTSIGKeys(std::vector<struct TSIGKey>& keys) override;
198   string directBackendCmd(const string& querystr) override;
199   bool searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result) override;
200   bool searchComments(const string& pattern, int maxResults, vector<Comment>& result) override;
201   void getAllDomains(vector<DomainInfo>* domains, bool include_disabled = false) override;
202   void getUpdatedMasters(vector<DomainInfo>* domains) override;
203   void alsoNotifies(const DNSName& domain, set<string>* ips) override;
204   void getUnfreshSlaveInfos(vector<DomainInfo>* domains) override;
205   void setStale(uint32_t domain_id) override;
206   void setFresh(uint32_t domain_id) override;
207 
208   static DNSBackend* maker();
209 
210 private:
211   int build();
212   std::unique_ptr<Connector> connector;
213   bool d_dnssec;
214   Json d_result;
215   int d_index;
216   int64_t d_trxid;
217   std::string d_connstr;
218 
219   bool send(Json& value);
220   bool recv(Json& value);
221   void makeErrorAndThrow(Json& value);
222 
asString(const Json & value)223   string asString(const Json& value)
224   {
225     if (value.is_number())
226       return std::to_string(value.int_value());
227     if (value.is_bool())
228       return (value.bool_value() ? "1" : "0");
229     if (value.is_string())
230       return value.string_value();
231     throw JsonException("Json value not convertible to String");
232   };
233 
asBool(const Json & value)234   bool asBool(const Json& value)
235   {
236     if (value.is_bool())
237       return value.bool_value();
238     try {
239       string val = asString(value);
240       if (val == "0")
241         return false;
242       if (val == "1")
243         return true;
244     }
245     catch (const JsonException&) {
246     };
247     throw JsonException("Json value not convertible to boolean");
248   };
249 
250   void parseDomainInfo(const json11::Json& obj, DomainInfo& di);
251 };
252