• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 9773443469

03 Jul 2024 07:11AM UTC coverage: 63.009% (-1.5%) from 64.521%
9773443469

Pull #14327

github

web-flow
Merge 0ace84568 into 1e12511dd
Pull Request #14327: dnsdist: add support for a callback when a new tickets key is added

12939 of 27302 branches covered (47.39%)

Branch coverage included in aggregate %.

41791 of 59559 relevant lines covered (70.17%)

5193036.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.24
/pdns/lua-base4.cc
1
#include <cassert>
2
#include <fstream>
3
#include <unordered_set>
4
#include <unordered_map>
5
#include <typeinfo>
6
#include "logger.hh"
7
#include "logging.hh"
8
#include "iputils.hh"
9
#include "dnsname.hh"
10
#include "dnsparser.hh"
11
#include "dnspacket.hh"
12
#include "namespaces.hh"
13
#include "ednssubnet.hh"
14
#include "lua-base4.hh"
15
#include "ext/luawrapper/include/LuaContext.hpp"
16
#include "dns_random.hh"
17

18
BaseLua4::BaseLua4() = default;
347✔
19

20
void BaseLua4::loadFile(const std::string& fname)
21
{
344✔
22
  std::ifstream ifs(fname);
344✔
23
  if (!ifs) {
344!
24
    auto ret = errno;
×
25
    auto msg = stringerror(ret);
×
26
    SLOG(g_log << Logger::Error << "Unable to read configuration file from '" << fname << "': " << msg << endl,
×
27
         g_slog->withName("lua")->error(Logr::Error, ret, "Unable to read configuration file", "file", Logging::Loggable(fname), "msg", Logging::Loggable(msg)));
×
28
    throw std::runtime_error(msg);
×
29
  }
×
30
  loadStream(ifs);
344✔
31
};
344✔
32

33
void BaseLua4::loadString(const std::string &script) {
2✔
34
  std::istringstream iss(script);
2✔
35
  loadStream(iss);
2✔
36
};
2✔
37

38
//  By default no features
39
void BaseLua4::getFeatures(Features &) { }
368✔
40

41
void BaseLua4::prepareContext() {
368✔
42
  d_lw = std::make_unique<LuaContext>();
368✔
43

44
  // lua features available
45
  Features features;
368✔
46
  getFeatures(features);
368✔
47
  d_lw->writeVariable("pdns_features", features);
368✔
48

49
  // dnsheader
50
  d_lw->registerFunction<int(dnsheader::*)()>("getID", [](dnsheader& dh) { return ntohs(dh.id); });
368✔
51
  d_lw->registerFunction<bool(dnsheader::*)()>("getCD", [](dnsheader& dh) { return dh.cd; });
368✔
52
  d_lw->registerFunction<bool(dnsheader::*)()>("getTC", [](dnsheader& dh) { return dh.tc; });
368✔
53
  d_lw->registerFunction<bool(dnsheader::*)()>("getRA", [](dnsheader& dh) { return dh.ra; });
368✔
54
  d_lw->registerFunction<bool(dnsheader::*)()>("getAD", [](dnsheader& dh) { return dh.ad; });
368✔
55
  d_lw->registerFunction<bool(dnsheader::*)()>("getAA", [](dnsheader& dh) { return dh.aa; });
368✔
56
  d_lw->registerFunction<bool(dnsheader::*)()>("getRD", [](dnsheader& dh) { return dh.rd; });
368✔
57
  d_lw->registerFunction<int(dnsheader::*)()>("getRCODE", [](dnsheader& dh) { return dh.rcode; });
368✔
58
  d_lw->registerFunction<int(dnsheader::*)()>("getOPCODE", [](dnsheader& dh) { return dh.opcode; });
368✔
59
  d_lw->registerFunction<int(dnsheader::*)()>("getQDCOUNT", [](dnsheader& dh) { return ntohs(dh.qdcount); });
368✔
60
  d_lw->registerFunction<int(dnsheader::*)()>("getANCOUNT", [](dnsheader& dh) { return ntohs(dh.ancount); });
368✔
61
  d_lw->registerFunction<int(dnsheader::*)()>("getNSCOUNT", [](dnsheader& dh) { return ntohs(dh.nscount); });
368✔
62
  d_lw->registerFunction<int(dnsheader::*)()>("getARCOUNT", [](dnsheader& dh) { return ntohs(dh.arcount); });
368✔
63

64
  // DNSName
65
  d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); });
68,695✔
66
  d_lw->registerFunction("__lt", &DNSName::operator<);
368✔
67
  d_lw->registerFunction("canonCompare", &DNSName::canonCompare);
368✔
68
  d_lw->registerFunction("makeRelative", &DNSName::makeRelative);
368✔
69
  d_lw->registerFunction("isPartOf", &DNSName::isPartOf);
368✔
70
  d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels);
