]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdistdist/dnsdist-lua-ffi.cc
dnsdist: Clean up FFI types
[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 void dnsdist_ffi_dnsquestion_get_masked_remoteaddr(dnsdist_ffi_dnsquestion_t* dq, const void** addr, size_t* addrSize, uint8_t bits)
59 {
60 dq->maskedRemote = Netmask(*dq->dq->remote, bits).getMaskedNetwork();
61 dnsdist_ffi_comboaddress_to_raw(dq->maskedRemote, addr, addrSize);
62 }
63
64 uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t* dq)
65 {
66 return dq->dq->local->getPort();
67 }
68
69 uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t* dq)
70 {
71 return dq->dq->remote->getPort();
72 }
73
74 void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t* dq, const char** qname, size_t* qnameSize)
75 {
76 const auto& storage = dq->dq->qname->getStorage();
77 *qname = storage.data();
78 *qnameSize = storage.size();
79 }
80
81 size_t dnsdist_ffi_dnsquestion_get_qname_hash(const dnsdist_ffi_dnsquestion_t* dq, size_t init)
82 {
83 return dq->dq->qname->hash(init);
84 }
85
86 int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
87 {
88 return dq->dq->dh->rcode;
89 }
90
91 void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
92 {
93 return dq->dq->dh;
94 }
95
96 uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
97 {
98 return dq->dq->len;
99 }
100
101 size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq)
102 {
103 return dq->dq->size;
104 }
105
106 uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq)
107 {
108 return dq->dq->dh->opcode;
109 }
110
111 bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq)
112 {
113 return dq->dq->tcp;
114 }
115
116 bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t* dq)
117 {
118 return dq->dq->skipCache;
119 }
120
121 bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t* dq)
122 {
123 return dq->dq->useECS;
124 }
125
126 bool dnsdist_ffi_dnsquestion_get_add_xpf(const dnsdist_ffi_dnsquestion_t* dq)
127 {
128 return dq->dq->addXPF;
129 }
130
131 bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq)
132 {
133 return dq->dq->ecsOverride;
134 }
135
136 uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq)
137 {
138 return dq->dq->ecsPrefixLength;
139 }
140
141 bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq)
142 {
143 return dq->dq->tempFailureTTL != boost::none;
144 }
145
146 uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t* dq)
147 {
148 if (dq->dq->tempFailureTTL) {
149 return *dq->dq->tempFailureTTL;
150 }
151 return 0;
152 }
153
154 bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t* dq)
155 {
156 return getEDNSZ(*dq->dq) & EDNS_HEADER_FLAG_DO;
157 }
158
159 void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t* dq, const char** sni, size_t* sniSize)
160 {
161 *sniSize = dq->dq->sni.size();
162 *sni = dq->dq->sni.c_str();
163 }
164
165 const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t* dq, const char* label)
166 {
167 const char * result = nullptr;
168
169 if (dq->dq->qTag != nullptr) {
170 const auto it = dq->dq->qTag->find(label);
171 if (it != dq->dq->qTag->cend()) {
172 result = it->second.c_str();
173 }
174 }
175
176 return result;
177 }
178
179 const char* dnsdist_ffi_dnsquestion_get_http_path(dnsdist_ffi_dnsquestion_t* dq)
180 {
181 if (!dq->httpPath) {
182 if (dq->dq->du == nullptr) {
183 return nullptr;
184 }
185 #ifdef HAVE_DNS_OVER_HTTPS
186 dq->httpPath = dq->dq->du->getHTTPPath();
187 #endif /* HAVE_DNS_OVER_HTTPS */
188 }
189 if (dq->httpPath) {
190 return dq->httpPath->c_str();
191 }
192 return nullptr;
193 }
194
195 const char* dnsdist_ffi_dnsquestion_get_http_query_string(dnsdist_ffi_dnsquestion_t* dq)
196 {
197 if (!dq->httpQueryString) {
198 if (dq->dq->du == nullptr) {
199 return nullptr;
200 }
201 #ifdef HAVE_DNS_OVER_HTTPS
202 dq->httpQueryString = dq->dq->du->getHTTPQueryString();
203 #endif /* HAVE_DNS_OVER_HTTPS */
204 }
205 if (dq->httpQueryString) {
206 return dq->httpQueryString->c_str();
207 }
208 return nullptr;
209 }
210
211 const char* dnsdist_ffi_dnsquestion_get_http_host(dnsdist_ffi_dnsquestion_t* dq)
212 {
213 if (!dq->httpHost) {
214 if (dq->dq->du == nullptr) {
215 return nullptr;
216 }
217 #ifdef HAVE_DNS_OVER_HTTPS
218 dq->httpHost = dq->dq->du->getHTTPHost();
219 #endif /* HAVE_DNS_OVER_HTTPS */
220 }
221 if (dq->httpHost) {
222 return dq->httpHost->c_str();
223 }
224 return nullptr;
225 }
226
227 const char* dnsdist_ffi_dnsquestion_get_http_scheme(dnsdist_ffi_dnsquestion_t* dq)
228 {
229 if (!dq->httpScheme) {
230 if (dq->dq->du == nullptr) {
231 return nullptr;
232 }
233 #ifdef HAVE_DNS_OVER_HTTPS
234 dq->httpScheme = dq->dq->du->getHTTPScheme();
235 #endif /* HAVE_DNS_OVER_HTTPS */
236 }
237 if (dq->httpScheme) {
238 return dq->httpScheme->c_str();
239 }
240 return nullptr;
241 }
242
243 static void fill_edns_option(const EDNSOptionViewValue& value, dnsdist_ffi_ednsoption_t& option)
244 {
245 option.len = value.size;
246 option.data = nullptr;
247
248 if (value.size > 0) {
249 option.data = value.content;
250 }
251 }
252
253 // returns the length of the resulting 'out' array. 'out' is not set if the length is 0
254 size_t dnsdist_ffi_dnsquestion_get_edns_options(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_ednsoption_t** out)
255 {
256 if (dq->dq->ednsOptions == nullptr) {
257 parseEDNSOptions(*(dq->dq));
258 }
259
260 size_t totalCount = 0;
261 for (const auto& option : *dq->dq->ednsOptions) {
262 totalCount += option.second.values.size();
263 }
264
265 dq->ednsOptionsVect.clear();
266 dq->ednsOptionsVect.resize(totalCount);
267 size_t pos = 0;
268 for (const auto& option : *dq->dq->ednsOptions) {
269 for (const auto& entry : option.second.values) {
270 fill_edns_option(entry, dq->ednsOptionsVect.at(pos));
271 dq->ednsOptionsVect.at(pos).optionCode = option.first;
272 pos++;
273 }
274 }
275
276 if (totalCount > 0) {
277 *out = dq->ednsOptionsVect.data();
278 }
279
280 return totalCount;
281 }
282
283 size_t dnsdist_ffi_dnsquestion_get_http_headers(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_http_header_t** out)
284 {
285 if (dq->dq->du == nullptr) {
286 return 0;
287 }
288
289 #ifdef HAVE_DNS_OVER_HTTPS
290 dq->httpHeaders = dq->dq->du->getHTTPHeaders();
291 dq->httpHeadersVect.clear();
292 dq->httpHeadersVect.resize(dq->httpHeaders.size());
293 size_t pos = 0;
294 for (const auto& header : dq->httpHeaders) {
295 dq->httpHeadersVect.at(pos).name = header.first.c_str();
296 dq->httpHeadersVect.at(pos).value = header.second.c_str();
297 ++pos;
298 }
299
300 if (!dq->httpHeadersVect.empty()) {
301 *out = dq->httpHeadersVect.data();
302 }
303
304 return dq->httpHeadersVect.size();
305 #else
306 return 0;
307 #endif
308 }
309
310 size_t dnsdist_ffi_dnsquestion_get_tag_array(dnsdist_ffi_dnsquestion_t* dq, const dnsdist_ffi_tag_t** out)
311 {
312 if (dq->dq->qTag == nullptr || dq->dq->qTag->size() == 0) {
313 return 0;
314 }
315
316 dq->tagsVect.clear();
317 dq->tagsVect.resize(dq->dq->qTag->size());
318 size_t pos = 0;
319
320 for (const auto& tag : *dq->dq->qTag) {
321 auto& entry = dq->tagsVect.at(pos);
322 entry.name = tag.first.c_str();
323 entry.value = tag.second.c_str();
324 ++pos;
325 }
326
327
328 if (!dq->tagsVect.empty()) {
329 *out = dq->tagsVect.data();
330 }
331
332 return dq->tagsVect.size();
333 }
334
335 void dnsdist_ffi_dnsquestion_set_result(dnsdist_ffi_dnsquestion_t* dq, const char* str, size_t strSize)
336 {
337 dq->result = std::string(str, strSize);
338 }
339
340 void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, const char* contentType)
341 {
342 if (dq->dq->du == nullptr) {
343 return;
344 }
345
346 #ifdef HAVE_DNS_OVER_HTTPS
347 dq->dq->du->setHTTPResponse(statusCode, body, contentType);
348 dq->dq->dh->qr = true;
349 #endif
350 }
351
352 void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
353 {
354 dq->dq->dh->rcode = rcode;
355 dq->dq->dh->qr = true;
356 }
357
358 void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
359 {
360 dq->dq->len = len;
361 }
362
363 void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t* dq, bool skipCache)
364 {
365 dq->dq->skipCache = skipCache;
366 }
367
368 void dnsdist_ffi_dnsquestion_set_use_ecs(dnsdist_ffi_dnsquestion_t* dq, bool useECS)
369 {
370 dq->dq->useECS = useECS;
371 }
372
373 void dnsdist_ffi_dnsquestion_set_ecs_override(dnsdist_ffi_dnsquestion_t* dq, bool ecsOverride)
374 {
375 dq->dq->ecsOverride = ecsOverride;
376 }
377
378 void dnsdist_ffi_dnsquestion_set_ecs_prefix_length(dnsdist_ffi_dnsquestion_t* dq, uint16_t ecsPrefixLength)
379 {
380 dq->dq->ecsPrefixLength = ecsPrefixLength;
381 }
382
383 void dnsdist_ffi_dnsquestion_set_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq, uint32_t tempFailureTTL)
384 {
385 dq->dq->tempFailureTTL = tempFailureTTL;
386 }
387
388 void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq)
389 {
390 dq->dq->tempFailureTTL = boost::none;
391 }
392
393 void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value)
394 {
395 if (!dq->dq->qTag) {
396 dq->dq->qTag = std::make_shared<QTag>();
397 }
398
399 dq->dq->qTag->insert({label, value});
400 }
401
402 size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out)
403 {
404 dq->trailingData = dq->dq->getTrailingData();
405 if (!dq->trailingData.empty()) {
406 *out = dq->trailingData.data();
407 }
408
409 return dq->trailingData.size();
410 }
411
412 bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen)
413 {
414 return dq->dq->setTrailingData(std::string(data, dataLen));
415 }
416
417 void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen)
418 {
419 if (g_snmpAgent && g_snmpTrapsEnabled) {
420 g_snmpAgent->sendDNSTrap(*dq->dq, std::string(reason, reasonLen));
421 }
422 }
423
424 size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list)
425 {
426 return list->ffiServers.size();
427 }
428
429 void dnsdist_ffi_servers_list_get_server(const dnsdist_ffi_servers_list_t* list, size_t idx, const dnsdist_ffi_server_t** out)
430 {
431 *out = &list->ffiServers.at(idx);
432 }
433
434 static size_t dnsdist_ffi_servers_get_index_from_server(const ServerPolicy::NumberedServerVector& servers, const std::shared_ptr<DownstreamState>& server)
435 {
436 for (const auto& pair : servers) {
437 if (pair.second == server) {
438 return pair.first - 1;
439 }
440 }
441 throw std::runtime_error("Unable to find servers in server list");
442 }
443
444 size_t dnsdist_ffi_servers_list_chashed(const dnsdist_ffi_servers_list_t* list, const dnsdist_ffi_dnsquestion_t* dq, size_t hash)
445 {
446 auto server = chashedFromHash(list->servers, hash);
447 return dnsdist_ffi_servers_get_index_from_server(list->servers, server);
448 }
449
450 size_t dnsdist_ffi_servers_list_whashed(const dnsdist_ffi_servers_list_t* list, const dnsdist_ffi_dnsquestion_t* dq, size_t hash)
451 {
452 auto server = whashedFromHash(list->servers, hash);
453 return dnsdist_ffi_servers_get_index_from_server(list->servers, server);
454 }
455
456 uint64_t dnsdist_ffi_server_get_outstanding(const dnsdist_ffi_server_t* server)
457 {
458 return server->server->outstanding;
459 }
460
461 int dnsdist_ffi_server_get_weight(const dnsdist_ffi_server_t* server)
462 {
463 return server->server->weight;
464 }
465
466 int dnsdist_ffi_server_get_order(const dnsdist_ffi_server_t* server)
467 {
468 return server->server->order;
469 }
470
471 bool dnsdist_ffi_server_is_up(const dnsdist_ffi_server_t* server)
472 {
473 return server->server->isUp();
474 }
475
476 const char* dnsdist_ffi_server_get_name(const dnsdist_ffi_server_t* server)
477 {
478 return server->server->getName().c_str();
479 }
480
481 const char* dnsdist_ffi_server_get_name_with_addr(const dnsdist_ffi_server_t* server)
482 {
483 return server->server->getNameWithAddr().c_str();
484 }
485
486 const std::string& getLuaFFIWrappers()
487 {
488 static const std::string interface =
489 #include "dnsdist-lua-ffi-interface.inc"
490 ;
491 static const std::string code = R"FFICodeContent(
492 local ffi = require("ffi")
493 local C = ffi.C
494
495 ffi.cdef[[
496 )FFICodeContent" + interface + R"FFICodeContent(
497 ]]
498
499 )FFICodeContent";
500 return code;
501 }