2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
23 #include "dnsdist-lua-ffi.hh"
24 #include "dnsdist-ecs.hh"
26 uint16_t dnsdist_ffi_dnsquestion_get_qtype(const dnsdist_ffi_dnsquestion_t
* dq
)
31 uint16_t dnsdist_ffi_dnsquestion_get_qclass(const dnsdist_ffi_dnsquestion_t
* dq
)
33 return dq
->dq
->qclass
;
36 static void dnsdist_ffi_comboaddress_to_raw(const ComboAddress
& ca
, const void** addr
, size_t* addrSize
)
39 *addr
= &ca
.sin4
.sin_addr
.s_addr
;
40 *addrSize
= sizeof(ca
.sin4
.sin_addr
.s_addr
);
43 *addr
= &ca
.sin6
.sin6_addr
.s6_addr
;
44 *addrSize
= sizeof(ca
.sin6
.sin6_addr
.s6_addr
);
48 void dnsdist_ffi_dnsquestion_get_localaddr(const dnsdist_ffi_dnsquestion_t
* dq
, const void** addr
, size_t* addrSize
)
50 dnsdist_ffi_comboaddress_to_raw(*dq
->dq
->local
, addr
, addrSize
);
53 void dnsdist_ffi_dnsquestion_get_remoteaddr(const dnsdist_ffi_dnsquestion_t
* dq
, const void** addr
, size_t* addrSize
)
55 dnsdist_ffi_comboaddress_to_raw(*dq
->dq
->remote
, addr
, addrSize
);
58 uint16_t dnsdist_ffi_dnsquestion_get_local_port(const dnsdist_ffi_dnsquestion_t
* dq
)
60 return dq
->dq
->local
->getPort();
63 uint16_t dnsdist_ffi_dnsquestion_get_remote_port(const dnsdist_ffi_dnsquestion_t
* dq
)
65 return dq
->dq
->remote
->getPort();
68 void dnsdist_ffi_dnsquestion_get_qname_raw(const dnsdist_ffi_dnsquestion_t
* dq
, const char** qname
, size_t* qnameSize
)
70 const auto& storage
= dq
->dq
->qname
->getStorage();
71 *qname
= storage
.data();
72 *qnameSize
= storage
.size();
75 int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t
* dq
)
77 return dq
->dq
->dh
->rcode
;
80 void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t
* dq
)
85 uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t
* dq
)
90 size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t
* dq
)
95 uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t
* dq
)
97 return dq
->dq
->dh
->opcode
;
100 bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t
* dq
)
105 bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t
* dq
)
107 return dq
->dq
->skipCache
;
110 bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t
* dq
)
112 return dq
->dq
->useECS
;
115 bool dnsdist_ffi_dnsquestion_get_add_xpf(const dnsdist_ffi_dnsquestion_t
* dq
)
117 return dq
->dq
->addXPF
;
120 bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t
* dq
)
122 return dq
->dq
->ecsOverride
;
125 uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t
* dq
)
127 return dq
->dq
->ecsPrefixLength
;
130 bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t
* dq
)
132 return dq
->dq
->tempFailureTTL
!= boost::none
;
135 uint32_t dnsdist_ffi_dnsquestion_get_temp_failure_ttl(const dnsdist_ffi_dnsquestion_t
* dq
)
137 if (dq
->dq
->tempFailureTTL
) {
138 return *dq
->dq
->tempFailureTTL
;
143 bool dnsdist_ffi_dnsquestion_get_do(const dnsdist_ffi_dnsquestion_t
* dq
)
145 return getEDNSZ(*dq
->dq
) & EDNS_HEADER_FLAG_DO
;
148 void dnsdist_ffi_dnsquestion_get_sni(const dnsdist_ffi_dnsquestion_t
* dq
, const char** sni
, size_t* sniSize
)
150 *sniSize
= dq
->dq
->sni
.size();
151 *sni
= dq
->dq
->sni
.c_str();
154 const char* dnsdist_ffi_dnsquestion_get_tag(const dnsdist_ffi_dnsquestion_t
* dq
, const char* label
)
156 const char * result
= nullptr;
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();
168 const char* dnsdist_ffi_dnsquestion_get_http_path(dnsdist_ffi_dnsquestion_t
* dq
)
171 if (dq
->dq
->du
== nullptr) {
174 #ifdef HAVE_DNS_OVER_HTTPS
175 dq
->httpPath
= dq
->dq
->du
->getHTTPPath();
176 #endif /* HAVE_DNS_OVER_HTTPS */
179 return dq
->httpPath
->c_str();
184 const char* dnsdist_ffi_dnsquestion_get_http_query_string(dnsdist_ffi_dnsquestion_t
* dq
)
186 if (!dq
->httpQueryString
) {
187 if (dq
->dq
->du
== nullptr) {
190 #ifdef HAVE_DNS_OVER_HTTPS
191 dq
->httpQueryString
= dq
->dq
->du
->getHTTPQueryString();
192 #endif /* HAVE_DNS_OVER_HTTPS */
194 if (dq
->httpQueryString
) {
195 return dq
->httpQueryString
->c_str();
200 const char* dnsdist_ffi_dnsquestion_get_http_host(dnsdist_ffi_dnsquestion_t
* dq
)
203 if (dq
->dq
->du
== nullptr) {
206 #ifdef HAVE_DNS_OVER_HTTPS
207 dq
->httpHost
= dq
->dq
->du
->getHTTPHost();
208 #endif /* HAVE_DNS_OVER_HTTPS */
211 return dq
->httpHost
->c_str();
216 const char* dnsdist_ffi_dnsquestion_get_http_scheme(dnsdist_ffi_dnsquestion_t
* dq
)
218 if (!dq
->httpScheme
) {
219 if (dq
->dq
->du
== nullptr) {
222 #ifdef HAVE_DNS_OVER_HTTPS
223 dq
->httpScheme
= dq
->dq
->du
->getHTTPScheme();
224 #endif /* HAVE_DNS_OVER_HTTPS */
226 if (dq
->httpScheme
) {
227 return dq
->httpScheme
->c_str();
232 static void fill_edns_option(const EDNSOptionViewValue
& value
, dnsdist_ednsoption_t
& option
)
234 option
.len
= value
.size
;
235 option
.data
= nullptr;
237 if (value
.size
> 0) {
238 option
.data
= value
.content
;
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
)
245 if (dq
->dq
->ednsOptions
== nullptr) {
246 parseEDNSOptions(*(dq
->dq
));
249 size_t totalCount
= 0;
250 for (const auto& option
: *dq
->dq
->ednsOptions
) {
251 totalCount
+= option
.second
.values
.size();
254 dq
->ednsOptionsVect
.clear();
255 dq
->ednsOptionsVect
.resize(totalCount
);
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
;
265 if (totalCount
> 0) {
266 *out
= dq
->ednsOptionsVect
.data();
272 size_t dnsdist_ffi_dnsquestion_get_http_headers(dnsdist_ffi_dnsquestion_t
* dq
, const dnsdist_http_header_t
** out
)
274 if (dq
->dq
->du
== nullptr) {
278 #ifdef HAVE_DNS_OVER_HTTPS
279 dq
->httpHeaders
= dq
->dq
->du
->getHTTPHeaders();
280 dq
->httpHeadersVect
.clear();
281 dq
->httpHeadersVect
.resize(dq
->httpHeaders
.size());
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();
289 if (!dq
->httpHeadersVect
.empty()) {
290 *out
= dq
->httpHeadersVect
.data();
293 return dq
->httpHeadersVect
.size();
299 size_t dnsdist_ffi_dnsquestion_get_tag_array(dnsdist_ffi_dnsquestion_t
* dq
, const dnsdist_tag_t
** out
)
301 if (dq
->dq
->qTag
== nullptr || dq
->dq
->qTag
->size() == 0) {
305 dq
->tagsVect
.clear();
306 dq
->tagsVect
.resize(dq
->dq
->qTag
->size());
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();
317 if (!dq
->tagsVect
.empty()) {
318 *out
= dq
->tagsVect
.data();
321 return dq
->tagsVect
.size();
324 void dnsdist_ffi_dnsquestion_set_result(dnsdist_ffi_dnsquestion_t
* dq
, const char* str
, size_t strSize
)
326 dq
->result
= std::string(str
, strSize
);
329 void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t
* dq
, uint16_t statusCode
, const char* body
, const char* contentType
)
331 if (dq
->dq
->du
== nullptr) {
335 #ifdef HAVE_DNS_OVER_HTTPS
336 dq
->dq
->du
->setHTTPResponse(statusCode
, body
, contentType
);
337 dq
->dq
->dh
->qr
= true;
341 void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t
* dq
, int rcode
)
343 dq
->dq
->dh
->rcode
= rcode
;
344 dq
->dq
->dh
->qr
= true;
347 void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t
* dq
, uint16_t len
)
352 void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t
* dq
, bool skipCache
)
354 dq
->dq
->skipCache
= skipCache
;
357 void dnsdist_ffi_dnsquestion_set_use_ecs(dnsdist_ffi_dnsquestion_t
* dq
, bool useECS
)
359 dq
->dq
->useECS
= useECS
;
362 void dnsdist_ffi_dnsquestion_set_ecs_override(dnsdist_ffi_dnsquestion_t
* dq
, bool ecsOverride
)
364 dq
->dq
->ecsOverride
= ecsOverride
;
367 void dnsdist_ffi_dnsquestion_set_ecs_prefix_length(dnsdist_ffi_dnsquestion_t
* dq
, uint16_t ecsPrefixLength
)
369 dq
->dq
->ecsPrefixLength
= ecsPrefixLength
;
372 void dnsdist_ffi_dnsquestion_set_temp_failure_ttl(dnsdist_ffi_dnsquestion_t
* dq
, uint32_t tempFailureTTL
)
374 dq
->dq
->tempFailureTTL
= tempFailureTTL
;
377 void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t
* dq
)
379 dq
->dq
->tempFailureTTL
= boost::none
;
382 void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t
* dq
, const char* label
, const char* value
)
385 dq
->dq
->qTag
= std::make_shared
<QTag
>();
388 dq
->dq
->qTag
->insert({label
, value
});
391 size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t
* dq
, const char** out
)
393 dq
->trailingData
= dq
->dq
->getTrailingData();
394 if (!dq
->trailingData
.empty()) {
395 *out
= dq
->trailingData
.data();
398 return dq
->trailingData
.size();
401 bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t
* dq
, const char* data
, size_t dataLen
)
403 return dq
->dq
->setTrailingData(std::string(data
, dataLen
));
406 void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t
* dq
, const char* reason
, size_t reasonLen
)
408 if (g_snmpAgent
&& g_snmpTrapsEnabled
) {
409 g_snmpAgent
->sendDNSTrap(*dq
->dq
, std::string(reason
, reasonLen
));
413 const std::string
& getLuaFFIWrappers()
415 static const std::string interface
=
416 #include "dnsdist-lua-ffi-interface.inc"
418 static const std::string code
= R
"FFICodeContent(
419 local ffi = require("ffi
")
423 )FFICodeContent" + interface
+ R
"FFICodeContent(