368✔
71
  d_lw->registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
368✔
72
  d_lw->registerFunction<size_t(DNSName::*)()>("wireLength", [](const DNSName& name) { return name.wirelength(); });
368✔
73
  d_lw->registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
368✔
74
  d_lw->registerFunction<bool(DNSName::*)(const std::string&)>("equal", [](const DNSName& lhs, const std::string& rhs) { return lhs==DNSName(rhs); });
368✔
75
  d_lw->registerEqFunction(&DNSName::operator==);
368✔
76
  d_lw->registerToStringFunction<string(DNSName::*)()>([](const DNSName&dn ) { return dn.toString(); });
368✔
77
  d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
368✔
78
  d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); });
368✔
79
  d_lw->registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
368✔
80

81
  // DNSResourceRecord
82
  d_lw->writeFunction("newDRR", [](const DNSName& qname, const string& qtype, const unsigned int ttl, const string& content, boost::optional<int> domain_id, boost::optional<int> auth){
368✔
83
    auto drr = DNSResourceRecord();
×
84
    drr.qname = qname;
×
85
    drr.qtype = qtype;
×
86
    drr.ttl = ttl;
×
87
    drr.setContent(content);
×
88
    if (domain_id)
×
89
      drr.domain_id = *domain_id;
×
90
    if (auth)
×
91
      drr.auth = *auth;
×
92
     return drr;
×
93
  });
×
94
  d_lw->registerEqFunction(&DNSResourceRecord::operator==);
368✔
95
  d_lw->registerFunction("__lt", &DNSResourceRecord::operator<);
368✔
96
  d_lw->registerToStringFunction<string(DNSResourceRecord::*)()>([](const DNSResourceRecord& rec) { return rec.getZoneRepresentation(); });
368✔
97
  d_lw->registerFunction<string(DNSResourceRecord::*)()>("toString", [](const DNSResourceRecord& rec) { return rec.getZoneRepresentation();} );
368✔
98
  d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("qname", [](DNSResourceRecord& rec) { return rec.qname; });
368✔
99
  d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("wildcardName", [](DNSResourceRecord& rec) { return rec.wildcardname; });
368✔
100
  d_lw->registerFunction<string(DNSResourceRecord::*)()>("content", [](DNSResourceRecord& rec) { return rec.content; });
368✔
101
  d_lw->registerFunction<time_t(DNSResourceRecord::*)()>("lastModified", [](DNSResourceRecord& rec) { return rec.last_modified; });
368✔
102
  d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("ttl", [](DNSResourceRecord& rec) { return rec.ttl; });
368✔
103
  d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("signttl", [](DNSResourceRecord& rec) { return rec.signttl; });
368✔
104
  d_lw->registerFunction<int(DNSResourceRecord::*)()>("domainId", [](DNSResourceRecord& rec) { return rec.domain_id; });
368✔
105
  d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qtype", [](DNSResourceRecord& rec) { return rec.qtype.getCode(); });
368✔
106
  d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qclass", [](DNSResourceRecord& rec) { return rec.qclass; });
368✔
107
  d_lw->registerFunction<uint8_t(DNSResourceRecord::*)()>("scopeMask", [](DNSResourceRecord& rec) { return rec.scopeMask; });
368✔
108
  d_lw->registerFunction<bool(DNSResourceRecord::*)()>("auth", [](DNSResourceRecord& rec) { return rec.auth; });
368✔
109
  d_lw->registerFunction<bool(DNSResourceRecord::*)()>("disabled", [](DNSResourceRecord& rec) { return rec.disabled; });
368✔
110

111
  // ComboAddress
112
  d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
368✔
113
  d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
368✔
114
  d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
368✔
115
  d_lw->registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
368✔
116
  d_lw->registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
368✔
117
  d_lw->registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
368✔
118
  d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
368✔
119
  d_lw->registerToStringFunction<string(ComboAddress::*)()>([](const ComboAddress& ca) { return ca.toString(); });
68,440✔
120
  d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
368✔
121
  d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) {
368✔
122
      if(ca.sin4.sin_family == AF_INET) {
×
123
        auto t=ca.sin4.sin_addr.s_addr; return string((const char*)&t, 4);
×
124
      }
×
125
      else
×
126
        return string((const char*)&ca.sin6.sin6_addr.s6_addr, 16);
×
127
    } );
×
128

129
  d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); });
