]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/lua-recursor4.hh
b90fe7686693343eab0981889352883b3f93ac59
[thirdparty/pdns.git] / pdns / recursordist / lua-recursor4.hh
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
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "iputils.hh"
29 #include "dnsname.hh"
30 #include "namespaces.hh"
31 #include "dnsrecords.hh"
32 #include "filterpo.hh"
33 #include "ednsoptions.hh"
34 #include "validate.hh"
35 #include "lua-base4.hh"
36 #include "proxy-protocol.hh"
37 #include "noinitvector.hh"
38 #include "rec-eventtrace.hh"
39
40 #include <unordered_map>
41
42 #include "lua-recursor4-ffi.hh"
43
44 // pdns_ffi_param_t is a lightuserdata
45 template <>
46 struct LuaContext::Pusher<pdns_ffi_param*>
47 {
48 static const int minSize = 1;
49 static const int maxSize = 1;
50
51 static PushedObject push(lua_State* state, pdns_ffi_param* ptr) noexcept
52 {
53 lua_pushlightuserdata(state, ptr);
54 return PushedObject{state, 1};
55 }
56 };
57
58 // pdns_postresolve_ffi_handle is a lightuserdata
59 template <>
60 struct LuaContext::Pusher<pdns_postresolve_ffi_handle*>
61 {
62 static const int minSize = 1;
63 static const int maxSize = 1;
64
65 static PushedObject push(lua_State* state, pdns_postresolve_ffi_handle* ptr) noexcept
66 {
67 lua_pushlightuserdata(state, ptr);
68 return PushedObject{state, 1};
69 }
70 };
71
72 class RecursorLua4 : public BaseLua4
73 {
74 public:
75 RecursorLua4();
76 RecursorLua4(const RecursorLua4&) = delete;
77 RecursorLua4(RecursorLua4&&) = delete;
78 RecursorLua4& operator=(const RecursorLua4&) = delete;
79 RecursorLua4& operator=(RecursorLua4&&) = delete;
80 ~RecursorLua4() override; // this is so unique_ptr works with an incomplete type
81
82 struct MetaValue
83 {
84 std::unordered_set<std::string> stringVal;
85 std::unordered_set<int64_t> intVal;
86 };
87 struct DNSQuestion
88 {
89 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
90 DNSQuestion(const ComboAddress& rem, const ComboAddress& loc, const DNSName& query, uint16_t type, bool tcp, bool& variable_, bool& wantsRPZ_, bool& logResponse_, bool& addPaddingToResponse_, const struct timeval& queryTime_) :
91 qname(query), qtype(type), local(loc), remote(rem), isTcp(tcp), variable(variable_), wantsRPZ(wantsRPZ_), logResponse(logResponse_), addPaddingToResponse(addPaddingToResponse_), queryTime(queryTime_)
92 {
93 }
94 const DNSName& qname;
95 const uint16_t qtype;
96 const ComboAddress& local;
97 const ComboAddress& remote;
98 const ComboAddress* fromAuthIP{nullptr};
99 const struct dnsheader* dh{nullptr};
100 const bool isTcp;
101 const std::vector<pair<uint16_t, string>>* ednsOptions{nullptr};
102 const uint16_t* ednsFlags{nullptr};
103 vector<DNSRecord>* currentRecords{nullptr};
104 DNSFilterEngine::Policy* appliedPolicy{nullptr};
105 std::unordered_set<std::string>* policyTags{nullptr};
106 const std::vector<ProxyProtocolValue>* proxyProtocolValues{nullptr};
107 std::unordered_map<std::string, bool>* discardedPolicies{nullptr};
108 std::string* extendedErrorExtra{nullptr};
109 boost::optional<uint16_t>* extendedErrorCode{nullptr};
110 std::string requestorId;
111 std::string deviceId;
112 std::string deviceName;
113 vState validationState{vState::Indeterminate};
114 bool& variable;
115 bool& wantsRPZ;
116 bool& logResponse;
117 bool& addPaddingToResponse;
118 unsigned int tag{0};
119 std::map<std::string, MetaValue> meta;
120 struct timeval queryTime;
121
122 void addAnswer(uint16_t type, const std::string& content, boost::optional<int> ttl, boost::optional<string> name);
123 void addRecord(uint16_t type, const std::string& content, DNSResourceRecord::Place place, boost::optional<int> ttl, boost::optional<string> name);
124 [[nodiscard]] vector<pair<int, DNSRecord>> getRecords() const;
125 [[nodiscard]] boost::optional<dnsheader> getDH() const;
126 [[nodiscard]] vector<pair<uint16_t, string>> getEDNSOptions() const;
127 [[nodiscard]] boost::optional<string> getEDNSOption(uint16_t code) const;
128 [[nodiscard]] boost::optional<Netmask> getEDNSSubnet() const;
129 [[nodiscard]] std::vector<std::pair<int, ProxyProtocolValue>> getProxyProtocolValues() const;
130 [[nodiscard]] vector<string> getEDNSFlags() const;
131 [[nodiscard]] bool getEDNSFlag(const string& flag) const;
132 void setRecords(const vector<pair<int, DNSRecord>>& arg);
133
134 int rcode{0};
135 // struct dnsheader, packet length would be great
136 vector<DNSRecord> records;
137
138 string followupFunction;
139 string followupPrefix;
140
141 string udpQuery;
142 ComboAddress udpQueryDest;
143 string udpAnswer;
144 string udpCallback;
145
146 LuaContext::LuaObject data;
147 DNSName followupName;
148 };
149
150 struct PolicyEvent
151 {
152 PolicyEvent(const ComboAddress& rem, const DNSName& name, const QType& type, bool tcp) :
153 qname(name), qtype(type), remote(rem), isTcp(tcp)
154 {
155 }
156 const DNSName& qname;
157 const QType qtype;
158 const ComboAddress& remote;
159 const bool isTcp;
160 DNSFilterEngine::Policy* appliedPolicy{nullptr};
161 std::unordered_set<std::string>* policyTags{nullptr};
162 std::unordered_map<std::string, bool>* discardedPolicies{nullptr};
163 };
164
165 struct FFIParams
166 {
167 public:
168 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
169 FFIParams(const DNSName& qname_, uint16_t qtype_, const ComboAddress& local_, const ComboAddress& remote_, const Netmask& ednssubnet_, LuaContext::LuaObject& data_, std::unordered_set<std::string>& policyTags_, std::vector<DNSRecord>& records_, const EDNSOptionViewMap& ednsOptions_, const std::vector<ProxyProtocolValue>& proxyProtocolValues_, std::string& requestorId_, std::string& deviceId_, std::string& deviceName_, std::string& routingTag_, boost::optional<int>& rcode_, uint32_t& ttlCap_, bool& variable_, bool tcp_, bool& logQuery_, bool& logResponse_, bool& followCNAMERecords_, boost::optional<uint16_t>& extendedErrorCode_, std::string& extendedErrorExtra_, bool& disablePadding_, std::map<std::string, MetaValue>& meta_) :
170 data(data_), qname(qname_), local(local_), remote(remote_), ednssubnet(ednssubnet_), policyTags(policyTags_), records(records_), ednsOptions(ednsOptions_), proxyProtocolValues(proxyProtocolValues_), requestorId(requestorId_), deviceId(deviceId_), deviceName(deviceName_), routingTag(routingTag_), extendedErrorExtra(extendedErrorExtra_), rcode(rcode_), extendedErrorCode(extendedErrorCode_), ttlCap(ttlCap_), variable(variable_), logQuery(logQuery_), logResponse(logResponse_), followCNAMERecords(followCNAMERecords_), disablePadding(disablePadding_), qtype(qtype_), tcp(tcp_), meta(meta_)
171 {
172 }
173
174 LuaContext::LuaObject& data;
175 const DNSName& qname;
176 const ComboAddress& local;
177 const ComboAddress& remote;
178 const Netmask& ednssubnet;
179 std::unordered_set<std::string>& policyTags;
180 std::vector<DNSRecord>& records;
181 const EDNSOptionViewMap& ednsOptions;
182 const std::vector<ProxyProtocolValue>& proxyProtocolValues;
183 std::string& requestorId;
184 std::string& deviceId;
185 std::string& deviceName;
186 std::string& routingTag;
187 std::string& extendedErrorExtra;
188 boost::optional<int>& rcode;
189 boost::optional<uint16_t>& extendedErrorCode;
190 uint32_t& ttlCap;
191 bool& variable;
192 bool& logQuery;
193 bool& logResponse;
194 bool& followCNAMERecords;
195 bool& disablePadding;
196
197 unsigned int tag{0};
198 uint16_t qtype;
199 bool tcp;
200
201 std::map<std::string, MetaValue>& meta;
202 };
203
204 unsigned int gettag(const ComboAddress& remote, const Netmask& ednssubnet, const ComboAddress& local, const DNSName& qname, uint16_t qtype, std::unordered_set<std::string>* policyTags, LuaContext::LuaObject& data, const EDNSOptionViewMap&, bool tcp, std::string& requestorId, std::string& deviceId, std::string& deviceName, std::string& routingTag, const std::vector<ProxyProtocolValue>& proxyProtocolValues) const;
205 unsigned int gettag_ffi(FFIParams&) const;
206
207 void maintenance() const;
208 bool prerpz(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const;
209 bool preresolve(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const;
210 bool nxdomain(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const;
211 bool nodata(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const;
212 bool postresolve(DNSQuestion& dnsQuestion, int& ret, RecEventTrace&) const;
213
214 bool preoutquery(const ComboAddress& nameserver, const ComboAddress& requestor, const DNSName& query, const QType& qtype, bool isTcp, vector<DNSRecord>& res, int& ret, RecEventTrace& eventTrace, const struct timeval& theTime) const;
215 bool ipfilter(const ComboAddress& remote, const ComboAddress& local, const struct dnsheader&, RecEventTrace&) const;
216
217 bool policyHitEventFilter(const ComboAddress& remote, const DNSName& qname, const QType& qtype, bool tcp, DNSFilterEngine::Policy& policy, std::unordered_set<std::string>& tags, std::unordered_map<std::string, bool>& discardedPolicies) const;
218
219 [[nodiscard]] bool needDQ() const
220 {
221 return (d_prerpz || d_preresolve || d_nxdomain || d_nodata || d_postresolve);
222 }
223
224
225 struct PostResolveFFIHandle
226 {
227 PostResolveFFIHandle(DNSQuestion& dnsQuestion) :
228 d_dq(dnsQuestion)
229 {
230 }
231 DNSQuestion& d_dq;
232 bool d_ret{false};
233 };
234 bool postresolve_ffi(PostResolveFFIHandle&) const;
235
236 [[nodiscard]] bool hasGettagFunc() const
237 {
238 return static_cast<bool>(d_gettag);
239 }
240 [[nodiscard]] bool hasGettagFFIFunc() const
241 {
242 return static_cast<bool>(d_gettag_ffi);
243 }
244 [[nodiscard]] bool hasPostResolveFFIfunc() const
245 {
246 return static_cast<bool>(d_postresolve_ffi);
247 }
248
249 protected:
250 void postPrepareContext() override;
251 void postLoad() override;
252 void getFeatures(Features& features) override;
253
254 private:
255 using gettag_t = std::function<std::tuple<unsigned int, boost::optional<std::unordered_map<int, string>>, boost::optional<LuaContext::LuaObject>, boost::optional<std::string>, boost::optional<std::string>, boost::optional<std::string>, boost::optional<string>> (ComboAddress, Netmask, ComboAddress, DNSName, uint16_t, const EDNSOptionViewMap &, bool, const std::vector<std::pair<int, const ProxyProtocolValue *>> &)>;
256 gettag_t d_gettag; // public so you can query if we have this hooked
257
258 using gettag_ffi_t = std::function<boost::optional<LuaContext::LuaObject> (pdns_ffi_param_t *)>;
259 gettag_ffi_t d_gettag_ffi;
260
261 using postresolve_ffi_t = std::function<bool (pdns_postresolve_ffi_handle_t *)>;
262 postresolve_ffi_t d_postresolve_ffi;
263
264 using luamaintenance_t = std::function<void ()>;
265 luamaintenance_t d_maintenance;
266
267 using luacall_t = std::function<bool (DNSQuestion *)>;
268 luacall_t d_prerpz, d_preresolve, d_nxdomain, d_nodata, d_postresolve, d_preoutquery, d_postoutquery;
269 bool genhook(const luacall_t& func, DNSQuestion& dnsQuestion, int& ret) const;
270
271 using ipfilter_t = std::function<bool (ComboAddress, ComboAddress, struct dnsheader)>;
272 ipfilter_t d_ipfilter;
273
274 using policyEventFilter_t = std::function<bool (PolicyEvent &)>;
275 policyEventFilter_t d_policyHitEventFilter;
276 };