]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdistdist/dnsdist-lua-ffi.cc
dnsdist: Allow wrapping the FFI interface for the existing DNSQuestion object
[thirdparty/pdns.git] / pdns / dnsdistdist / dnsdist-lua-ffi.cc
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
23 #include "dnsdist-lua-ffi.hh"
24 #include "dnsdist-ecs.hh"
25
26 uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
27 {
28 return dq->dq->qtype;
29 }
30
31 uint16_t dnsdist_ffi_dnsquestion_get_qclass(const dnsdist_ffi_dnsquestion_t* dq)
32 {
33 return dq->dq->qclass;
34 }
35
36 static void dnsdist_ffi_comboaddress_to_raw(const ComboAddress& ca, const void** addr, size_t* addrSize)
37 {
38 if (ca.isIPv4()) {
39 *addr = &ca.sin4.sin_addr.s_addr;
40 *addrSize = sizeof(ca.sin4.sin_addr.s_addr);
41 }
42 else {
43 *addr = &ca.sin6.sin6_addr.s6_addr;
44 *addrSize = sizeof(ca.sin6.sin6_addr.s6_addr);
45 }
46 }
47
48 void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize)
49 {
50 dnsdist_ffi_comboaddress_to_raw(*dq->dq->local, addr, addrSize);
51 }
52
53 void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize)
54 {
55 dnsdist_ffi_comboaddress_to_raw(*dq->dq->remote, addr, addrSize);
56 }
57
58 uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t* dq)
59 {
60 return dq->dq->local->getPort();
61 }
62
63 uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq)
64 {
65 return dq->dq->remote->getPort();
66 }
67
68 void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize)
69 {
70 const auto& storage = dq->dq->qname->getStorage();
71 *qname = storage.data();
72 *qnameSize = storage.size();
73 }
74
75 int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
76 {
77 return dq->dq->dh->rcode;
78 }
79
80 void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
81 {
82 return dq->dq->dh;
83 }
84
85 uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
86 {
87 return dq->dq->len;
88 }
89
90 size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq)
91 {
92 return dq->dq->size;
93 }
94
95 uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq)
96 {
97 return dq->dq->dh->opcode;
98 }
99
100 bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq)
101 {
102 return dq->dq->tcp;
103 }
104
105 bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t* dq)
106 {
107 return dq->dq->skipCache;
108 }
109
110 bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t* dq)
111 {
112 return dq->dq->useECS;
113 }
114
115 bool dnsdist_ffi_dnsquestion_get_add_xpf(const dnsdist_ffi_dnsquestion_t* dq)
116 {
117 return dq->dq->addXPF;
118 }
119
120 bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq)
121 {
122 return dq->dq->ecsOverride;
123 }
124
125 uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq)
126 {
127 return dq->dq->ecsPrefixLength;
128 }
129
130 bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq)
131 {
132 return dq->dq->tempFailureTTL != boost::none;
133 }
134
135 uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t* dq)
136 {
137 if (dq->dq->tempFailureTTL) {
138 return *dq->dq->tempFailureTTL;
139 }
140 return 0;
141 }
142
143 bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq)
144 {
145 return getEDNSZ(*dq->dq) & EDNS_HEADER_FLAG_DO;
146 }
147
148 void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize)
149 {
150 *sniSize = dq->dq->sni.size();
151 *sni = dq->dq->sni.c_str();
152 }
153
154 const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label)
155 {
156 const char * result = nullptr;
157
158 if (dq->dq->qTag != nullptr) {
159 const auto it = dq->dq->qTag->find(label);
160 if (it != dq->dq->qTag->cend()) {
161 result = it->second.c_str();
162 }
163 }
164
165 return result;
166 }
167
168 const char* dnsdist_ffi_dnsquestion_get_http_path(dnsdist_ffi_dnsquestion_t* dq)
169 {
170 if (!dq->httpPath) {
171 if (dq->dq->du == nullptr) {
172 return nullptr;
173 }
174 #ifdef HAVE_DNS_OVER_HTTPS
175 dq->httpPath = dq->dq->du->getHTTPPath();
176 #endif /* HAVE_DNS_OVER_HTTPS */
177 }
178 if (dq->httpPath) {
179 return dq->httpPath->c_str();
180 }
181 return nullptr;
182 }
183
184 const char* dnsdist_ffi_dnsquestion_get_http_query_string(dnsdist_ffi_dnsquestion_t* dq)
185 {
186 if (!dq->httpQueryString) {
187 if (dq->dq->du == nullptr) {
188 return nullptr;
189 }
190 #ifdef HAVE_DNS_OVER_HTTPS
191 dq->httpQueryString = dq->dq->du->getHTTPQueryString();
192 #endif /* HAVE_DNS_OVER_HTTPS */
193 }
194 if (dq->httpQueryString) {
195 return dq->httpQueryString->c_str();
196 }
197 return nullptr;
198 }
199
200 const char* dnsdist_ffi_dnsquestion_get_http_host(dnsdist_ffi_dnsquestion_t* dq)
201 {
202 if (!dq->httpHost) {
203 if (dq->dq->du == nullptr) {
204 return nullptr;
205 }
206 #ifdef HAVE_DNS_OVER_HTTPS
207 dq->httpHost = dq->dq->du->getHTTPHost();
208 #endif /* HAVE_DNS_OVER_HTTPS */
209 }
210 if (dq->httpHost) {
211 return dq->httpHost->c_str();
212 }
213 return nullptr;
214 }
215
216 const char* dnsdist_ffi_dnsquestion_get_http_scheme(dnsdist_ffi_dnsquestion_t* dq)
217 {
218 if (!dq->httpScheme) {
219 if (dq->dq->du == nullptr) {
220 return nullptr;
221 }
222 #ifdef HAVE_DNS_OVER_HTTPS
223 dq->httpScheme = dq->dq->du->getHTTPScheme();
224 #endif /* HAVE_DNS_OVER_HTTPS */
225 }
226 if (dq->httpScheme) {
227 return dq->httpScheme->c_str();
228 }
229 return nullptr;
230 }
231
232 static void fill_edns_option(const EDNSOptionViewValue& value, dnsdist_ednsoption_t& option)
233 {
234 option.len = value.size;
235 option.data = nullptr;
236
237 if (value.size > 0) {
238 option.data = value.content;
239 }
240 }
241
242 // returns the length of the resulting 'out' array. 'out' is not set if the length is 0
243 size_t dnsdist_ffi_dnsquestion_get_edns_options(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ednsoption_t** out)
244 {
245 if (dq->dq->ednsOptions == nullptr) {
246 parseEDNSOptions(*(dq->dq));
247 }
248
249 size_t totalCount = 0;
250 for (const auto& option : *dq->dq->ednsOptions) {
251 totalCount += option.second.values.size();
252 }
253
254 dq->ednsOptionsVect.clear();
255 dq->ednsOptionsVect.resize(totalCount);
256 size_t pos = 0;
257 for (const auto& option : *dq->dq->ednsOptions) {
258 for (const auto& entry : option.second.values) {
259 fill_edns_option(entry, dq->ednsOptionsVect.at(pos));
260 dq->ednsOptionsVect.at(pos).optionCode = option.first;
261 pos++;
262 }
263 }
264
265 if (totalCount > 0) {
266 *out = dq->ednsOptionsVect.data();
267 }
268
269 return totalCount;
270 }
271
272 size_t dnsdist_ffi_dnsquestion_get_http_headers(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_http_header_t** out)
273 {
274 if (dq->dq->du == nullptr) {
275 return 0;
276 }
277
278 #ifdef HAVE_DNS_OVER_HTTPS
279 dq->httpHeaders = dq->dq->du->getHTTPHeaders();
280 dq->httpHeadersVect.clear();
281 dq->httpHeadersVect.resize(dq->httpHeaders.size());
282 size_t pos = 0;
283 for (const auto& header : dq->httpHeaders) {
284 dq->httpHeadersVect.at(pos).name = header.first.c_str();
285 dq->httpHeadersVect.at(pos).value = header.second.c_str();
286 ++pos;
287 }
288
289 if (!dq->httpHeadersVect.empty()) {
290 *out = dq->httpHeadersVect.data();
291 }
292
293 return dq->httpHeadersVect.size();
294 #else
295 return 0;
296 #endif
297 }
298
299 size_t dnsdist_ffi_dnsquestion_get_tag_array(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_tag_t** out)
300 {
301 if (dq->dq->qTag == nullptr || dq->dq->qTag->size() == 0) {
302 return 0;
303 }
304
305 dq->tagsVect.clear();
306 dq->tagsVect.resize(dq->dq->qTag->size());
307 size_t pos = 0;
308
309 for (const auto& tag : *dq->dq->qTag) {
310 auto& entry = dq->tagsVect.at(pos);
311 entry.name = tag.first.c_str();
312 entry.value = tag.second.c_str();
313 ++pos;
314 }
315
316
317 if (!dq->tagsVect.empty()) {
318 *out = dq->tagsVect.data();
319 }
320
321 return dq->tagsVect.size();
322 }
323
324 void dnsdist_ffi_dnsquestion_set_result(dnsdist_ffi_dnsquestion_t* dq, const char* str, size_t strSize)
325 {
326 dq->result = std::string(str, strSize);
327 }
328
329 void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, const char* contentType)
330 {
331 if (dq->dq->du == nullptr) {
332 return;
333 }
334
335 #ifdef HAVE_DNS_OVER_HTTPS
336 dq->dq->du->setHTTPResponse(statusCode, body, contentType);
337 dq->dq->dh->qr = true;
338 #endif
339 }
340
341 void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
342 {
343 dq->dq->dh->rcode = rcode;
344 dq->dq->dh->qr = true;
345 }
346
347 void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
348 {
349 dq->dq->len = len;
350 }
351
352 void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t* dq, bool skipCache)
353 {
354 dq->dq->skipCache = skipCache;
355 }
356
357 void dnsdist_ffi_dnsquestion_set_use_ecs(dnsdist_ffi_dnsquestion_t* dq, bool useECS)
358 {
359 dq->dq->useECS = useECS;
360 }
361
362 void dnsdist_ffi_dnsquestion_set_ecs_override(dnsdist_ffi_dnsquestion_t* dq, bool ecsOverride)
363 {
364 dq->dq->ecsOverride = ecsOverride;
365 }
366
367 void dnsdist_ffi_dnsquestion_set_ecs_prefix_length(dnsdist_ffi_dnsquestion_t* dq, uint16_t ecsPrefixLength)
368 {
369 dq->dq->ecsPrefixLength = ecsPrefixLength;
370 }
371
372 void dnsdist_ffi_dnsquestion_set_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t tempFailureTTL)
373 {
374 dq->dq->tempFailureTTL = tempFailureTTL;
375 }
376
377 void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq)
378 {
379 dq->dq->tempFailureTTL = boost::none;
380 }
381
382 void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value)
383 {
384 if (!dq->dq->qTag) {
385 dq->dq->qTag = std::make_shared<QTag>();
386 }
387
388 dq->dq->qTag->insert({label, value});
389 }
390
391 size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out)
392 {
393 dq->trailingData = dq->dq->getTrailingData();
394 if (!dq->trailingData.empty()) {
395 *out = dq->trailingData.data();
396 }
397
398 return dq->trailingData.size();
399 }
400
401 bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen)
402 {
403 return dq->dq->setTrailingData(std::string(data, dataLen));
404 }
405
406 void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
407 {
408 if (g_snmpAgent && g_snmpTrapsEnabled) {
409 g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
410 }
411 }
412
413 const std::string& getLuaFFIWrappers()
414 {
415 static const std::string interface =
416 #include "dnsdist-lua-ffi-interface.inc"
417 ;
418 static const std::string code = R"FFICodeContent(
419 local ffi = require("ffi")
420 local C = ffi.C
421
422 ffi.cdef[[
423 )FFICodeContent" + interface + R"FFICodeContent(
424 ]]
425
426 )FFICodeContent";
427 return code;
428 }