368✔
130
  d_lw->writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) {
368✔
131
                                        if (raw.size() == 4) {
×
132
                                          struct sockaddr_in sin4;
×
133
                                          memset(&sin4, 0, sizeof(sin4));
×
134
                                          sin4.sin_family = AF_INET;
×
135
                                          memcpy(&sin4.sin_addr.s_addr, raw.c_str(), raw.size());
×
136
                                          if (port) {
×
137
                                            sin4.sin_port = htons(*port);
×
138
                                          }
×
139
                                          return ComboAddress(&sin4);
×
140
                                        }
×
141
                                        else if (raw.size() == 16) {
×
142
                                          struct sockaddr_in6 sin6;
×
143
                                          memset(&sin6, 0, sizeof(sin6));
×
144
                                          sin6.sin6_family = AF_INET6;
×
145
                                          memcpy(&sin6.sin6_addr.s6_addr, raw.c_str(), raw.size());
×
146
                                          if (port) {
×
147
                                            sin6.sin6_port = htons(*port);
×
148
                                          }
×
149
                                          return ComboAddress(&sin6);
×
150
                                        }
×
151
                                        return ComboAddress();
×
152
                                      });
×
153
  typedef std::unordered_set<ComboAddress,ComboAddress::addressOnlyHash,ComboAddress::addressOnlyEqual> cas_t;
368✔
154
  d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); });
368✔
155

156
  // cas_t
157
  d_lw->writeFunction("newCAS", []{ return cas_t(); });
368✔
158
  d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>("add",
368✔
159
    [](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in)
368✔
160
    {
368✔
161
      try {
×
162
      if(auto s = boost::get<string>(&in)) {
×
163
        cas.insert(ComboAddress(*s));
×
164
      }
×
165
      else if(auto v = boost::get<vector<pair<unsigned int, string> > >(&in)) {
×
166
        for(const auto& str : *v)
×
167
          cas.insert(ComboAddress(str.second));
×
168
      }
×
169
      else
×
170
        cas.insert(boost::get<ComboAddress>(in));
×
171
      }
×
172
      catch(std::exception& e) {
×
173
        SLOG(g_log <<Logger::Error<<e.what()<<endl,
×
174
             g_slog->withName("lua")->error(Logr::Error, e.what(), "Exception in newCAS", "exception", Logging::Loggable("std::exception")));
×
175
      }
×
176
    });
×
177
  d_lw->registerFunction<bool(cas_t::*)(const ComboAddress&)>("check",[](const cas_t& cas, const ComboAddress&ca) { return cas.count(ca)>0; });
368✔
178

179
  // QType
180
  d_lw->writeFunction("newQType", [](const string& s) { QType q; q = s; return q; });
414✔
181
  d_lw->registerFunction("getCode", &QType::getCode);
368✔
182
  d_lw->registerFunction("getName", &QType::toString);
368✔
183
  d_lw->registerEqFunction<bool(QType::*)(const QType&)>([](const QType& a, const QType& b){ return a == b;}); // operator overloading confuses LuaContext
368✔
184
  d_lw->registerToStringFunction(&QType::toString);
368✔
185

186
  // Netmask
187
  d_lw->writeFunction("newNetmask", [](const string& s) { return Netmask(s); });
368✔
188
  d_lw->registerFunction<ComboAddress(Netmask::*)()>("getNetwork", [](const Netmask& nm) { return nm.getNetwork(); } ); // const reference makes this necessary
368✔
189
  d_lw->registerFunction<ComboAddress(Netmask::*)()>("getMaskedNetwork", [](const Netmask& nm) { return nm.getMaskedNetwork(); } );
368✔
190
  d_lw->registerFunction("isIpv4", &Netmask::isIPv4);
368✔
191
  d_lw->registerFunction("isIPv4", &Netmask::isIPv4);
368✔
192
  d_lw->registerFunction("isIpv6", &Netmask::isIPv6);
368✔
193
  d_lw->registerFunction("isIPv6", &Netmask::isIPv6);
368✔
194
  d_lw->registerFunction("getBits", &Netmask::getBits);
368✔
195
  d_lw->registerFunction("toString", &Netmask::toString);
368✔
196
  d_lw->registerFunction("empty", &Netmask::empty);
368✔
197
  d_lw->registerFunction("match", (bool (Netmask::*)(const string&) const)&Netmask::match);
368✔
198
  d_lw->registerEqFunction(&Netmask::operator==);
368✔
199
  d_lw->registerToStringFunction(&Netmask::toString);
368✔
200

201
  // NetmaskGroup
202
  d_lw->writeFunction("newNMG", [](boost::optional<vector<pair<unsigned int, std::string>>> masks) {
368✔
203
    auto nmg = NetmaskGroup();
×
204

205
    if (masks) {
×
206
      for(const auto& mask: *masks) {
×
207
        nmg.addMask(mask.second);
×
208
      }
×
209
    }
×
210

211
    return nmg;
×
212
  });
×
213
  // d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
214
  d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask) { nmg.addMask(mask); });
368✔
215
  d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>("addMasks", [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks) { for(const auto& mask: masks) { nmg.addMask(mask.second); } });
368!
216
  d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
368✔
217

218
  // DNSRecord
