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