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