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