]> git.ipfire.org Git - thirdparty/pdns.git/blame - 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
CommitLineData
5e7672ff
RG
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
26uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t* dq)
27{
28 return dq->dq->qtype;
29}
30
31uint16_t dnsdist_ffi_dnsquestion_get_qclass(const dnsdist_ffi_dnsquestion_t* dq)
32{
33 return dq->dq->qclass;
34}
35
36static 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
48void 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
53void 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
0ed8f0fa
RG
58uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t* dq)
59{
60 return dq->dq->local->getPort();
61}
62
63uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq)
64{
65 return dq->dq->remote->getPort();
66}
67
5e7672ff
RG
68void 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
75int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
76{
77 return dq->dq->dh->rcode;
78}
79
80void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
81{
82 return dq->dq->dh;
83}
84
85uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
86{
87 return dq->dq->len;
88}
89
90size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq)
91{
92 return dq->dq->size;
93}
94
95uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq)
96{
97 return dq->dq->dh->opcode;
98}
99
100bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq)
101{
102 return dq->dq->tcp;
103}
104
105bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t* dq)
106{
107 return dq->dq->skipCache;
108}
109
110bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t* dq)
111{
112 return dq->dq->useECS;
113}
114
115bool dnsdist_ffi_dnsquestion_get_add_xpf(const dnsdist_ffi_dnsquestion_t* dq)
116{
117 return dq->dq->addXPF;
118}
119
120bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq)
121{
122 return dq->dq->ecsOverride;
123}
124
125uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq)
126{
127 return dq->dq->ecsPrefixLength;
128}
129
130bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq)
131{
132 return dq->dq->tempFailureTTL != boost::none;
133}
134
135uint32_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
143bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq)
144{
145 return getEDNSZ(*dq->dq) & EDNS_HEADER_FLAG_DO;
146}
147
148void 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
154const 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
168const 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
184const 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
200const 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
216const 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
232static 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
243size_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
272size_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
0ed8f0fa
RG
299size_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
b774d943
RG
324void 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
5e7672ff
RG
329void 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
341void 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
347void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
348{
349 dq->dq->len = len;
350}
351
352void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t* dq, bool skipCache)
353{
354 dq->dq->skipCache = skipCache;
355}
356
357void dnsdist_ffi_dnsquestion_set_use_ecs(dnsdist_ffi_dnsquestion_t* dq, bool useECS)
358{
359 dq->dq->useECS = useECS;
360}
361
362void dnsdist_ffi_dnsquestion_set_ecs_override(dnsdist_ffi_dnsquestion_t* dq, bool ecsOverride)
363{
364 dq->dq->ecsOverride = ecsOverride;
365}
366
367void dnsdist_ffi_dnsquestion_set_ecs_prefix_length(dnsdist_ffi_dnsquestion_t* dq, uint16_t ecsPrefixLength)
368{
369 dq->dq->ecsPrefixLength = ecsPrefixLength;
370}
371
372void dnsdist_ffi_dnsquestion_set_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t tempFailureTTL)
373{
374 dq->dq->tempFailureTTL = tempFailureTTL;
375}
376
0ed8f0fa
RG
377void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq)
378{
379 dq->dq->tempFailureTTL = boost::none;
380}
381
5e7672ff
RG
382void 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}
0ed8f0fa
RG
390
391size_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
401bool 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
406void 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
413const 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}