]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-actions.cc
dnsdist: Add spoofRawAction() to craft answers from raw bytes
[thirdparty/pdns.git] / pdns / dnsdist-lua-actions.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 #include "config.h"
23 #include "threadname.hh"
24 #include "dnsdist.hh"
25 #include "dnsdist-ecs.hh"
26 #include "dnsdist-lua.hh"
27 #include "dnsdist-protobuf.hh"
28 #include "dnsdist-kvs.hh"
29
30 #include "dolog.hh"
31 #include "dnstap.hh"
32 #include "ednsoptions.hh"
33 #include "fstrm_logger.hh"
34 #include "remote_logger.hh"
35
36 #include <boost/optional/optional_io.hpp>
37
38 #ifdef HAVE_LIBCRYPTO
39 #include "ipcipher.hh"
40 #endif /* HAVE_LIBCRYPTO */
41
42 class DropAction : public DNSAction
43 {
44 public:
45 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
46 {
47 return Action::Drop;
48 }
49 std::string toString() const override
50 {
51 return "drop";
52 }
53 };
54
55 class AllowAction : public DNSAction
56 {
57 public:
58 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
59 {
60 return Action::Allow;
61 }
62 std::string toString() const override
63 {
64 return "allow";
65 }
66 };
67
68 class NoneAction : public DNSAction
69 {
70 public:
71 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
72 {
73 return Action::None;
74 }
75 std::string toString() const override
76 {
77 return "no op";
78 }
79 };
80
81 class QPSAction : public DNSAction
82 {
83 public:
84 QPSAction(int limit) : d_qps(limit, limit)
85 {}
86 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
87 {
88 if(d_qps.check())
89 return Action::None;
90 else
91 return Action::Drop;
92 }
93 std::string toString() const override
94 {
95 return "qps limit to "+std::to_string(d_qps.getRate());
96 }
97 private:
98 QPSLimiter d_qps;
99 };
100
101 class DelayAction : public DNSAction
102 {
103 public:
104 DelayAction(int msec) : d_msec(msec)
105 {}
106 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
107 {
108 *ruleresult=std::to_string(d_msec);
109 return Action::Delay;
110 }
111 std::string toString() const override
112 {
113 return "delay by "+std::to_string(d_msec)+ " msec";
114 }
115 private:
116 int d_msec;
117 };
118
119
120 class TeeAction : public DNSAction
121 {
122 public:
123 TeeAction(const ComboAddress& ca, bool addECS=false);
124 ~TeeAction() override;
125 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override;
126 std::string toString() const override;
127 std::map<std::string, double> getStats() const override;
128
129 private:
130 ComboAddress d_remote;
131 std::thread d_worker;
132 void worker();
133
134 int d_fd;
135 mutable std::atomic<unsigned long> d_senderrors{0};
136 unsigned long d_recverrors{0};
137 mutable std::atomic<unsigned long> d_queries{0};
138 unsigned long d_responses{0};
139 unsigned long d_nxdomains{0};
140 unsigned long d_servfails{0};
141 unsigned long d_refuseds{0};
142 unsigned long d_formerrs{0};
143 unsigned long d_notimps{0};
144 unsigned long d_noerrors{0};
145 mutable unsigned long d_tcpdrops{0};
146 unsigned long d_otherrcode{0};
147 std::atomic<bool> d_pleaseQuit{false};
148 bool d_addECS{false};
149 };
150
151 TeeAction::TeeAction(const ComboAddress& ca, bool addECS) : d_remote(ca), d_addECS(addECS)
152 {
153 d_fd=SSocket(d_remote.sin4.sin_family, SOCK_DGRAM, 0);
154 SConnect(d_fd, d_remote);
155 setNonBlocking(d_fd);
156 d_worker=std::thread(std::bind(&TeeAction::worker, this));
157 }
158
159 TeeAction::~TeeAction()
160 {
161 d_pleaseQuit=true;
162 close(d_fd);
163 d_worker.join();
164 }
165
166 DNSAction::Action TeeAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
167 {
168 if(dq->tcp) {
169 d_tcpdrops++;
170 }
171 else {
172 ssize_t res;
173 d_queries++;
174
175 if(d_addECS) {
176 std::string query;
177 uint16_t len = dq->len;
178 bool ednsAdded = false;
179 bool ecsAdded = false;
180 query.reserve(dq->size);
181 query.assign((char*) dq->dh, len);
182
183 std::string newECSOption;
184 generateECSOption(dq->ecsSet ? dq->ecs.getNetwork() : *dq->remote, newECSOption, dq->ecsSet ? dq->ecs.getBits() : dq->ecsPrefixLength);
185
186 if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, &ednsAdded, &ecsAdded, dq->ecsOverride, newECSOption, g_preserveTrailingData)) {
187 return DNSAction::Action::None;
188 }
189
190 res = send(d_fd, query.c_str(), len, 0);
191 }
192 else {
193 res = send(d_fd, (char*)dq->dh, dq->len, 0);
194 }
195
196 if (res <= 0)
197 d_senderrors++;
198 }
199 return DNSAction::Action::None;
200 }
201
202 std::string TeeAction::toString() const
203 {
204 return "tee to "+d_remote.toStringWithPort();
205 }
206
207 std::map<std::string,double> TeeAction::getStats() const
208 {
209 return {{"queries", d_queries},
210 {"responses", d_responses},
211 {"recv-errors", d_recverrors},
212 {"send-errors", d_senderrors},
213 {"noerrors", d_noerrors},
214 {"nxdomains", d_nxdomains},
215 {"refuseds", d_refuseds},
216 {"servfails", d_servfails},
217 {"other-rcode", d_otherrcode},
218 {"tcp-drops", d_tcpdrops}
219 };
220 }
221
222 void TeeAction::worker()
223 {
224 setThreadName("dnsdist/TeeWork");
225 char packet[1500];
226 int res=0;
227 struct dnsheader* dh=(struct dnsheader*)packet;
228 for(;;) {
229 res=waitForData(d_fd, 0, 250000);
230 if(d_pleaseQuit)
231 break;
232 if(res < 0) {
233 usleep(250000);
234 continue;
235 }
236 if(res==0)
237 continue;
238 res=recv(d_fd, packet, sizeof(packet), 0);
239 if(res <= (int)sizeof(struct dnsheader))
240 d_recverrors++;
241 else if(res > 0)
242 d_responses++;
243
244 if(dh->rcode == RCode::NoError)
245 d_noerrors++;
246 else if(dh->rcode == RCode::ServFail)
247 d_servfails++;
248 else if(dh->rcode == RCode::NXDomain)
249 d_nxdomains++;
250 else if(dh->rcode == RCode::Refused)
251 d_refuseds++;
252 else if(dh->rcode == RCode::FormErr)
253 d_formerrs++;
254 else if(dh->rcode == RCode::NotImp)
255 d_notimps++;
256 }
257 }
258
259 class PoolAction : public DNSAction
260 {
261 public:
262 PoolAction(const std::string& pool) : d_pool(pool) {}
263 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
264 {
265 *ruleresult=d_pool;
266 return Action::Pool;
267 }
268 std::string toString() const override
269 {
270 return "to pool "+d_pool;
271 }
272
273 private:
274 std::string d_pool;
275 };
276
277
278 class QPSPoolAction : public DNSAction
279 {
280 public:
281 QPSPoolAction(unsigned int limit, const std::string& pool) : d_qps(limit, limit), d_pool(pool) {}
282 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
283 {
284 if(d_qps.check()) {
285 *ruleresult=d_pool;
286 return Action::Pool;
287 }
288 else
289 return Action::None;
290 }
291 std::string toString() const override
292 {
293 return "max " +std::to_string(d_qps.getRate())+" to pool "+d_pool;
294 }
295
296 private:
297 QPSLimiter d_qps;
298 std::string d_pool;
299 };
300
301 class RCodeAction : public DNSAction
302 {
303 public:
304 RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
305 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
306 {
307 dq->dh->rcode = d_rcode;
308 dq->dh->qr = true; // for good measure
309 setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
310 return Action::HeaderModify;
311 }
312 std::string toString() const override
313 {
314 return "set rcode "+std::to_string(d_rcode);
315 }
316
317 ResponseConfig d_responseConfig;
318 private:
319 uint8_t d_rcode;
320 };
321
322 class ERCodeAction : public DNSAction
323 {
324 public:
325 ERCodeAction(uint8_t rcode) : d_rcode(rcode) {}
326 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
327 {
328 dq->dh->rcode = (d_rcode & 0xF);
329 dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
330 dq->dh->qr = true; // for good measure
331 setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
332 return Action::HeaderModify;
333 }
334 std::string toString() const override
335 {
336 return "set ercode "+ERCode::to_s(d_rcode);
337 }
338
339 ResponseConfig d_responseConfig;
340 private:
341 uint8_t d_rcode;
342 };
343
344 class TCAction : public DNSAction
345 {
346 public:
347 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
348 {
349 return Action::Truncate;
350 }
351 std::string toString() const override
352 {
353 return "tc=1 answer";
354 }
355 };
356
357 DNSAction::Action LuaAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
358 {
359 std::lock_guard<std::mutex> lock(g_luamutex);
360 try {
361 auto ret = d_func(dq);
362 if (ruleresult) {
363 if (boost::optional<std::string> rule = std::get<1>(ret)) {
364 *ruleresult = *rule;
365 }
366 else {
367 // default to empty string
368 ruleresult->clear();
369 }
370 }
371 return (Action)std::get<0>(ret);
372 } catch (std::exception &e) {
373 warnlog("LuaAction failed inside lua, returning ServFail: %s", e.what());
374 } catch (...) {
375 warnlog("LuaAction failed inside lua, returning ServFail: [unknown exception]");
376 }
377 return DNSAction::Action::ServFail;
378 }
379
380 DNSResponseAction::Action LuaResponseAction::operator()(DNSResponse* dr, std::string* ruleresult) const
381 {
382 std::lock_guard<std::mutex> lock(g_luamutex);
383 try {
384 auto ret = d_func(dr);
385 if(ruleresult) {
386 if (boost::optional<std::string> rule = std::get<1>(ret)) {
387 *ruleresult = *rule;
388 }
389 else {
390 // default to empty string
391 ruleresult->clear();
392 }
393 }
394 return (Action)std::get<0>(ret);
395 } catch (std::exception &e) {
396 warnlog("LuaResponseAction failed inside lua, returning ServFail: %s", e.what());
397 } catch (...) {
398 warnlog("LuaResponseAction failed inside lua, returning ServFail: [unknown exception]");
399 }
400 return DNSResponseAction::Action::ServFail;
401 }
402
403 DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, std::string* ruleresult) const
404 {
405 uint16_t qtype = dq->qtype;
406 // do we even have a response?
407 if (d_cname.empty() &&
408 d_rawResponse.empty() &&
409 d_types.count(qtype) == 0) {
410 return Action::None;
411 }
412
413 vector<ComboAddress> addrs;
414 unsigned int totrdatalen = 0;
415 uint16_t numberOfRecords = 0;
416 if (!d_cname.empty()) {
417 qtype = QType::CNAME;
418 totrdatalen += d_cname.toDNSString().size();
419 numberOfRecords = 1;
420 } else if (!d_rawResponse.empty()) {
421 totrdatalen += d_rawResponse.size();
422 numberOfRecords = 1;
423 }
424 else {
425 for(const auto& addr : d_addrs) {
426 if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
427 (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
428 continue;
429 }
430 totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
431 addrs.push_back(addr);
432 ++numberOfRecords;
433 }
434 }
435
436 if(addrs.size() > 1)
437 random_shuffle(addrs.begin(), addrs.end());
438
439 unsigned int consumed=0;
440 DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
441
442 if (dq->size < (sizeof(dnsheader) + consumed + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) {
443 return Action::None;
444 }
445
446 bool dnssecOK = false;
447 bool hadEDNS = false;
448 if (g_addEDNSToSelfGeneratedResponses && queryHasEDNS(*dq)) {
449 hadEDNS = true;
450 dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
451 }
452
453 dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS
454 char* dest = ((char*)dq->dh) + dq->len;
455
456 dq->dh->qr = true; // for good measure
457 setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
458 dq->dh->ancount = 0;
459 dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
460
461 uint32_t ttl = htonl(d_responseConfig.ttl);
462 unsigned char recordstart[] = {0xc0, 0x0c, // compressed name
463 0, 0, // QTYPE
464 0, QClass::IN,
465 0, 0, 0, 0, // TTL
466 0, 0 }; // rdata length
467 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
468 memcpy(&recordstart[6], &ttl, sizeof(ttl));
469
470 if (qtype == QType::CNAME) {
471 const std::string wireData = d_cname.toDNSString(); // Note! This doesn't do compression!
472 uint16_t rdataLen = htons(wireData.length());
473 qtype = htons(qtype);
474 memcpy(&recordstart[2], &qtype, sizeof(qtype));
475 memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
476
477 memcpy(dest, recordstart, sizeof(recordstart));
478 dest += sizeof(recordstart);
479 memcpy(dest, wireData.c_str(), wireData.length());
480 dq->len += wireData.length() + sizeof(recordstart);
481 dq->dh->ancount++;
482 }
483 else if (!d_rawResponse.empty()) {
484 uint16_t rdataLen = htons(d_rawResponse.size());
485 qtype = htons(qtype);
486 memcpy(&recordstart[2], &qtype, sizeof(qtype));
487 memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
488
489 memcpy(dest, recordstart, sizeof(recordstart));
490 dest += sizeof(recordstart);
491 memcpy(dest, d_rawResponse.c_str(), d_rawResponse.size());
492 dq->len += d_rawResponse.size() + sizeof(recordstart);
493 dq->dh->ancount++;
494 }
495 else {
496 for(const auto& addr : addrs) {
497 uint16_t rdataLen = htons(addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
498 qtype = htons(addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA);
499 memcpy(&recordstart[2], &qtype, sizeof(qtype));
500 memcpy(&recordstart[10], &rdataLen, sizeof(rdataLen));
501
502 memcpy(dest, recordstart, sizeof(recordstart));
503 dest += sizeof(recordstart);
504
505 memcpy(dest,
506 addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
507 addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
508 dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
509 dq->len += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr)) + sizeof(recordstart);
510 dq->dh->ancount++;
511 }
512 }
513
514 dq->dh->ancount = htons(dq->dh->ancount);
515
516 if (hadEDNS) {
517 addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
518 }
519
520 return Action::HeaderModify;
521 }
522
523 class MacAddrAction : public DNSAction
524 {
525 public:
526 MacAddrAction(uint16_t code) : d_code(code)
527 {}
528 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
529 {
530 if(dq->dh->arcount)
531 return Action::None;
532
533 std::string mac = getMACAddress(*dq->remote);
534 if(mac.empty())
535 return Action::None;
536
537 std::string optRData;
538 generateEDNSOption(d_code, mac, optRData);
539
540 std::string res;
541 generateOptRR(optRData, res, g_EdnsUDPPayloadSize, 0, false);
542
543 if ((dq->size - dq->len) < res.length())
544 return Action::None;
545
546 dq->dh->arcount = htons(1);
547 char* dest = ((char*)dq->dh) + dq->len;
548 memcpy(dest, res.c_str(), res.length());
549 dq->len += res.length();
550
551 return Action::None;
552 }
553 std::string toString() const override
554 {
555 return "add EDNS MAC (code="+std::to_string(d_code)+")";
556 }
557 private:
558 uint16_t d_code{3};
559 };
560
561 class NoRecurseAction : public DNSAction
562 {
563 public:
564 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
565 {
566 dq->dh->rd = false;
567 return Action::None;
568 }
569 std::string toString() const override
570 {
571 return "set rd=0";
572 }
573 };
574
575 class LogAction : public DNSAction, public boost::noncopyable
576 {
577 public:
578 LogAction(): d_fp(nullptr, fclose)
579 {
580 }
581
582 LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_binary(binary), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp)
583 {
584 if(str.empty())
585 return;
586 if(append)
587 d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "a+"), fclose);
588 else
589 d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "w"), fclose);
590 if(!d_fp)
591 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror());
592 if(!buffered)
593 setbuf(d_fp.get(), 0);
594 }
595
596 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
597 {
598 if (!d_fp) {
599 if (!d_verboseOnly || g_verbose) {
600 if (d_includeTimestamp) {
601 infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
602 }
603 else {
604 infolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
605 }
606 }
607 }
608 else {
609 if (d_binary) {
610 std::string out = dq->qname->toDNSString();
611 if (d_includeTimestamp) {
612 uint64_t tv_sec = static_cast<uint64_t>(dq->queryTime->tv_sec);
613 uint32_t tv_nsec = static_cast<uint32_t>(dq->queryTime->tv_nsec);
614 fwrite(&tv_sec, sizeof(tv_sec), 1, d_fp.get());
615 fwrite(&tv_nsec, sizeof(tv_nsec), 1, d_fp.get());
616 }
617 uint16_t id = dq->dh->id;
618 fwrite(&id, sizeof(id), 1, d_fp.get());
619 fwrite(out.c_str(), 1, out.size(), d_fp.get());
620 fwrite(&dq->qtype, sizeof(dq->qtype), 1, d_fp.get());
621 fwrite(&dq->remote->sin4.sin_family, sizeof(dq->remote->sin4.sin_family), 1, d_fp.get());
622 if (dq->remote->sin4.sin_family == AF_INET) {
623 fwrite(&dq->remote->sin4.sin_addr.s_addr, sizeof(dq->remote->sin4.sin_addr.s_addr), 1, d_fp.get());
624 }
625 else if (dq->remote->sin4.sin_family == AF_INET6) {
626 fwrite(&dq->remote->sin6.sin6_addr.s6_addr, sizeof(dq->remote->sin6.sin6_addr.s6_addr), 1, d_fp.get());
627 }
628 fwrite(&dq->remote->sin4.sin_port, sizeof(dq->remote->sin4.sin_port), 1, d_fp.get());
629 }
630 else {
631 if (d_includeTimestamp) {
632 fprintf(d_fp.get(), "[%llu.%lu] Packet from %s for %s %s with id %d\n", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->dh->id);
633 }
634 else {
635 fprintf(d_fp.get(), "Packet from %s for %s %s with id %d\n", dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->dh->id);
636 }
637 }
638 }
639 return Action::None;
640 }
641
642 std::string toString() const override
643 {
644 if (!d_fname.empty()) {
645 return "log to " + d_fname;
646 }
647 return "log";
648 }
649 private:
650 std::string d_fname;
651 std::unique_ptr<FILE, int(*)(FILE*)> d_fp{nullptr, fclose};
652 bool d_binary{true};
653 bool d_verboseOnly{true};
654 bool d_includeTimestamp{false};
655 };
656
657 class LogResponseAction : public DNSResponseAction, public boost::noncopyable
658 {
659 public:
660 LogResponseAction(): d_fp(nullptr, fclose)
661 {
662 }
663
664 LogResponseAction(const std::string& str, bool append=false, bool buffered=true, bool verboseOnly=true, bool includeTimestamp=false): d_fname(str), d_verboseOnly(verboseOnly), d_includeTimestamp(includeTimestamp)
665 {
666 if(str.empty())
667 return;
668 if(append)
669 d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "a+"), fclose);
670 else
671 d_fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(str.c_str(), "w"), fclose);
672 if(!d_fp)
673 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+stringerror());
674 if(!buffered)
675 setbuf(d_fp.get(), 0);
676 }
677
678 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
679 {
680 if (!d_fp) {
681 if (!d_verboseOnly || g_verbose) {
682 if (d_includeTimestamp) {
683 infolog("[%u.%u] Answer to %s for %s %s (%s) with id %d", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id);
684 }
685 else {
686 infolog("Answer to %s for %s %s (%s) with id %d", dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id);
687 }
688 }
689 }
690 else {
691 if (d_includeTimestamp) {
692 fprintf(d_fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %d\n", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id);
693 }
694 else {
695 fprintf(d_fp.get(), "Answer to %s for %s %s (%s) with id %d\n", dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id);
696 }
697 }
698 return Action::None;
699 }
700
701 std::string toString() const override
702 {
703 if (!d_fname.empty()) {
704 return "log to " + d_fname;
705 }
706 return "log";
707 }
708 private:
709 std::string d_fname;
710 std::unique_ptr<FILE, int(*)(FILE*)> d_fp{nullptr, fclose};
711 bool d_verboseOnly{true};
712 bool d_includeTimestamp{false};
713 };
714
715
716 class DisableValidationAction : public DNSAction
717 {
718 public:
719 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
720 {
721 dq->dh->cd = true;
722 return Action::None;
723 }
724 std::string toString() const override
725 {
726 return "set cd=1";
727 }
728 };
729
730 class SkipCacheAction : public DNSAction
731 {
732 public:
733 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
734 {
735 dq->skipCache = true;
736 return Action::None;
737 }
738 std::string toString() const override
739 {
740 return "skip cache";
741 }
742 };
743
744 class TempFailureCacheTTLAction : public DNSAction
745 {
746 public:
747 TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
748 {}
749 TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
750 {
751 dq->tempFailureTTL = d_ttl;
752 return Action::None;
753 }
754 std::string toString() const override
755 {
756 return "set tempfailure cache ttl to "+std::to_string(d_ttl);
757 }
758 private:
759 uint32_t d_ttl;
760 };
761
762 class ECSPrefixLengthAction : public DNSAction
763 {
764 public:
765 ECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
766 {
767 }
768 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
769 {
770 dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
771 return Action::None;
772 }
773 std::string toString() const override
774 {
775 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
776 }
777 private:
778 uint16_t d_v4PrefixLength;
779 uint16_t d_v6PrefixLength;
780 };
781
782 class ECSOverrideAction : public DNSAction
783 {
784 public:
785 ECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
786 {
787 }
788 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
789 {
790 dq->ecsOverride = d_ecsOverride;
791 return Action::None;
792 }
793 std::string toString() const override
794 {
795 return "set ECS override to " + std::to_string(d_ecsOverride);
796 }
797 private:
798 bool d_ecsOverride;
799 };
800
801
802 class DisableECSAction : public DNSAction
803 {
804 public:
805 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
806 {
807 dq->useECS = false;
808 return Action::None;
809 }
810 std::string toString() const override
811 {
812 return "disable ECS";
813 }
814 };
815
816 class SetECSAction : public DNSAction
817 {
818 public:
819 SetECSAction(const Netmask& v4): d_v4(v4), d_hasV6(false)
820 {
821 }
822
823 SetECSAction(const Netmask& v4, const Netmask& v6): d_v4(v4), d_v6(v6), d_hasV6(true)
824 {
825 }
826
827 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
828 {
829 dq->ecsSet = true;
830
831 if (d_hasV6) {
832 dq->ecs = dq->remote->isIPv4() ? d_v4 : d_v6;
833 }
834 else {
835 dq->ecs = d_v4;
836 }
837
838 return Action::None;
839 }
840
841 std::string toString() const override
842 {
843 std::string result = "set ECS to " + d_v4.toString();
844 if (d_hasV6) {
845 result += " / " + d_v6.toString();
846 }
847 return result;
848 }
849
850 private:
851 Netmask d_v4;
852 Netmask d_v6;
853 bool d_hasV6;
854 };
855
856
857 class DnstapLogAction : public DNSAction, public boost::noncopyable
858 {
859 public:
860 DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
861 {
862 }
863 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
864 {
865 #ifdef HAVE_PROTOBUF
866 DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
867 {
868 if (d_alterFunc) {
869 std::lock_guard<std::mutex> lock(g_luamutex);
870 (*d_alterFunc)(dq, &message);
871 }
872 }
873 std::string data;
874 message.serialize(data);
875 d_logger->queueData(data);
876 #endif /* HAVE_PROTOBUF */
877 return Action::None;
878 }
879 std::string toString() const override
880 {
881 return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
882 }
883 private:
884 std::string d_identity;
885 std::shared_ptr<RemoteLoggerInterface> d_logger;
886 boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > d_alterFunc;
887 };
888
889 class RemoteLogAction : public DNSAction, public boost::noncopyable
890 {
891 public:
892 RemoteLogAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey)
893 {
894 }
895 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
896 {
897 #ifdef HAVE_PROTOBUF
898 if (!dq->uniqueId) {
899 dq->uniqueId = getUniqueID();
900 }
901
902 DNSDistProtoBufMessage message(*dq);
903 if (!d_serverID.empty()) {
904 message.setServerIdentity(d_serverID);
905 }
906
907 #if HAVE_LIBCRYPTO
908 if (!d_ipEncryptKey.empty())
909 {
910 message.setRequestor(encryptCA(*dq->remote, d_ipEncryptKey));
911 }
912 #endif /* HAVE_LIBCRYPTO */
913
914 if (d_alterFunc) {
915 std::lock_guard<std::mutex> lock(g_luamutex);
916 (*d_alterFunc)(dq, &message);
917 }
918
919 std::string data;
920 message.serialize(data);
921 d_logger->queueData(data);
922 #endif /* HAVE_PROTOBUF */
923 return Action::None;
924 }
925 std::string toString() const override
926 {
927 return "remote log to " + (d_logger ? d_logger->toString() : "");
928 }
929 private:
930 std::shared_ptr<RemoteLoggerInterface> d_logger;
931 boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > d_alterFunc;
932 std::string d_serverID;
933 std::string d_ipEncryptKey;
934 };
935
936 class SNMPTrapAction : public DNSAction
937 {
938 public:
939 SNMPTrapAction(const std::string& reason): d_reason(reason)
940 {
941 }
942 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
943 {
944 if (g_snmpAgent && g_snmpTrapsEnabled) {
945 g_snmpAgent->sendDNSTrap(*dq, d_reason);
946 }
947
948 return Action::None;
949 }
950 std::string toString() const override
951 {
952 return "send SNMP trap";
953 }
954 private:
955 std::string d_reason;
956 };
957
958 class TagAction : public DNSAction
959 {
960 public:
961 TagAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
962 {
963 }
964 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
965 {
966 if (!dq->qTag) {
967 dq->qTag = std::make_shared<QTag>();
968 }
969
970 dq->qTag->insert({d_tag, d_value});
971
972 return Action::None;
973 }
974 std::string toString() const override
975 {
976 return "set tag '" + d_tag + "' to value '" + d_value + "'";
977 }
978 private:
979 std::string d_tag;
980 std::string d_value;
981 };
982
983 class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
984 {
985 public:
986 DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
987 {
988 }
989 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
990 {
991 #ifdef HAVE_PROTOBUF
992 struct timespec now;
993 gettime(&now, true);
994 DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
995 {
996 if (d_alterFunc) {
997 std::lock_guard<std::mutex> lock(g_luamutex);
998 (*d_alterFunc)(dr, &message);
999 }
1000 }
1001 std::string data;
1002 message.serialize(data);
1003 d_logger->queueData(data);
1004 #endif /* HAVE_PROTOBUF */
1005 return Action::None;
1006 }
1007 std::string toString() const override
1008 {
1009 return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
1010 }
1011 private:
1012 std::string d_identity;
1013 std::shared_ptr<RemoteLoggerInterface> d_logger;
1014 boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > d_alterFunc;
1015 };
1016
1017 class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
1018 {
1019 public:
1020 RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface>& logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, const std::string& serverID, const std::string& ipEncryptKey, bool includeCNAME): d_logger(logger), d_alterFunc(alterFunc), d_serverID(serverID), d_ipEncryptKey(ipEncryptKey), d_includeCNAME(includeCNAME)
1021 {
1022 }
1023 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1024 {
1025 #ifdef HAVE_PROTOBUF
1026 if (!dr->uniqueId) {
1027 dr->uniqueId = getUniqueID();
1028 }
1029
1030 DNSDistProtoBufMessage message(*dr, d_includeCNAME);
1031 if (!d_serverID.empty()) {
1032 message.setServerIdentity(d_serverID);
1033 }
1034
1035 #if HAVE_LIBCRYPTO
1036 if (!d_ipEncryptKey.empty())
1037 {
1038 message.setRequestor(encryptCA(*dr->remote, d_ipEncryptKey));
1039 }
1040 #endif /* HAVE_LIBCRYPTO */
1041
1042 if (d_alterFunc) {
1043 std::lock_guard<std::mutex> lock(g_luamutex);
1044 (*d_alterFunc)(dr, &message);
1045 }
1046
1047 std::string data;
1048 message.serialize(data);
1049 d_logger->queueData(data);
1050 #endif /* HAVE_PROTOBUF */
1051 return Action::None;
1052 }
1053 std::string toString() const override
1054 {
1055 return "remote log response to " + (d_logger ? d_logger->toString() : "");
1056 }
1057 private:
1058 std::shared_ptr<RemoteLoggerInterface> d_logger;
1059 boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > d_alterFunc;
1060 std::string d_serverID;
1061 std::string d_ipEncryptKey;
1062 bool d_includeCNAME;
1063 };
1064
1065 class DropResponseAction : public DNSResponseAction
1066 {
1067 public:
1068 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1069 {
1070 return Action::Drop;
1071 }
1072 std::string toString() const override
1073 {
1074 return "drop";
1075 }
1076 };
1077
1078 class AllowResponseAction : public DNSResponseAction
1079 {
1080 public:
1081 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1082 {
1083 return Action::Allow;
1084 }
1085 std::string toString() const override
1086 {
1087 return "allow";
1088 }
1089 };
1090
1091 class DelayResponseAction : public DNSResponseAction
1092 {
1093 public:
1094 DelayResponseAction(int msec) : d_msec(msec)
1095 {}
1096 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1097 {
1098 *ruleresult=std::to_string(d_msec);
1099 return Action::Delay;
1100 }
1101 std::string toString() const override
1102 {
1103 return "delay by "+std::to_string(d_msec)+ " msec";
1104 }
1105 private:
1106 int d_msec;
1107 };
1108
1109 class SNMPTrapResponseAction : public DNSResponseAction
1110 {
1111 public:
1112 SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
1113 {
1114 }
1115 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1116 {
1117 if (g_snmpAgent && g_snmpTrapsEnabled) {
1118 g_snmpAgent->sendDNSTrap(*dr, d_reason);
1119 }
1120
1121 return Action::None;
1122 }
1123 std::string toString() const override
1124 {
1125 return "send SNMP trap";
1126 }
1127 private:
1128 std::string d_reason;
1129 };
1130
1131 class TagResponseAction : public DNSResponseAction
1132 {
1133 public:
1134 TagResponseAction(const std::string& tag, const std::string& value): d_tag(tag), d_value(value)
1135 {
1136 }
1137 DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
1138 {
1139 if (!dr->qTag) {
1140 dr->qTag = std::make_shared<QTag>();
1141 }
1142
1143 dr->qTag->insert({d_tag, d_value});
1144
1145 return Action::None;
1146 }
1147 std::string toString() const override
1148 {
1149 return "set tag '" + d_tag + "' to value '" + d_value + "'";
1150 }
1151 private:
1152 std::string d_tag;
1153 std::string d_value;
1154 };
1155
1156 class ContinueAction : public DNSAction
1157 {
1158 public:
1159 ContinueAction(std::shared_ptr<DNSAction>& action): d_action(action)
1160 {
1161 }
1162
1163 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1164 {
1165 if (d_action) {
1166 /* call the action */
1167 auto action = (*d_action)(dq, ruleresult);
1168 bool drop = false;
1169 /* apply the changes if needed (pool selection, flags, etc */
1170 processRulesResult(action, *dq, *ruleresult, drop);
1171 }
1172
1173 /* but ignore the resulting action no matter what */
1174 return Action::None;
1175 }
1176
1177 std::string toString() const override
1178 {
1179 if (d_action) {
1180 return "continue after: " + (d_action ? d_action->toString() : "");
1181 }
1182 else {
1183 return "no op";
1184 }
1185 }
1186
1187 private:
1188 std::shared_ptr<DNSAction> d_action;
1189 };
1190
1191 #ifdef HAVE_DNS_OVER_HTTPS
1192 class HTTPStatusAction: public DNSAction
1193 {
1194 public:
1195 HTTPStatusAction(int code, const std::string& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
1196 {
1197 }
1198
1199 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1200 {
1201 if (!dq->du) {
1202 return Action::None;
1203 }
1204
1205 dq->du->setHTTPResponse(d_code, d_body, d_contentType);
1206 dq->dh->qr = true; // for good measure
1207 setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
1208 return Action::HeaderModify;
1209 }
1210
1211 std::string toString() const override
1212 {
1213 return "return an HTTP status of " + std::to_string(d_code);
1214 }
1215
1216 ResponseConfig d_responseConfig;
1217 private:
1218 std::string d_body;
1219 std::string d_contentType;
1220 int d_code;
1221 };
1222 #endif /* HAVE_DNS_OVER_HTTPS */
1223
1224 class KeyValueStoreLookupAction : public DNSAction
1225 {
1226 public:
1227 KeyValueStoreLookupAction(std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag): d_kvs(kvs), d_key(lookupKey), d_tag(destinationTag)
1228 {
1229 }
1230
1231 DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
1232 {
1233 std::vector<std::string> keys = d_key->getKeys(*dq);
1234 std::string result;
1235 for (const auto& key : keys) {
1236 if (d_kvs->getValue(key, result) == true) {
1237 break;
1238 }
1239 }
1240
1241 if (!dq->qTag) {
1242 dq->qTag = std::make_shared<QTag>();
1243 }
1244
1245 dq->qTag->insert({d_tag, std::move(result)});
1246
1247 return Action::None;
1248 }
1249
1250 std::string toString() const override
1251 {
1252 return "lookup key-value store based on '" + d_key->toString() + "' and set the result in tag '" + d_tag + "'";
1253 }
1254
1255 private:
1256 std::shared_ptr<KeyValueStore> d_kvs;
1257 std::shared_ptr<KeyValueLookupKey> d_key;
1258 std::string d_tag;
1259 };
1260
1261 template<typename T, typename ActionT>
1262 static void addAction(GlobalStateHolder<vector<T> > *someRulActions, const luadnsrule_t& var, const std::shared_ptr<ActionT>& action, boost::optional<luaruleparams_t>& params) {
1263 setLuaSideEffect();
1264
1265 boost::uuids::uuid uuid;
1266 uint64_t creationOrder;
1267 parseRuleParams(params, uuid, creationOrder);
1268
1269 auto rule=makeRule(var);
1270 someRulActions->modify([&rule, &action, &uuid, creationOrder](vector<T>& rulactions){
1271 rulactions.push_back({std::move(rule), std::move(action), std::move(uuid), creationOrder});
1272 });
1273 }
1274
1275 typedef std::unordered_map<std::string, boost::variant<bool, uint32_t> > responseParams_t;
1276
1277 static void parseResponseConfig(boost::optional<responseParams_t> vars, ResponseConfig& config)
1278 {
1279 if (vars) {
1280 if (vars->count("ttl")) {
1281 config.ttl = boost::get<uint32_t>((*vars)["ttl"]);
1282 }
1283 if (vars->count("aa")) {
1284 config.setAA = boost::get<bool>((*vars)["aa"]);
1285 }
1286 if (vars->count("ad")) {
1287 config.setAD = boost::get<bool>((*vars)["ad"]);
1288 }
1289 if (vars->count("ra")) {
1290 config.setRA = boost::get<bool>((*vars)["ra"]);
1291 }
1292 }
1293 }
1294
1295 void setResponseHeadersFromConfig(dnsheader& dh, const ResponseConfig& config)
1296 {
1297 if (config.setAA) {
1298 dh.aa = *config.setAA;
1299 }
1300 if (config.setAD) {
1301 dh.ad = *config.setAD;
1302 }
1303 else {
1304 dh.ad = false;
1305 }
1306 if (config.setRA) {
1307 dh.ra = *config.setRA;
1308 }
1309 else {
1310 dh.ra = dh.rd; // for good measure
1311 }
1312 }
1313
1314 void setupLuaActions()
1315 {
1316 g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
1317 boost::uuids::uuid uuid;
1318 uint64_t creationOrder;
1319 parseRuleParams(params, uuid, creationOrder);
1320
1321 auto rule=makeRule(dnsrule);
1322 DNSDistRuleAction ra({std::move(rule), action, uuid, creationOrder});
1323 return std::make_shared<DNSDistRuleAction>(ra);
1324 });
1325
1326 g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1327 if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
1328 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
1329 }
1330
1331 addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
1332 });
1333
1334 g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
1335 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1336 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1337 }
1338
1339 addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1340 });
1341
1342 g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1343 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1344 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1345 }
1346
1347 addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1348 });
1349
1350 g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
1351 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
1352 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
1353 }
1354
1355 addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
1356 });
1357
1358 g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
1359 setLuaNoSideEffect();
1360 auto stats = ta.getStats();
1361 for(const auto& s : stats) {
1362 g_outputBuffer+=s.first+"\t";
1363 if((uint64_t)s.second == s.second)
1364 g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
1365 else
1366 g_outputBuffer += std::to_string(s.second)+"\n";
1367 }
1368 });
1369
1370 g_lua.writeFunction("getAction", [](unsigned int num) {
1371 setLuaNoSideEffect();
1372 boost::optional<std::shared_ptr<DNSAction>> ret;
1373 auto rulactions = g_rulactions.getCopy();
1374 if(num < rulactions.size())
1375 ret=rulactions[num].d_action;
1376 return ret;
1377 });
1378
1379 g_lua.registerFunction("getStats", &DNSAction::getStats);
1380
1381 g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) {
1382 setLuaSideEffect();
1383 return std::shared_ptr<DNSAction>(new LuaAction(func));
1384 });
1385
1386 g_lua.writeFunction("NoRecurseAction", []() {
1387 return std::shared_ptr<DNSAction>(new NoRecurseAction);
1388 });
1389
1390 g_lua.writeFunction("MacAddrAction", [](int code) {
1391 return std::shared_ptr<DNSAction>(new MacAddrAction(code));
1392 });
1393
1394 g_lua.writeFunction("PoolAction", [](const std::string& a) {
1395 return std::shared_ptr<DNSAction>(new PoolAction(a));
1396 });
1397
1398 g_lua.writeFunction("QPSAction", [](int limit) {
1399 return std::shared_ptr<DNSAction>(new QPSAction(limit));
1400 });
1401
1402 g_lua.writeFunction("QPSPoolAction", [](int limit, const std::string& a) {
1403 return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
1404 });
1405
1406 g_lua.writeFunction("SpoofAction", [](boost::variant<std::string,vector<pair<int, std::string>>> inp, boost::optional<std::string> b, boost::optional<responseParams_t> vars ) {
1407 vector<ComboAddress> addrs;
1408 if(auto s = boost::get<std::string>(&inp))
1409 addrs.push_back(ComboAddress(*s));
1410 else {
1411 const auto& v = boost::get<vector<pair<int,std::string>>>(inp);
1412 for(const auto& a: v)
1413 addrs.push_back(ComboAddress(a.second));
1414 }
1415 if(b) {
1416 addrs.push_back(ComboAddress(*b));
1417 }
1418
1419 auto ret = std::shared_ptr<DNSAction>(new SpoofAction(addrs));
1420 auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
1421 parseResponseConfig(vars, sa->d_responseConfig);
1422 return ret;
1423 });
1424
1425 g_lua.writeFunction("SpoofCNAMEAction", [](const std::string& a, boost::optional<responseParams_t> vars) {
1426 auto ret = std::shared_ptr<DNSAction>(new SpoofAction(DNSName(a)));
1427 auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
1428 parseResponseConfig(vars, sa->d_responseConfig);
1429 return ret;
1430 });
1431
1432 g_lua.writeFunction("SpoofRawAction", [](const std::string& raw, boost::optional<responseParams_t> vars) {
1433 auto ret = std::shared_ptr<DNSAction>(new SpoofAction(raw));
1434 auto sa = std::dynamic_pointer_cast<SpoofAction>(ret);
1435 parseResponseConfig(vars, sa->d_responseConfig);
1436 return ret;
1437 });
1438
1439 g_lua.writeFunction("DropAction", []() {
1440 return std::shared_ptr<DNSAction>(new DropAction);
1441 });
1442
1443 g_lua.writeFunction("AllowAction", []() {
1444 return std::shared_ptr<DNSAction>(new AllowAction);
1445 });
1446
1447 g_lua.writeFunction("NoneAction", []() {
1448 return std::shared_ptr<DNSAction>(new NoneAction);
1449 });
1450
1451 g_lua.writeFunction("DelayAction", [](int msec) {
1452 return std::shared_ptr<DNSAction>(new DelayAction(msec));
1453 });
1454
1455 g_lua.writeFunction("TCAction", []() {
1456 return std::shared_ptr<DNSAction>(new TCAction);
1457 });
1458
1459 g_lua.writeFunction("DisableValidationAction", []() {
1460 return std::shared_ptr<DNSAction>(new DisableValidationAction);
1461 });
1462
1463 g_lua.writeFunction("LogAction", [](boost::optional<std::string> fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
1464 return std::shared_ptr<DNSAction>(new LogAction(fname ? *fname : "", binary ? *binary : true, append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
1465 });
1466
1467 g_lua.writeFunction("LogResponseAction", [](boost::optional<std::string> fname, boost::optional<bool> append, boost::optional<bool> buffered, boost::optional<bool> verboseOnly, boost::optional<bool> includeTimestamp) {
1468 return std::shared_ptr<DNSResponseAction>(new LogResponseAction(fname ? *fname : "", append ? *append : false, buffered ? *buffered : false, verboseOnly ? *verboseOnly : true, includeTimestamp ? *includeTimestamp : false));
1469 });
1470
1471 g_lua.writeFunction("RCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
1472 auto ret = std::shared_ptr<DNSAction>(new RCodeAction(rcode));
1473 auto rca = std::dynamic_pointer_cast<RCodeAction>(ret);
1474 parseResponseConfig(vars, rca->d_responseConfig);
1475 return ret;
1476 });
1477
1478 g_lua.writeFunction("ERCodeAction", [](uint8_t rcode, boost::optional<responseParams_t> vars) {
1479 auto ret = std::shared_ptr<DNSAction>(new ERCodeAction(rcode));
1480 auto erca = std::dynamic_pointer_cast<ERCodeAction>(ret);
1481 parseResponseConfig(vars, erca->d_responseConfig);
1482 return ret;
1483 });
1484
1485 g_lua.writeFunction("SkipCacheAction", []() {
1486 return std::shared_ptr<DNSAction>(new SkipCacheAction);
1487 });
1488
1489 g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
1490 return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
1491 });
1492
1493 g_lua.writeFunction("DropResponseAction", []() {
1494 return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
1495 });
1496
1497 g_lua.writeFunction("AllowResponseAction", []() {
1498 return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
1499 });
1500
1501 g_lua.writeFunction("DelayResponseAction", [](int msec) {
1502 return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
1503 });
1504
1505 g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
1506 setLuaSideEffect();
1507 return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
1508 });
1509
1510 g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<std::unordered_map<std::string, std::string>> vars) {
1511 if (logger) {
1512 // avoids potentially-evaluated-expression warning with clang.
1513 RemoteLoggerInterface& rl = *logger.get();
1514 if (typeid(rl) != typeid(RemoteLogger)) {
1515 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1516 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1517 }
1518 }
1519
1520 std::string serverID;
1521 std::string ipEncryptKey;
1522 if (vars) {
1523 if (vars->count("serverID")) {
1524 serverID = boost::get<std::string>((*vars)["serverID"]);
1525 }
1526 if (vars->count("ipEncryptKey")) {
1527 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
1528 }
1529 }
1530
1531 #ifdef HAVE_PROTOBUF
1532 return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc, serverID, ipEncryptKey));
1533 #else
1534 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1535 #endif
1536 });
1537
1538 g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME, boost::optional<std::unordered_map<std::string, std::string>> vars) {
1539 if (logger) {
1540 // avoids potentially-evaluated-expression warning with clang.
1541 RemoteLoggerInterface& rl = *logger.get();
1542 if (typeid(rl) != typeid(RemoteLogger)) {
1543 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1544 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1545 }
1546 }
1547
1548 std::string serverID;
1549 std::string ipEncryptKey;
1550 if (vars) {
1551 if (vars->count("serverID")) {
1552 serverID = boost::get<std::string>((*vars)["serverID"]);
1553 }
1554 if (vars->count("ipEncryptKey")) {
1555 ipEncryptKey = boost::get<std::string>((*vars)["ipEncryptKey"]);
1556 }
1557 }
1558
1559 #ifdef HAVE_PROTOBUF
1560 return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, serverID, ipEncryptKey, includeCNAME ? *includeCNAME : false));
1561 #else
1562 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1563 #endif
1564 });
1565
1566 g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSQuestion*, DnstapMessage*)> > alterFunc) {
1567 #ifdef HAVE_PROTOBUF
1568 return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
1569 #else
1570 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1571 #endif
1572 });
1573
1574 g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(DNSResponse*, DnstapMessage*)> > alterFunc) {
1575 #ifdef HAVE_PROTOBUF
1576 return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
1577 #else
1578 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1579 #endif
1580 });
1581
1582 g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
1583 return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
1584 });
1585
1586 g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
1587 return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
1588 });
1589
1590 g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
1591 return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride));
1592 });
1593
1594 g_lua.writeFunction("DisableECSAction", []() {
1595 return std::shared_ptr<DNSAction>(new DisableECSAction());
1596 });
1597
1598 g_lua.writeFunction("SetECSAction", [](const std::string v4, boost::optional<std::string> v6) {
1599 if (v6) {
1600 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4), Netmask(*v6)));
1601 }
1602 return std::shared_ptr<DNSAction>(new SetECSAction(Netmask(v4)));
1603 });
1604
1605 g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
1606 #ifdef HAVE_NET_SNMP
1607 return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
1608 #else
1609 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1610 #endif /* HAVE_NET_SNMP */
1611 });
1612
1613 g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
1614 #ifdef HAVE_NET_SNMP
1615 return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
1616 #else
1617 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1618 #endif /* HAVE_NET_SNMP */
1619 });
1620
1621 g_lua.writeFunction("TagAction", [](std::string tag, std::string value) {
1622 return std::shared_ptr<DNSAction>(new TagAction(tag, value));
1623 });
1624
1625 g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
1626 return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value));
1627 });
1628
1629 g_lua.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
1630 return std::shared_ptr<DNSAction>(new ContinueAction(action));
1631 });
1632
1633 #ifdef HAVE_DNS_OVER_HTTPS
1634 g_lua.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
1635 auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
1636 auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
1637 parseResponseConfig(vars, hsa->d_responseConfig);
1638 return ret;
1639 });
1640 #endif /* HAVE_DNS_OVER_HTTPS */
1641
1642 g_lua.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
1643 return std::shared_ptr<DNSAction>(new KeyValueStoreLookupAction(kvs, lookupKey, destinationTag));
1644 });
1645 }