]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsrulactions.hh
Protobuf refactoring
[thirdparty/pdns.git] / pdns / dnsrulactions.hh
CommitLineData
0940e4eb 1#include "dnsdist.hh"
01520028 2#include "dnsdist-ecs.hh"
0940e4eb 3#include "dnsname.hh"
808c5ef7 4#include "dolog.hh"
5c3b5e7f 5#include "ednsoptions.hh"
f0acf608 6#include "lock.hh"
ec469dd7
RG
7#include "remote_logger.hh"
8#include "dnsdist-protobuf.hh"
55baa1f2 9#include "dnsparser.hh"
0940e4eb 10
6bba426c 11class MaxQPSIPRule : public DNSRule
12{
13public:
1b726acf 14 MaxQPSIPRule(unsigned int qps, unsigned int ipv4trunc=32, unsigned int ipv6trunc=64) :
15 d_qps(qps), d_ipv4trunc(ipv4trunc), d_ipv6trunc(ipv6trunc)
f0acf608
RG
16 {
17 pthread_rwlock_init(&d_lock, 0);
18 }
6bba426c 19
497a6e3a 20 bool matches(const DNSQuestion* dq) const override
6bba426c 21 {
497a6e3a 22 ComboAddress zeroport(*dq->remote);
6bba426c 23 zeroport.sin4.sin_port=0;
1b726acf 24 zeroport.truncate(zeroport.sin4.sin_family == AF_INET ? d_ipv4trunc : d_ipv6trunc);
f0acf608
RG
25 {
26 ReadLock r(&d_lock);
27 const auto iter = d_limits.find(zeroport);
28 if (iter != d_limits.end()) {
29 return !iter->second.check();
30 }
31 }
32 {
33 WriteLock w(&d_lock);
34 auto iter = d_limits.find(zeroport);
35 if(iter == d_limits.end()) {
36 iter=d_limits.insert({zeroport,QPSLimiter(d_qps, d_qps)}).first;
37 }
38 return !iter->second.check();
6bba426c 39 }
6bba426c 40 }
41
42 string toString() const override
43 {
1b726acf 44 return "IP (/"+std::to_string(d_ipv4trunc)+", /"+std::to_string(d_ipv6trunc)+") match for QPS over " + std::to_string(d_qps);
6bba426c 45 }
46
47
48private:
f0acf608 49 mutable pthread_rwlock_t d_lock;
6bba426c 50 mutable std::map<ComboAddress, QPSLimiter> d_limits;
1b726acf 51 unsigned int d_qps, d_ipv4trunc, d_ipv6trunc;
6bba426c 52
53};
54
2332b03c 55class MaxQPSRule : public DNSRule
56{
57public:
58 MaxQPSRule(unsigned int qps)
59 : d_qps(qps, qps)
60 {}
61
62 MaxQPSRule(unsigned int qps, unsigned int burst)
63 : d_qps(qps, burst)
64 {}
65
66
497a6e3a 67 bool matches(const DNSQuestion* qd) const override
2332b03c 68 {
69 return d_qps.check();
70 }
71
72 string toString() const override
73 {
74 return "Max " + std::to_string(d_qps.getRate()) + " qps";
75 }
76
77
78private:
79 mutable QPSLimiter d_qps;
80};
81
82
6bba426c 83
0940e4eb 84class NetmaskGroupRule : public DNSRule
85{
86public:
87 NetmaskGroupRule(const NetmaskGroup& nmg) : d_nmg(nmg)
88 {
89
90 }
497a6e3a 91 bool matches(const DNSQuestion* dq) const override
0940e4eb 92 {
497a6e3a 93 return d_nmg.match(*dq->remote);
0940e4eb 94 }
95
96 string toString() const override
97 {
a95d4eeb 98 return "Src: "+d_nmg.toString();
0940e4eb 99 }
100private:
101 NetmaskGroup d_nmg;
102};
103
89cb6f9a 104class AllRule : public DNSRule
105{
106public:
107 AllRule() {}
497a6e3a 108 bool matches(const DNSQuestion* dq) const override
89cb6f9a 109 {
110 return true;
111 }
112
113 string toString() const override
114 {
115 return "All";
116 }
117
118};
119
120
520eb5a0 121class DNSSECRule : public DNSRule
122{
123public:
124 DNSSECRule()
125 {
126
127 }
497a6e3a 128 bool matches(const DNSQuestion* dq) const override
520eb5a0 129 {
497a6e3a 130 return dq->dh->cd || (getEDNSZ((const char*)dq->dh, dq->len) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
520eb5a0 131 }
132
133 string toString() const override
134 {
135 return "DNSSEC";
136 }
137};
138
b7860997 139class AndRule : public DNSRule
140{
141public:
142 AndRule(const vector<pair<int, shared_ptr<DNSRule> > >& rules)
143 {
144 for(const auto& r : rules)
145 d_rules.push_back(r.second);
146 }
147
497a6e3a 148 bool matches(const DNSQuestion* dq) const override
b7860997 149 {
150 auto iter = d_rules.begin();
151 for(; iter != d_rules.end(); ++iter)
497a6e3a 152 if(!(*iter)->matches(dq))
b7860997 153 break;
154 return iter == d_rules.end();
155 }
156
157 string toString() const override
158 {
159 string ret;
160 for(const auto& rule : d_rules) {
161 if(!ret.empty())
162 ret+= " && ";
163 ret += "("+ rule->toString()+")";
164 }
165 return ret;
166 }
167private:
168
169 vector<std::shared_ptr<DNSRule> > d_rules;
170
171};
172
173
e7a1029c
RG
174class OrRule : public DNSRule
175{
176public:
177 OrRule(const vector<pair<int, shared_ptr<DNSRule> > >& rules)
178 {
179 for(const auto& r : rules)
180 d_rules.push_back(r.second);
181 }
182
183 bool matches(const DNSQuestion* dq) const override
184 {
185 auto iter = d_rules.begin();
186 for(; iter != d_rules.end(); ++iter)
187 if((*iter)->matches(dq))
188 return true;
189 return false;
190 }
191
192 string toString() const override
193 {
194 string ret;
195 for(const auto& rule : d_rules) {
196 if(!ret.empty())
197 ret+= " || ";
198 ret += "("+ rule->toString()+")";
199 }
200 return ret;
201 }
202private:
203
204 vector<std::shared_ptr<DNSRule> > d_rules;
205
206};
207
208
6eecd4c2 209class RegexRule : public DNSRule
210{
211public:
212 RegexRule(const std::string& regex) : d_regex(regex), d_visual(regex)
213 {
214
215 }
497a6e3a 216 bool matches(const DNSQuestion* dq) const override
6eecd4c2 217 {
497a6e3a 218 return d_regex.match(dq->qname->toStringNoDot());
6eecd4c2 219 }
220
221 string toString() const override
222 {
4ed8dfeb 223 return "Regex: "+d_visual;
6eecd4c2 224 }
225private:
226 Regex d_regex;
227 string d_visual;
228};
229
4ed8dfeb 230#ifdef HAVE_RE2
231#include <re2/re2.h>
232class RE2Rule : public DNSRule
233{
234public:
235 RE2Rule(const std::string& re2) : d_re2(re2, RE2::Latin1), d_visual(re2)
236 {
237
238 }
239 bool matches(const DNSQuestion* dq) const override
240 {
241 return RE2::FullMatch(dq->qname->toStringNoDot(), d_re2);
242 }
243
244 string toString() const override
245 {
246 return "RE2 match: "+d_visual;
247 }
248private:
249 RE2 d_re2;
250 string d_visual;
251};
252#endif
253
520eb5a0 254
0940e4eb 255class SuffixMatchNodeRule : public DNSRule
256{
257public:
291729f3 258 SuffixMatchNodeRule(const SuffixMatchNode& smn, bool quiet=false) : d_smn(smn), d_quiet(quiet)
0940e4eb 259 {
260 }
497a6e3a 261 bool matches(const DNSQuestion* dq) const override
0940e4eb 262 {
497a6e3a 263 return d_smn.check(*dq->qname);
0940e4eb 264 }
265 string toString() const override
266 {
291729f3 267 if(d_quiet)
268 return "qname==in-set";
269 else
270 return "qname=="+d_smn.toString();
0940e4eb 271 }
272private:
273 SuffixMatchNode d_smn;
291729f3 274 bool d_quiet;
0940e4eb 275};
276
277class QTypeRule : public DNSRule
278{
279public:
280 QTypeRule(uint16_t qtype) : d_qtype(qtype)
281 {
282 }
497a6e3a 283 bool matches(const DNSQuestion* dq) const override
0940e4eb 284 {
497a6e3a 285 return d_qtype == dq->qtype;
0940e4eb 286 }
287 string toString() const override
288 {
289 QType qt(d_qtype);
290 return "qtype=="+qt.getName();
291 }
292private:
293 uint16_t d_qtype;
294};
295
3b069df2 296class QClassRule : public DNSRule
297{
298public:
299 QClassRule(uint16_t qclass) : d_qclass(qclass)
300 {
301 }
302 bool matches(const DNSQuestion* dq) const override
303 {
304 return d_qclass == dq->qclass;
305 }
306 string toString() const override
307 {
308 return "qclass=="+std::to_string(d_qclass);
309 }
310private:
311 uint16_t d_qclass;
312};
313
55baa1f2
RG
314class OpcodeRule : public DNSRule
315{
316public:
317 OpcodeRule(uint8_t opcode) : d_opcode(opcode)
318 {
319 }
320 bool matches(const DNSQuestion* dq) const override
321 {
322 return d_opcode == dq->dh->opcode;
323 }
324 string toString() const override
325 {
326 return "opcode=="+d_opcode;
327 }
328private:
329 uint8_t d_opcode;
330};
3b069df2 331
490a29bb
RG
332class TCPRule : public DNSRule
333{
334public:
335 TCPRule(bool tcp): d_tcp(tcp)
336 {
337 }
338 bool matches(const DNSQuestion* dq) const override
339 {
340 return dq->tcp == d_tcp;
341 }
342 string toString() const override
343 {
344 return (d_tcp ? "TCP" : "UDP");
345 }
346private:
347 bool d_tcp;
348};
349
e7a1029c
RG
350
351class NotRule : public DNSRule
352{
353public:
354 NotRule(shared_ptr<DNSRule>& rule): d_rule(rule)
355 {
356 }
357 bool matches(const DNSQuestion* dq) const override
358 {
359 return !d_rule->matches(dq);
360 }
361 string toString() const override
362 {
3b069df2 363 return "!("+ d_rule->toString()+")";
e7a1029c
RG
364 }
365private:
366 shared_ptr<DNSRule> d_rule;
367};
368
55baa1f2
RG
369class RecordsCountRule : public DNSRule
370{
371public:
372 RecordsCountRule(uint8_t section, uint16_t minCount, uint16_t maxCount): d_minCount(minCount), d_maxCount(maxCount), d_section(section)
373 {
374 }
375 bool matches(const DNSQuestion* dq) const override
376 {
377 uint16_t count = 0;
378 switch(d_section) {
379 case 0:
380 count = ntohs(dq->dh->qdcount);
381 break;
382 case 1:
383 count = ntohs(dq->dh->ancount);
384 break;
385 case 2:
386 count = ntohs(dq->dh->nscount);
387 break;
388 case 3:
389 count = ntohs(dq->dh->arcount);
390 break;
391 }
392 return count >= d_minCount && count <= d_maxCount;
393 }
394 string toString() const override
395 {
396 string section;
397 switch(d_section) {
398 case 0:
399 section = "QD";
400 break;
401 case 1:
402 section = "AN";
403 break;
404 case 2:
405 section = "NS";
406 break;
407 case 3:
408 section = "AR";
409 break;
410 }
411 return std::to_string(d_minCount) + " <= records in " + section + " <= "+ std::to_string(d_maxCount);
412 }
413private:
414 uint16_t d_minCount;
415 uint16_t d_maxCount;
416 uint8_t d_section;
417};
418
419class RecordsTypeCountRule : public DNSRule
420{
421public:
422 RecordsTypeCountRule(uint8_t section, uint16_t type, uint16_t minCount, uint16_t maxCount): d_type(type), d_minCount(minCount), d_maxCount(maxCount), d_section(section)
423 {
424 }
425 bool matches(const DNSQuestion* dq) const override
426 {
427 uint16_t count = 0;
428 switch(d_section) {
429 case 0:
430 count = ntohs(dq->dh->qdcount);
431 break;
432 case 1:
433 count = ntohs(dq->dh->ancount);
434 break;
435 case 2:
436 count = ntohs(dq->dh->nscount);
437 break;
438 case 3:
439 count = ntohs(dq->dh->arcount);
440 break;
441 }
442 if (count < d_minCount || count > d_maxCount) {
443 return false;
444 }
445 count = getRecordsOfTypeCount(reinterpret_cast<const char*>(dq->dh), dq->len, d_section, d_type);
446 return count >= d_minCount && count <= d_maxCount;
447 }
448 string toString() const override
449 {
450 string section;
451 switch(d_section) {
452 case 0:
453 section = "QD";
454 break;
455 case 1:
456 section = "AN";
457 break;
458 case 2:
459 section = "NS";
460 break;
461 case 3:
462 section = "AR";
463 break;
464 }
465 return std::to_string(d_minCount) + " <= " + QType(d_type).getName() + " records in " + section + " <= "+ std::to_string(d_maxCount);
466 }
467private:
468 uint16_t d_type;
469 uint16_t d_minCount;
470 uint16_t d_maxCount;
471 uint8_t d_section;
472};
473
474class TrailingDataRule : public DNSRule
475{
476public:
477 TrailingDataRule()
478 {
479 }
480 bool matches(const DNSQuestion* dq) const override
481 {
482 uint16_t length = getDNSPacketLength(reinterpret_cast<const char*>(dq->dh), dq->len);
483 return length < dq->len;
484 }
485 string toString() const override
486 {
487 return "trailing data";
488 }
489};
e7a1029c 490
0940e4eb 491class DropAction : public DNSAction
492{
493public:
497a6e3a 494 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
0940e4eb 495 {
496 return Action::Drop;
497 }
498 string toString() const override
499 {
500 return "drop";
501 }
502};
503
63beb26d
G
504class AllowAction : public DNSAction
505{
506public:
497a6e3a 507 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
63beb26d
G
508 {
509 return Action::Allow;
510 }
511 string toString() const override
512 {
513 return "allow";
514 }
515};
516
6bba426c 517
0940e4eb 518class QPSAction : public DNSAction
519{
520public:
521 QPSAction(int limit) : d_qps(limit, limit)
522 {}
497a6e3a 523 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
0940e4eb 524 {
525 if(d_qps.check())
856c35e3 526 return Action::None;
0940e4eb 527 else
528 return Action::Drop;
529 }
530 string toString() const override
531 {
532 return "qps limit to "+std::to_string(d_qps.getRate());
533 }
534private:
535 QPSLimiter d_qps;
536};
537
7b3865cd 538class DelayAction : public DNSAction
539{
540public:
541 DelayAction(int msec) : d_msec(msec)
542 {}
497a6e3a 543 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
7b3865cd 544 {
545 *ruleresult=std::to_string(d_msec);
546 return Action::Delay;
547 }
548 string toString() const override
549 {
550 return "delay by "+std::to_string(d_msec)+ " msec";
551 }
552private:
553 int d_msec;
554};
555
556
cf6874ba 557class TeeAction : public DNSAction
558{
559public:
384c2cb2 560 TeeAction(const ComboAddress& ca, bool addECS=false);
cf6874ba 561 ~TeeAction();
562 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override;
563 string toString() const override;
564 std::unordered_map<string, double> getStats() const override;
565private:
566 ComboAddress d_remote;
567 std::thread d_worker;
568 void worker();
569
570 int d_fd;
fa6c1f0c 571 mutable std::atomic<unsigned long> d_senderrors{0};
3d8a6b1d 572 unsigned long d_recverrors{0};
fa6c1f0c 573 mutable std::atomic<unsigned long> d_queries{0};
cf6874ba 574 unsigned long d_responses{0};
3d8a6b1d 575 unsigned long d_nxdomains{0};
576 unsigned long d_servfails{0};
577 unsigned long d_refuseds{0};
578 unsigned long d_formerrs{0};
579 unsigned long d_notimps{0};
580 unsigned long d_noerrors{0};
581 mutable unsigned long d_tcpdrops{0};
582 unsigned long d_otherrcode{0};
cf6874ba 583 std::atomic<bool> d_pleaseQuit{false};
384c2cb2 584 bool d_addECS{false};
cf6874ba 585};
586
587
588
0940e4eb 589class PoolAction : public DNSAction
590{
591public:
592 PoolAction(const std::string& pool) : d_pool(pool) {}
497a6e3a 593 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
0940e4eb 594 {
595 *ruleresult=d_pool;
596 return Action::Pool;
597 }
598 string toString() const override
599 {
600 return "to pool "+d_pool;
601 }
602
603private:
604 string d_pool;
605};
606
fd010ca3 607
608class QPSPoolAction : public DNSAction
609{
610public:
611 QPSPoolAction(unsigned int limit, const std::string& pool) : d_qps(limit, limit), d_pool(pool) {}
497a6e3a 612 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
fd010ca3 613 {
614 if(d_qps.check()) {
615 *ruleresult=d_pool;
616 return Action::Pool;
617 }
618 else
619 return Action::None;
620 }
621 string toString() const override
622 {
623 return "max " +std::to_string(d_qps.getRate())+" to pool "+d_pool;
624 }
625
626private:
627 QPSLimiter d_qps;
628 string d_pool;
629};
630
0940e4eb 631class RCodeAction : public DNSAction
632{
633public:
634 RCodeAction(int rcode) : d_rcode(rcode) {}
497a6e3a 635 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
0940e4eb 636 {
497a6e3a
RG
637 dq->dh->rcode = d_rcode;
638 dq->dh->qr = true; // for good measure
0940e4eb 639 return Action::HeaderModify;
640 }
641 string toString() const override
642 {
643 return "set rcode "+std::to_string(d_rcode);
644 }
645
646private:
647 int d_rcode;
648};
649
650class TCAction : public DNSAction
651{
652public:
497a6e3a 653 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
0940e4eb 654 {
497a6e3a
RG
655 dq->dh->tc = true;
656 dq->dh->qr = true; // for good measure
0940e4eb 657 return Action::HeaderModify;
658 }
659 string toString() const override
660 {
661 return "tc=1 answer";
662 }
663};
0570f37c 664
731774a8 665class SpoofAction : public DNSAction
666{
667public:
9ebc0e91 668 SpoofAction(const vector<ComboAddress>& addrs) : d_addrs(addrs)
7791f83a 669 {
7791f83a 670 }
9ebc0e91 671
672 SpoofAction(const string& cname): d_cname(cname) { }
673
497a6e3a 674 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
731774a8 675 {
497a6e3a 676 uint16_t qtype = dq->qtype;
9ebc0e91 677 // do we even have a response?
678 if(d_cname.empty() && !std::count_if(d_addrs.begin(), d_addrs.end(), [qtype](const ComboAddress& a)
679 {
680 return (qtype == QType::ANY || ((a.sin4.sin_family == AF_INET && qtype == QType::A) ||
681 (a.sin4.sin_family == AF_INET6 && qtype == QType::AAAA)));
682 }))
731774a8 683 return Action::None;
9ebc0e91 684
685 vector<ComboAddress> addrs;
686 unsigned int totrdatalen=0;
87c605c4
RG
687 if (!d_cname.empty()) {
688 qtype = QType::CNAME;
9ebc0e91 689 totrdatalen += d_cname.toDNSString().size();
87c605c4 690 } else {
9ebc0e91 691 for(const auto& addr : d_addrs) {
692 if(qtype != QType::ANY && ((addr.sin4.sin_family == AF_INET && qtype != QType::A) ||
693 (addr.sin4.sin_family == AF_INET6 && qtype != QType::AAAA)))
694 continue;
a683e8bd 695 totrdatalen += addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
9ebc0e91 696 addrs.push_back(addr);
697 }
87c605c4
RG
698 }
699
9ebc0e91 700 if(addrs.size() > 1)
701 random_shuffle(addrs.begin(), addrs.end());
87c605c4 702
9ebc0e91 703 unsigned int consumed=0;
497a6e3a 704 DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
87c605c4 705
9ebc0e91 706 if (dq->size < (sizeof(dnsheader) + consumed + 4 + ((d_cname.empty() ? 0 : 1) + addrs.size())*12 /* recordstart */ + totrdatalen)) {
87c605c4
RG
707 return Action::None;
708 }
709
9ebc0e91 710 dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS
711 char* dest = ((char*)dq->dh) + dq->len;
712
497a6e3a
RG
713 dq->dh->qr = true; // for good measure
714 dq->dh->ra = dq->dh->rd; // for good measure
715 dq->dh->ad = false;
9ebc0e91 716 dq->dh->ancount = 0;
497a6e3a 717 dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
731774a8 718
9ebc0e91 719 if(qtype == QType::CNAME) {
720 string wireData = d_cname.toDNSString(); // Note! This doesn't do compression!
721 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
722 0, (unsigned char) qtype,
723 0, QClass::IN, // IN
724 0, 0, 0, 60, // TTL
725 0, (unsigned char)wireData.length()};
a683e8bd 726 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
9ebc0e91 727
728 memcpy(dest, recordstart, sizeof(recordstart));
729 dest += sizeof(recordstart);
730 memcpy(dest, wireData.c_str(), wireData.length());
731 dq->len += wireData.length() + sizeof(recordstart);
732 dq->dh->ancount++;
87c605c4 733 }
a683e8bd
RG
734 else {
735 for(const auto& addr : addrs) {
736 unsigned char rdatalen = addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr);
737 const unsigned char recordstart[]={0xc0, 0x0c, // compressed name
738 0, (unsigned char) (addr.sin4.sin_family == AF_INET ? QType::A : QType::AAAA),
739 0, QClass::IN, // IN
740 0, 0, 0, 60, // TTL
741 0, rdatalen};
742 static_assert(sizeof(recordstart) == 12, "sizeof(recordstart) must be equal to 12, otherwise the above check is invalid");
743
744 memcpy(dest, recordstart, sizeof(recordstart));
745 dest += sizeof(recordstart);
746
747 memcpy(dest,
748 addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
749 rdatalen);
750 dest += rdatalen;
751 dq->len += rdatalen + sizeof(recordstart);
752 dq->dh->ancount++;
753 }
9ebc0e91 754 }
a683e8bd 755
9ebc0e91 756 dq->dh->ancount = htons(dq->dh->ancount);
757
731774a8 758 return Action::HeaderModify;
759 }
9ebc0e91 760
731774a8 761 string toString() const override
762 {
9ebc0e91 763 string ret = "spoof in ";
87c605c4 764 if(!d_cname.empty()) {
9ebc0e91 765 ret+=d_cname.toString()+ " ";
87c605c4 766 } else {
9ebc0e91 767 for(const auto& a : d_addrs)
768 ret += a.toString()+" ";
731774a8 769 }
770 return ret;
771 }
772private:
9ebc0e91 773 std::vector<ComboAddress> d_addrs;
87c605c4 774 DNSName d_cname;
731774a8 775};
776
6907f014 777class MacAddrAction : public DNSAction
778{
779public:
780 MacAddrAction(uint16_t code) : d_code(code)
781 {}
782 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
783 {
784 if(dq->dh->arcount)
785 return Action::None;
786
01520028
RG
787 string mac = getMACAddress(*dq->remote);
788 if(mac.empty())
789 return Action::None;
790
6907f014 791 string optRData;
01520028
RG
792 generateEDNSOption(d_code, mac, optRData);
793
794 string res;
795 generateOptRR(optRData, res);
796
797 if ((dq->size - dq->len) < res.length())
798 return Action::None;
799
800 dq->dh->arcount = htons(1);
801 char* dest = ((char*)dq->dh) + dq->len;
802 memcpy(dest, res.c_str(), res.length());
803 dq->len += res.length();
804
6907f014 805 return Action::None;
806 }
807 string toString() const override
808 {
809 return "add EDNS MAC (code="+std::to_string(d_code)+")";
810 }
811private:
812 uint16_t d_code{3};
813};
731774a8 814
0570f37c 815class NoRecurseAction : public DNSAction
816{
817public:
497a6e3a 818 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
0570f37c 819 {
497a6e3a 820 dq->dh->rd = false;
1a2a4e68 821 return Action::None;
0570f37c 822 }
823 string toString() const override
824 {
6bba426c 825 return "set rd=0";
0570f37c 826 }
827};
f39b7598 828
808c5ef7 829class LogAction : public DNSAction, public boost::noncopyable
830{
831public:
832 LogAction() : d_fp(0)
833 {
834 }
18029431 835 LogAction(const std::string& str, bool binary=true) : d_fname(str), d_binary(binary)
808c5ef7 836 {
837 if(str.empty())
838 return;
839 d_fp = fopen(str.c_str(), "w");
840 if(!d_fp)
841 throw std::runtime_error("Unable to open file '"+str+"' for logging: "+string(strerror(errno)));
842 }
843 ~LogAction()
844 {
845 if(d_fp)
846 fclose(d_fp);
847 }
497a6e3a 848 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
808c5ef7 849 {
0a271e94 850 if(!d_fp) {
497a6e3a 851 vinfolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
0a271e94 852 }
808c5ef7 853 else {
18029431
RG
854 if(d_binary) {
855 string out = dq->qname->toDNSString();
856 fwrite(out.c_str(), 1, out.size(), d_fp);
857 fwrite((void*)&dq->qtype, 1, 2, d_fp);
858 }
859 else {
860 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);
861 }
808c5ef7 862 }
863 return Action::None;
864 }
865 string toString() const override
866 {
18029431
RG
867 if (!d_fname.empty()) {
868 return "log to " + d_fname;
869 }
808c5ef7 870 return "log";
871 }
872private:
873 string d_fname;
8d06661a 874 FILE* d_fp{0};
18029431 875 bool d_binary{true};
808c5ef7 876};
877
878
f39b7598
RG
879class DisableValidationAction : public DNSAction
880{
881public:
497a6e3a 882 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
f39b7598 883 {
497a6e3a 884 dq->dh->cd = true;
1a2a4e68 885 return Action::None;
f39b7598
RG
886 }
887 string toString() const override
888 {
889 return "set cd=1";
890 }
891};
886e2cf2
RG
892
893class SkipCacheAction : public DNSAction
894{
895public:
896 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
897 {
898 dq->skipCache = true;
899 return Action::None;
900 }
901 string toString() const override
902 {
903 return "skip cache";
904 }
905};
d8c19b98
RG
906
907class RemoteLogAction : public DNSAction, public boost::noncopyable
908{
909public:
910 RemoteLogAction(std::shared_ptr<RemoteLogger> logger): d_logger(logger)
911 {
912 }
913 DNSAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
914 {
ec469dd7 915#ifdef HAVE_PROTOBUF
d9d3f9c1 916 DNSDistProtoBufMessage message(DNSDistProtoBufMessage::Query, *dq);
ec469dd7 917 std::string data;
d9d3f9c1 918 message.serialize(data);
ec469dd7
RG
919 d_logger->queueData(data);
920#endif /* HAVE_PROTOBUF */
d8c19b98
RG
921 return Action::None;
922 }
923 string toString() const override
924 {
925 return "remote log to " + d_logger->toString();
926 }
927private:
928 std::shared_ptr<RemoteLogger> d_logger;
929};
930
8146444b 931class RemoteLogResponseAction : public DNSResponseAction, public boost::noncopyable
d8c19b98
RG
932{
933public:
934 RemoteLogResponseAction(std::shared_ptr<RemoteLogger> logger): d_logger(logger)
935 {
936 }
8146444b 937 DNSResponseAction::Action operator()(DNSQuestion* dq, string* ruleresult) const override
d8c19b98 938 {
ec469dd7 939#ifdef HAVE_PROTOBUF
d9d3f9c1 940 DNSDistProtoBufMessage message(DNSDistProtoBufMessage::Response, *dq);
ec469dd7 941 std::string data;
d9d3f9c1 942 message.serialize(data);
ec469dd7
RG
943 d_logger->queueData(data);
944#endif /* HAVE_PROTOBUF */
d8c19b98
RG
945 return Action::None;
946 }
947 string toString() const override
948 {
949 return "remote log response to " + d_logger->toString();
950 }
951private:
952 std::shared_ptr<RemoteLogger> d_logger;
953};