]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-lua-actions.cc
8d25ae8742f45917a8eee1b10bbdae99a4f86ce1
[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 "dnsdist.hh"
23 #include "dnsdist-ecs.hh"
24 #include "dnsdist-lua.hh"
25 #include "dnsdist-protobuf.hh"
26
27 #include "dolog.hh"
28 #include "dnstap.hh"
29 #include "ednsoptions.hh"
30 #include "fstrm_logger.hh"
31 #include "remote_logger.hh"
32
33 class DropAction : public DNSAction
34 {
35 public:
36 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
37 {
38 return Action::Drop;
39 }
40 string toString() const override
41 {
42 return "drop";
43 }
44 };
45
46 class AllowAction : public DNSAction
47 {
48 public:
49 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
50 {
51 return Action::Allow;
52 }
53 string toString() const override
54 {
55 return "allow";
56 }
57 };
58
59
60 class QPSAction : public DNSAction
61 {
62 public:
63 QPSAction(int limit) : d_qps(limit, limit)
64 {}
65 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
66 {
67 if(d_qps.check())
68 return Action::None;
69 else
70 return Action::Drop;
71 }
72 string toString() const override
73 {
74 return "qps limit to "+std::to_string(d_qps.getRate());
75 }
76 private:
77 QPSLimiter d_qps;
78 };
79
80 class DelayAction : public DNSAction
81 {
82 public:
83 DelayAction(int msec) : d_msec(msec)
84 {}
85 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
86 {
87 *ruleresult=std::to_string(d_msec);
88 return Action::Delay;
89 }
90 string toString() const override
91 {
92 return "delay by "+std::to_string(d_msec)+ " msec";
93 }
94 private:
95 int d_msec;
96 };
97
98
99 class TeeAction : public DNSAction
100 {
101 public:
102 TeeAction(const ComboAddress& ca, bool addECS=false);
103 ~TeeAction() override;
104 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override;
105 string toString() const override;
106 std::unordered_map<string, double> getStats() const override;
107
108 private:
109 ComboAddress d_remote;
110 std::thread d_worker;
111 void worker();
112
113 int d_fd;
114 mutable std::atomic<unsigned long> d_senderrors{0};
115 unsigned long d_recverrors{0};
116 mutable std::atomic<unsigned long> d_queries{0};
117 unsigned long d_responses{0};
118 unsigned long d_nxdomains{0};
119 unsigned long d_servfails{0};
120 unsigned long d_refuseds{0};
121 unsigned long d_formerrs{0};
122 unsigned long d_notimps{0};
123 unsigned long d_noerrors{0};
124 mutable unsigned long d_tcpdrops{0};
125 unsigned long d_otherrcode{0};
126 std::atomic<bool> d_pleaseQuit{false};
127 bool d_addECS{false};
128 };
129
130 TeeAction::TeeAction(const ComboAddress& ca, bool addECS) : d_remote(ca), d_addECS(addECS)
131 {
132 d_fd=SSocket(d_remote.sin4.sin_family, SOCK_DGRAM, 0);
133 SConnect(d_fd, d_remote);
134 setNonBlocking(d_fd);
135 d_worker=std::thread(std::bind(&TeeAction::worker, this));
136 }
137
138 TeeAction::~TeeAction()
139 {
140 d_pleaseQuit=true;
141 close(d_fd);
142 d_worker.join();
143 }
144
145
146 DNSAction::Action TeeAction::operator()(DNSQuestion* dq, string* ruleresult) const
147 {
148 if(dq->tcp) {
149 d_tcpdrops++;
150 }
151 else {
152 ssize_t res;
153 d_queries++;
154
155 if(d_addECS) {
156 std::string query;
157 uint16_t len = dq->len;
158 bool ednsAdded = false;
159 bool ecsAdded = false;
160 query.reserve(dq->size);
161 query.assign((char*) dq->dh, len);
162
163 if (!handleEDNSClientSubnet((char*) query.c_str(), query.capacity(), dq->qname->wirelength(), &len, &ednsAdded, &ecsAdded, *dq->remote, dq->ecsOverride, dq->ecsPrefixLength)) {
164 return DNSAction::Action::None;
165 }
166
167 res = send(d_fd, query.c_str(), len, 0);
168 }
169 else {
170 res = send(d_fd, (char*)dq->dh, dq->len, 0);
171 }
172
173 if (res <= 0)
174 d_senderrors++;
175 }
176 return DNSAction::Action::None;
177 }
178
179 string TeeAction::toString() const
180 {
181 return "tee to "+d_remote.toStringWithPort();
182 }
183
184 std::unordered_map<string,double> TeeAction::getStats() const
185 {
186 return {{"queries", d_queries},
187 {"responses", d_responses},
188 {"recv-errors", d_recverrors},
189 {"send-errors", d_senderrors},
190 {"noerrors", d_noerrors},
191 {"nxdomains", d_nxdomains},
192 {"refuseds", d_refuseds},
193 {"servfails", d_servfails},
194 {"other-rcode", d_otherrcode},
195 {"tcp-drops", d_tcpdrops}
196 };
197 }
198
199 void TeeAction::worker()
200 {
201 char packet[1500];
202 int res=0;
203 struct dnsheader* dh=(struct dnsheader*)packet;
204 for(;;) {
205 res=waitForData(d_fd, 0, 250000);
206 if(d_pleaseQuit)
207 break;
208 if(res < 0) {
209 usleep(250000);
210 continue;
211 }
212 if(res==0)
213 continue;
214 res=recv(d_fd, packet, sizeof(packet), 0);
215 if(res <= (int)sizeof(struct dnsheader))
216 d_recverrors++;
217 else if(res > 0)
218 d_responses++;
219
220 if(dh->rcode == RCode::NoError)
221 d_noerrors++;
222 else if(dh->rcode == RCode::ServFail)
223 d_servfails++;
224 else if(dh->rcode == RCode::NXDomain)
225 d_nxdomains++;
226 else if(dh->rcode == RCode::Refused)
227 d_refuseds++;
228 else if(dh->rcode == RCode::FormErr)
229 d_formerrs++;
230 else if(dh->rcode == RCode::NotImp)
231 d_notimps++;
232 }
233 }
234
235 class PoolAction : public DNSAction
236 {
237 public:
238 PoolAction(const std::string& pool) : d_pool(pool) {}
239 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
240 {
241 *ruleresult=d_pool;
242 return Action::Pool;
243 }
244 string toString() const override
245 {
246 return "to pool "+d_pool;
247 }
248
249 private:
250 string d_pool;
251 };
252
253
254 class QPSPoolAction : public DNSAction
255 {
256 public:
257 QPSPoolAction(unsigned int limit, const std::string& pool) : d_qps(limit, limit), d_pool(pool) {}
258 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
259 {
260 if(d_qps.check()) {
261 *ruleresult=d_pool;
262 return Action::Pool;
263 }
264 else
265 return Action::None;
266 }
267 string toString() const override
268 {
269 return "max " +std::to_string(d_qps.getRate())+" to pool "+d_pool;
270 }
271
272 private:
273 QPSLimiter d_qps;
274 string d_pool;
275 };
276
277 class RCodeAction : public DNSAction
278 {
279 public:
280 RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
281 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
282 {
283 dq->dh->rcode = d_rcode;
284 dq->dh->qr = true; // for good measure
285 return Action::HeaderModify;
286 }
287 string toString() const override
288 {
289 return "set rcode "+std::to_string(d_rcode);
290 }
291
292 private:
293 uint8_t d_rcode;
294 };
295
296 class TCAction : public DNSAction
297 {
298 public:
299 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
300 {
301 return Action::Truncate;
302 }
303 string toString() const override
304 {
305 return "tc=1 answer";
306 }
307 };
308
309 DNSAction::Action SpoofAction::operator()(DNSQuestion* dq, string* ruleresult) const
310 {
311 uint16_t qtype = dq->qtype;
312 // do we even have a response?
313 if(d_cname.empty() && !std::count_if(d_addrs.begin(), d_addrs.end(), [qtype](const ComboAddress& a)
314 {
315 return (qtype == QType::ANY || ((a.sin4.sin_family == AF_INET && qtype == QType::A) ||
316 (a.sin4.sin_family == AF_INET6 && qtype == QType::AAAA)));
317 }))
318 return Action::None;
319
320 vector<ComboAddress> addrs;
321 unsigned int totrdatalen=0;
322 if (!d_cname.empty()) {
323 qtype = QType::CNAME;
324 totrdatalen += d_cname.toDNSString().size();
325 } else {
326 for(const auto& addr : d_addrs) {
327 if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
328 (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA))) {
329 continue;
330 }
331 totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
332 addrs.push_back(addr);
333 }
334 }
335
336 if(addrs.size() > 1)
337 random_shuffle(addrs.begin(), addrs.end());
338
339 unsigned int consumed=0;
340 DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
341
342 if (dq->size < (sizeof(dnsheader) + consumed + 4 + ((d_cname.empty() ? 0 : 1) + addrs.size())*12 /* recordstart */ + totrdatalen)) {
343 return Action::None;
344 }
345
346 dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS
347 char* dest = ((char*)dq->dh) + dq->len;
348
349 dq->dh->qr = true; // for good measure
350 dq->dh->ra = dq->dh->rd; // for good measure
351 dq->dh->ad = false;
352 dq->dh->ancount = 0;
353 dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
354
355 if(qtype == QType::CNAME) {
356 string wireData = d_cname.toDNSString(); // Note! This doesn't do compression!
357 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
358 0, (unsigned char) qtype,
359 0, QClass::IN, // IN
360 0, 0, 0, 60, // TTL
361 0, (unsigned char)wireData.length()};
362 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
363
364 memcpy(dest, recordstart, sizeof(recordstart));
365 dest += sizeof(recordstart);
366 memcpy(dest, wireData.c_str(), wireData.length());
367 dq->len += wireData.length() + sizeof(recordstart);
368 dq->dh->ancount++;
369 }
370 else {
371 for(const auto& addr : addrs) {
372 unsigned char rdatalen = addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
373 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
374 0, (unsigned char) (addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA),
375 0, QClass::IN, // IN
376 0, 0, 0, 60, // TTL
377 0, rdatalen};
378 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
379
380 memcpy(dest, recordstart, sizeof(recordstart));
381 dest += sizeof(recordstart);
382
383 memcpy(dest,
384 addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
385 rdatalen);
386 dest += rdatalen;
387 dq->len += rdatalen + sizeof(recordstart);
388 dq->dh->ancount++;
389 }
390 }
391
392 dq->dh->ancount = htons(dq->dh->ancount);
393
394 return Action::HeaderModify;
395 }
396
397 class MacAddrAction : public DNSAction
398 {
399 public:
400 MacAddrAction(uint16_t code) : d_code(code)
401 {}
402 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
403 {
404 if(dq->dh->arcount)
405 return Action::None;
406
407 string mac = getMACAddress(*dq->remote);
408 if(mac.empty())
409 return Action::None;
410
411 string optRData;
412 generateEDNSOption(d_code, mac, optRData);
413
414 string res;
415 generateOptRR(optRData, res);
416
417 if ((dq->size - dq->len) < res.length())
418 return Action::None;
419
420 dq->dh->arcount = htons(1);
421 char* dest = ((char*)dq->dh) + dq->len;
422 memcpy(dest, res.c_str(), res.length());
423 dq->len += res.length();
424
425 return Action::None;
426 }
427 string toString() const override
428 {
429 return "add EDNS MAC (code="+std::to_string(d_code)+")";
430 }
431 private:
432 uint16_t d_code{3};
433 };
434
435 class NoRecurseAction : public DNSAction
436 {
437 public:
438 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
439 {
440 dq->dh->rd = false;
441 return Action::None;
442 }
443 string toString() const override
444 {
445 return "set rd=0";
446 }
447 };
448
449 class LogAction : public DNSAction, public boost::noncopyable
450 {
451 public:
452 LogAction() : d_fp(0)
453 {
454 }
455 LogAction(const std::string& str, bool binary=true, bool append=false, bool buffered=true) : d_fname(str), d_binary(binary)
456 {
457 if(str.empty())
458 return;
459 if(append)
460 d_fp = fopen(str.c_str(), "a+");
461 else
462 d_fp = fopen(str.c_str(), "w");
463 if(!d_fp)
464 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+string(strerror(errno)));
465 if(!buffered)
466 setbuf(d_fp, 0);
467 }
468 ~LogAction() override
469 {
470 if(d_fp)
471 fclose(d_fp);
472 }
473 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
474 {
475 if(!d_fp) {
476 vinfolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
477 }
478 else {
479 if(d_binary) {
480 string out = dq->qname->toDNSString();
481 fwrite(out.c_str(), 1, out.size(), d_fp);
482 fwrite((void*)&dq->qtype, 1, 2, d_fp);
483 }
484 else {
485 fprintf(d_fp, "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);
486 }
487 }
488 return Action::None;
489 }
490 string toString() const override
491 {
492 if (!d_fname.empty()) {
493 return "log to " + d_fname;
494 }
495 return "log";
496 }
497 private:
498 string d_fname;
499 FILE* d_fp{0};
500 bool d_binary{true};
501 };
502
503
504 class DisableValidationAction : public DNSAction
505 {
506 public:
507 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
508 {
509 dq->dh->cd = true;
510 return Action::None;
511 }
512 string toString() const override
513 {
514 return "set cd=1";
515 }
516 };
517
518 class SkipCacheAction : public DNSAction
519 {
520 public:
521 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
522 {
523 dq->skipCache = true;
524 return Action::None;
525 }
526 string toString() const override
527 {
528 return "skip cache";
529 }
530 };
531
532 class TempFailureCacheTTLAction : public DNSAction
533 {
534 public:
535 TempFailureCacheTTLAction(uint32_t ttl) : d_ttl(ttl)
536 {}
537 TempFailureCacheTTLAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
538 {
539 dq->tempFailureTTL = d_ttl;
540 return Action::None;
541 }
542 string toString() const override
543 {
544 return "set tempfailure cache ttl to "+std::to_string(d_ttl);
545 }
546 private:
547 uint32_t d_ttl;
548 };
549
550 class ECSPrefixLengthAction : public DNSAction
551 {
552 public:
553 ECSPrefixLengthAction(uint16_t v4Length, uint16_t v6Length) : d_v4PrefixLength(v4Length), d_v6PrefixLength(v6Length)
554 {
555 }
556 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
557 {
558 dq->ecsPrefixLength = dq->remote->sin4.sin_family == AF_INET ? d_v4PrefixLength : d_v6PrefixLength;
559 return Action::None;
560 }
561 string toString() const override
562 {
563 return "set ECS prefix length to " + std::to_string(d_v4PrefixLength) + "/" + std::to_string(d_v6PrefixLength);
564 }
565 private:
566 uint16_t d_v4PrefixLength;
567 uint16_t d_v6PrefixLength;
568 };
569
570 class ECSOverrideAction : public DNSAction
571 {
572 public:
573 ECSOverrideAction(bool ecsOverride) : d_ecsOverride(ecsOverride)
574 {
575 }
576 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
577 {
578 dq->ecsOverride = d_ecsOverride;
579 return Action::None;
580 }
581 string toString() const override
582 {
583 return "set ECS override to " + std::to_string(d_ecsOverride);
584 }
585 private:
586 bool d_ecsOverride;
587 };
588
589
590 class DisableECSAction : public DNSAction
591 {
592 public:
593 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
594 {
595 dq->useECS = false;
596 return Action::None;
597 }
598 string toString() const override
599 {
600 return "disable ECS";
601 }
602 };
603
604 class DnstapLogAction : public DNSAction, public boost::noncopyable
605 {
606 public:
607 DnstapLogAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
608 {
609 }
610 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
611 {
612 #ifdef HAVE_PROTOBUF
613 DnstapMessage message(d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
614 {
615 if (d_alterFunc) {
616 std::lock_guard<std::mutex> lock(g_luamutex);
617 (*d_alterFunc)(*dq, &message);
618 }
619 }
620 std::string data;
621 message.serialize(data);
622 d_logger->queueData(data);
623 #endif /* HAVE_PROTOBUF */
624 return Action::None;
625 }
626 string toString() const override
627 {
628 return "remote log as dnstap to " + (d_logger ? d_logger->toString() : "");
629 }
630 private:
631 std::string d_identity;
632 std::shared_ptr<RemoteLoggerInterface> d_logger;
633 boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > d_alterFunc;
634 };
635
636 class RemoteLogAction : public DNSAction, public boost::noncopyable
637 {
638 public:
639 RemoteLogAction(std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc): d_logger(logger), d_alterFunc(alterFunc)
640 {
641 }
642 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
643 {
644 #ifdef HAVE_PROTOBUF
645 if (!dq->uniqueId) {
646 dq->uniqueId = t_uuidGenerator();
647 }
648
649 DNSDistProtoBufMessage message(*dq);
650 {
651 if (d_alterFunc) {
652 std::lock_guard<std::mutex> lock(g_luamutex);
653 (*d_alterFunc)(*dq, &message);
654 }
655 }
656 std::string data;
657 message.serialize(data);
658 d_logger->queueData(data);
659 #endif /* HAVE_PROTOBUF */
660 return Action::None;
661 }
662 string toString() const override
663 {
664 return "remote log to " + (d_logger ? d_logger->toString() : "");
665 }
666 private:
667 std::shared_ptr<RemoteLoggerInterface> d_logger;
668 boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > d_alterFunc;
669 };
670
671 class SNMPTrapAction : public DNSAction
672 {
673 public:
674 SNMPTrapAction(const std::string& reason): d_reason(reason)
675 {
676 }
677 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
678 {
679 if (g_snmpAgent && g_snmpTrapsEnabled) {
680 g_snmpAgent->sendDNSTrap(*dq, d_reason);
681 }
682
683 return Action::None;
684 }
685 string toString() const override
686 {
687 return "send SNMP trap";
688 }
689 private:
690 std::string d_reason;
691 };
692
693 class TagAction : public DNSAction
694 {
695 public:
696 TagAction(const std::string tag, const std::string value): d_tag(tag), d_value(value)
697 {
698 }
699 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
700 {
701 if (!dq->qTag) {
702 dq->qTag = std::make_shared<QTag>();
703 }
704
705 dq->qTag->insert({d_tag, d_value});
706
707 return Action::None;
708 }
709 string toString() const override
710 {
711 return "set tag '" + d_tag + "' to value '" + d_value + "'";
712 }
713 private:
714 std::string d_tag;
715 std::string d_value;
716 };
717
718 class DnstapLogResponseAction : public DNSResponseAction, public boost::noncopyable
719 {
720 public:
721 DnstapLogResponseAction(const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > alterFunc): d_identity(identity), d_logger(logger), d_alterFunc(alterFunc)
722 {
723 }
724 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
725 {
726 #ifdef HAVE_PROTOBUF
727 struct timespec now;
728 gettime(&now, true);
729 DnstapMessage message(d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
730 {
731 if (d_alterFunc) {
732 std::lock_guard<std::mutex> lock(g_luamutex);
733 (*d_alterFunc)(*dr, &message);
734 }
735 }
736 std::string data;
737 message.serialize(data);
738 d_logger->queueData(data);
739 #endif /* HAVE_PROTOBUF */
740 return Action::None;
741 }
742 string toString() const override
743 {
744 return "log response as dnstap to " + (d_logger ? d_logger->toString() : "");
745 }
746 private:
747 std::string d_identity;
748 std::shared_ptr<RemoteLoggerInterface> d_logger;
749 boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > d_alterFunc;
750 };
751
752 class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
753 {
754 public:
755 RemoteLogResponseAction(std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, bool includeCNAME): d_logger(logger), d_alterFunc(alterFunc), d_includeCNAME(includeCNAME)
756 {
757 }
758 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
759 {
760 #ifdef HAVE_PROTOBUF
761 if (!dr->uniqueId) {
762 dr->uniqueId = t_uuidGenerator();
763 }
764
765 DNSDistProtoBufMessage message(*dr, d_includeCNAME);
766 {
767 if (d_alterFunc) {
768 std::lock_guard<std::mutex> lock(g_luamutex);
769 (*d_alterFunc)(*dr, &message);
770 }
771 }
772 std::string data;
773 message.serialize(data);
774 d_logger->queueData(data);
775 #endif /* HAVE_PROTOBUF */
776 return Action::None;
777 }
778 string toString() const override
779 {
780 return "remote log response to " + (d_logger ? d_logger->toString() : "");
781 }
782 private:
783 std::shared_ptr<RemoteLoggerInterface> d_logger;
784 boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > d_alterFunc;
785 bool d_includeCNAME;
786 };
787
788 class DropResponseAction : public DNSResponseAction
789 {
790 public:
791 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
792 {
793 return Action::Drop;
794 }
795 string toString() const override
796 {
797 return "drop";
798 }
799 };
800
801 class AllowResponseAction : public DNSResponseAction
802 {
803 public:
804 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
805 {
806 return Action::Allow;
807 }
808 string toString() const override
809 {
810 return "allow";
811 }
812 };
813
814 class DelayResponseAction : public DNSResponseAction
815 {
816 public:
817 DelayResponseAction(int msec) : d_msec(msec)
818 {}
819 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
820 {
821 *ruleresult=std::to_string(d_msec);
822 return Action::Delay;
823 }
824 string toString() const override
825 {
826 return "delay by "+std::to_string(d_msec)+ " msec";
827 }
828 private:
829 int d_msec;
830 };
831
832 class SNMPTrapResponseAction : public DNSResponseAction
833 {
834 public:
835 SNMPTrapResponseAction(const std::string& reason): d_reason(reason)
836 {
837 }
838 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
839 {
840 if (g_snmpAgent && g_snmpTrapsEnabled) {
841 g_snmpAgent->sendDNSTrap(*dr, d_reason);
842 }
843
844 return Action::None;
845 }
846 string toString() const override
847 {
848 return "send SNMP trap";
849 }
850 private:
851 std::string d_reason;
852 };
853
854 class TagResponseAction : public DNSResponseAction
855 {
856 public:
857 TagResponseAction(const std::string tag, const std::string value): d_tag(tag), d_value(value)
858 {
859 }
860 DNSResponseAction::Action operator()(DNSResponse* dr, string* ruleresult) const override
861 {
862 if (!dr->qTag) {
863 dr->qTag = std::make_shared<QTag>();
864 }
865
866 dr->qTag->insert({d_tag, d_value});
867
868 return Action::None;
869 }
870 string toString() const override
871 {
872 return "set tag '" + d_tag + "' to value '" + d_value + "'";
873 }
874 private:
875 std::string d_tag;
876 std::string d_value;
877 };
878
879 template<typename T, typename ActionT>
880 static void addAction(GlobalStateHolder<vector<T> > *someRulActions, luadnsrule_t var, std::shared_ptr<ActionT> action, boost::optional<luaruleparams_t> params) {
881 setLuaSideEffect();
882
883 boost::uuids::uuid uuid;
884 parseRuleParams(params, uuid);
885
886 auto rule=makeRule(var);
887 someRulActions->modify([rule, action, uuid](vector<T>& rulactions){
888 rulactions.push_back({rule, action, uuid});
889 });
890 }
891
892 void setupLuaActions()
893 {
894 g_lua.writeFunction("newRuleAction", [](luadnsrule_t dnsrule, std::shared_ptr<DNSAction> action, boost::optional<luaruleparams_t> params) {
895 boost::uuids::uuid uuid;
896 parseRuleParams(params, uuid);
897
898 auto rule=makeRule(dnsrule);
899 DNSDistRuleAction ra({rule, action, uuid});
900 return std::make_shared<DNSDistRuleAction>(ra);
901 });
902
903 g_lua.writeFunction("addAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
904 if (era.type() != typeid(std::shared_ptr<DNSAction>)) {
905 throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?");
906 }
907
908 addAction(&g_rulactions, var, boost::get<std::shared_ptr<DNSAction> >(era), params);
909 });
910
911 g_lua.writeFunction("addLuaAction", [](luadnsrule_t var, LuaAction::func_t func, boost::optional<luaruleparams_t> params) {
912 addAction(&g_rulactions, var, std::make_shared<LuaAction>(func), params);
913 });
914
915 g_lua.writeFunction("addLuaResponseAction", [](luadnsrule_t var, LuaResponseAction::func_t func, boost::optional<luaruleparams_t> params) {
916 addAction(&g_resprulactions, var, std::make_shared<LuaResponseAction>(func), params);
917 });
918
919 g_lua.writeFunction("addResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction> > era, boost::optional<luaruleparams_t> params) {
920 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
921 throw std::runtime_error("addResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
922 }
923
924 addAction(&g_resprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
925 });
926
927 g_lua.writeFunction("addCacheHitResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
928 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
929 throw std::runtime_error("addCacheHitResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
930 }
931
932 addAction(&g_cachehitresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
933 });
934
935 g_lua.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant<std::shared_ptr<DNSAction>, std::shared_ptr<DNSResponseAction>> era, boost::optional<luaruleparams_t> params) {
936 if (era.type() != typeid(std::shared_ptr<DNSResponseAction>)) {
937 throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?");
938 }
939
940 addAction(&g_selfansweredresprulactions, var, boost::get<std::shared_ptr<DNSResponseAction> >(era), params);
941 });
942
943 g_lua.registerFunction<void(DNSAction::*)()>("printStats", [](const DNSAction& ta) {
944 setLuaNoSideEffect();
945 auto stats = ta.getStats();
946 for(const auto& s : stats) {
947 g_outputBuffer+=s.first+"\t";
948 if((uint64_t)s.second == s.second)
949 g_outputBuffer += std::to_string((uint64_t)s.second)+"\n";
950 else
951 g_outputBuffer += std::to_string(s.second)+"\n";
952 }
953 });
954
955 g_lua.writeFunction("getAction", [](unsigned int num) {
956 setLuaNoSideEffect();
957 boost::optional<std::shared_ptr<DNSAction>> ret;
958 auto rulactions = g_rulactions.getCopy();
959 if(num < rulactions.size())
960 ret=rulactions[num].d_action;
961 return ret;
962 });
963
964 g_lua.registerFunction("getStats", &DNSAction::getStats);
965
966 g_lua.writeFunction("LuaAction", [](LuaAction::func_t func) {
967 setLuaSideEffect();
968 return std::shared_ptr<DNSAction>(new LuaAction(func));
969 });
970
971 g_lua.writeFunction("NoRecurseAction", []() {
972 return std::shared_ptr<DNSAction>(new NoRecurseAction);
973 });
974
975 g_lua.writeFunction("MacAddrAction", [](int code) {
976 return std::shared_ptr<DNSAction>(new MacAddrAction(code));
977 });
978
979 g_lua.writeFunction("PoolAction", [](const string& a) {
980 return std::shared_ptr<DNSAction>(new PoolAction(a));
981 });
982
983 g_lua.writeFunction("QPSAction", [](int limit) {
984 return std::shared_ptr<DNSAction>(new QPSAction(limit));
985 });
986
987 g_lua.writeFunction("QPSPoolAction", [](int limit, const string& a) {
988 return std::shared_ptr<DNSAction>(new QPSPoolAction(limit, a));
989 });
990
991 g_lua.writeFunction("SpoofAction", [](boost::variant<string,vector<pair<int, string>>> inp, boost::optional<string> b ) {
992 vector<ComboAddress> addrs;
993 if(auto s = boost::get<string>(&inp))
994 addrs.push_back(ComboAddress(*s));
995 else {
996 const auto& v = boost::get<vector<pair<int,string>>>(inp);
997 for(const auto& a: v)
998 addrs.push_back(ComboAddress(a.second));
999 }
1000 if(b)
1001 addrs.push_back(ComboAddress(*b));
1002 return std::shared_ptr<DNSAction>(new SpoofAction(addrs));
1003 });
1004
1005 g_lua.writeFunction("SpoofCNAMEAction", [](const string& a) {
1006 return std::shared_ptr<DNSAction>(new SpoofAction(a));
1007 });
1008
1009 g_lua.writeFunction("DropAction", []() {
1010 return std::shared_ptr<DNSAction>(new DropAction);
1011 });
1012
1013 g_lua.writeFunction("AllowAction", []() {
1014 return std::shared_ptr<DNSAction>(new AllowAction);
1015 });
1016
1017 g_lua.writeFunction("DelayAction", [](int msec) {
1018 return std::shared_ptr<DNSAction>(new DelayAction(msec));
1019 });
1020
1021 g_lua.writeFunction("TCAction", []() {
1022 return std::shared_ptr<DNSAction>(new TCAction);
1023 });
1024
1025 g_lua.writeFunction("DisableValidationAction", []() {
1026 return std::shared_ptr<DNSAction>(new DisableValidationAction);
1027 });
1028
1029 g_lua.writeFunction("LogAction", [](const std::string& fname, boost::optional<bool> binary, boost::optional<bool> append, boost::optional<bool> buffered) {
1030 return std::shared_ptr<DNSAction>(new LogAction(fname, binary ? *binary : true, append ? *append : false, buffered ? *buffered : false));
1031 });
1032
1033 g_lua.writeFunction("RCodeAction", [](uint8_t rcode) {
1034 return std::shared_ptr<DNSAction>(new RCodeAction(rcode));
1035 });
1036
1037 g_lua.writeFunction("SkipCacheAction", []() {
1038 return std::shared_ptr<DNSAction>(new SkipCacheAction);
1039 });
1040
1041 g_lua.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
1042 return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
1043 });
1044
1045 g_lua.writeFunction("DropResponseAction", []() {
1046 return std::shared_ptr<DNSResponseAction>(new DropResponseAction);
1047 });
1048
1049 g_lua.writeFunction("AllowResponseAction", []() {
1050 return std::shared_ptr<DNSResponseAction>(new AllowResponseAction);
1051 });
1052
1053 g_lua.writeFunction("DelayResponseAction", [](int msec) {
1054 return std::shared_ptr<DNSResponseAction>(new DelayResponseAction(msec));
1055 });
1056
1057 g_lua.writeFunction("LuaResponseAction", [](LuaResponseAction::func_t func) {
1058 setLuaSideEffect();
1059 return std::shared_ptr<DNSResponseAction>(new LuaResponseAction(func));
1060 });
1061
1062 g_lua.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DNSDistProtoBufMessage*)> > alterFunc) {
1063 // avoids potentially-evaluated-expression warning with clang.
1064 RemoteLoggerInterface& rl = *logger.get();
1065 if (typeid(rl) != typeid(RemoteLogger)) {
1066 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1067 throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
1068 }
1069 #ifdef HAVE_PROTOBUF
1070 return std::shared_ptr<DNSAction>(new RemoteLogAction(logger, alterFunc));
1071 #else
1072 throw std::runtime_error("Protobuf support is required to use RemoteLogAction");
1073 #endif
1074 });
1075
1076 g_lua.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DNSDistProtoBufMessage*)> > alterFunc, boost::optional<bool> includeCNAME) {
1077 // avoids potentially-evaluated-expression warning with clang.
1078 RemoteLoggerInterface& rl = *logger.get();
1079 if (typeid(rl) != typeid(RemoteLogger)) {
1080 // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
1081 throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
1082 }
1083 #ifdef HAVE_PROTOBUF
1084 return std::shared_ptr<DNSResponseAction>(new RemoteLogResponseAction(logger, alterFunc, includeCNAME ? *includeCNAME : false));
1085 #else
1086 throw std::runtime_error("Protobuf support is required to use RemoteLogResponseAction");
1087 #endif
1088 });
1089
1090 g_lua.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSQuestion&, DnstapMessage*)> > alterFunc) {
1091 #ifdef HAVE_PROTOBUF
1092 return std::shared_ptr<DNSAction>(new DnstapLogAction(identity, logger, alterFunc));
1093 #else
1094 throw std::runtime_error("Protobuf support is required to use DnstapLogAction");
1095 #endif
1096 });
1097
1098 g_lua.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, boost::optional<std::function<void(const DNSResponse&, DnstapMessage*)> > alterFunc) {
1099 #ifdef HAVE_PROTOBUF
1100 return std::shared_ptr<DNSResponseAction>(new DnstapLogResponseAction(identity, logger, alterFunc));
1101 #else
1102 throw std::runtime_error("Protobuf support is required to use DnstapLogResponseAction");
1103 #endif
1104 });
1105
1106 g_lua.writeFunction("TeeAction", [](const std::string& remote, boost::optional<bool> addECS) {
1107 return std::shared_ptr<DNSAction>(new TeeAction(ComboAddress(remote, 53), addECS ? *addECS : false));
1108 });
1109
1110 g_lua.writeFunction("ECSPrefixLengthAction", [](uint16_t v4PrefixLength, uint16_t v6PrefixLength) {
1111 return std::shared_ptr<DNSAction>(new ECSPrefixLengthAction(v4PrefixLength, v6PrefixLength));
1112 });
1113
1114 g_lua.writeFunction("ECSOverrideAction", [](bool ecsOverride) {
1115 return std::shared_ptr<DNSAction>(new ECSOverrideAction(ecsOverride));
1116 });
1117
1118 g_lua.writeFunction("DisableECSAction", []() {
1119 return std::shared_ptr<DNSAction>(new DisableECSAction());
1120 });
1121
1122 g_lua.writeFunction("SNMPTrapAction", [](boost::optional<std::string> reason) {
1123 #ifdef HAVE_NET_SNMP
1124 return std::shared_ptr<DNSAction>(new SNMPTrapAction(reason ? *reason : ""));
1125 #else
1126 throw std::runtime_error("NET SNMP support is required to use SNMPTrapAction()");
1127 #endif /* HAVE_NET_SNMP */
1128 });
1129
1130 g_lua.writeFunction("SNMPTrapResponseAction", [](boost::optional<std::string> reason) {
1131 #ifdef HAVE_NET_SNMP
1132 return std::shared_ptr<DNSResponseAction>(new SNMPTrapResponseAction(reason ? *reason : ""));
1133 #else
1134 throw std::runtime_error("NET SNMP support is required to use SNMPTrapResponseAction()");
1135 #endif /* HAVE_NET_SNMP */
1136 });
1137
1138 g_lua.writeFunction("TagAction", [](std::string tag, std::string value) {
1139 return std::shared_ptr<DNSAction>(new TagAction(tag, value));
1140 });
1141
1142 g_lua.writeFunction("TagResponseAction", [](std::string tag, std::string value) {
1143 return std::shared_ptr<DNSResponseAction>(new TagResponseAction(tag, value));
1144 });
1145 }