219
  d_lw->writeFunction("newDR", [](const DNSName& name, const std::string& type, unsigned int ttl, const std::string& content, int place) { QType qtype; qtype = type; auto dr = DNSRecord(); dr.d_name = name; dr.d_type = qtype.getCode(); dr.d_ttl = ttl; dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, QClass::IN, content))); dr.d_place = static_cast<DNSResourceRecord::Place>(place); return dr; });
368✔
220
  d_lw->registerMember("name", &DNSRecord::d_name);
368✔
221
  d_lw->registerMember("type", &DNSRecord::d_type);
368✔
222
  d_lw->registerMember("ttl", &DNSRecord::d_ttl);
368✔
223
  d_lw->registerMember("place", &DNSRecord::d_place);
368✔
224
  d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.getContent()->getZoneRepresentation(); });
368✔
225
  d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
368✔
226
      boost::optional<ComboAddress> ret;
×
227

228
      if(auto arec = getRR<ARecordContent>(dr))
×
229
        ret=arec->getCA(53);
×
230
      else if(auto aaaarec = getRR<AAAARecordContent>(dr))
×
231
        ret=aaaarec->getCA(53);
×
232
      return ret;
×
233
    });
×
234
  d_lw->registerFunction<void (DNSRecord::*)(const std::string&)>("changeContent", [](DNSRecord& dr, const std::string& newContent) { dr.setContent(shared_ptr<DNSRecordContent>(DNSRecordContent::make(dr.d_type, 1, newContent))); });
368✔
235

236
  // pdnsload
237
  d_lw->writeFunction("pdnslog", [](const std::string& msg, boost::optional<int> loglevel) {
368✔
238
    SLOG(g_log << (Logger::Urgency)loglevel.get_value_or(Logger::Warning) << msg<<endl,
×
239
         g_slog->withName("lua")->info(static_cast<Logr::Priority>(loglevel.get_value_or(Logr::Warning)), msg));
×
240
  });
×
241
  d_lw->writeFunction("pdnsrandom", [](boost::optional<uint32_t> maximum) {
368✔
242
    return maximum ? dns_random(*maximum) : dns_random_uint32();
×
243
  });
×
244

245
  // certain constants
246

247
  vector<pair<string, int> > rcodes = {{"NOERROR",  RCode::NoError  },
368✔
248
                                       {"FORMERR",  RCode::FormErr  },
368✔
249
                                       {"SERVFAIL", RCode::ServFail },
368✔
250
                                       {"NXDOMAIN", RCode::NXDomain },
368✔
251
                                       {"NOTIMP",   RCode::NotImp   },
368✔
252
                                       {"REFUSED",  RCode::Refused  },
368✔
253
                                       {"YXDOMAIN", RCode::YXDomain },
368✔
254
                                       {"YXRRSET",  RCode::YXRRSet  },
368✔
255
                                       {"NXRRSET",  RCode::NXRRSet  },
368✔
256
                                       {"NOTAUTH",  RCode::NotAuth  },
368✔
257
                                       {"NOTZONE",  RCode::NotZone  },
368✔
258
                                       {"DROP",    -2               }}; // To give backport-incompatibility warning
368✔
259
  for(const auto& rcode : rcodes)
368✔
260
    d_pd.push_back({rcode.first, rcode.second});
4,416✔
261

262
  d_pd.push_back({"place", in_t{
368✔
263
    {"QUESTION", 0},
368✔
264
    {"ANSWER", 1},
368✔
265
    {"AUTHORITY", 2},
368✔
266
    {"ADDITIONAL", 3}
368✔
267
  }});
368✔
268

269
  d_pd.push_back({"loglevels", in_t{
368✔
270
        {"Alert", LOG_ALERT},
368✔
271
        {"Critical", LOG_CRIT},
368✔
272
        {"Debug", LOG_DEBUG},
368✔
273
        {"Emergency", LOG_EMERG},
368✔
274
        {"Info", LOG_INFO},
368✔
275
        {"Notice", LOG_NOTICE},
368✔
276
        {"Warning", LOG_WARNING},
368✔
277
        {"Error", LOG_ERR}
368✔
278
          }});
368✔
279

280
  for(const auto& n : QType::names)
368✔
281
    d_pd.push_back({n.first, n.second});
23,919✔
282

283
  d_lw->registerMember("tv_sec", &timeval::tv_sec);
368✔
284
  d_lw->registerMember("tv_usec", &timeval::tv_usec);
368✔
285

286
  postPrepareContext();
368✔
287

288
  // so we can let postprepare do changes to this
289
  d_lw->writeVariable("pdns", d_pd);
368✔
290
}
368✔
291

292
void BaseLua4::loadStream(std::istream &is) {
347✔
293
  d_lw->executeCode(is);
347✔
294

295
  postLoad();
347✔
296
}
347✔
297

298
BaseLua4::~BaseLua4() = default;
19✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc