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

PowerDNS / pdns / 9448225702

10 Jun 2024 12:22PM UTC coverage: 62.801% (-1.8%) from 64.61%
9448225702

Pull #14307

github

web-flow
Merge ae0a8bb06 into b1d2ec1c5
Pull Request #14307: Update repo test script.

28487 of 74902 branches covered (38.03%)

Branch coverage included in aggregate %.

98325 of 127025 relevant lines covered (77.41%)

4617608.99 hits per line

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

60.81
/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;
265✔
19

20
void BaseLua4::loadFile(const std::string& fname)
21
{
119✔
22
  std::ifstream ifs(fname);
119✔
23
  if (!ifs) {
119!
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);
119✔
31
};
119✔
32

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

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

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

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

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

64
  // DNSName
65
  d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); });
265✔
66
  d_lw->registerFunction("__lt", &DNSName::operator<);
265✔
67
  d_lw->registerFunction("canonCompare", &DNSName::canonCompare);
265✔
68
  d_lw->registerFunction("makeRelative", &DNSName::makeRelative);
265✔
69
  d_lw->registerFunction("isPartOf", &DNSName::isPartOf);
265✔
70
  d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels);
265✔
71
  d_lw->registerFunction<unsigned int(DNSName::*)()>("countLabels", [](const DNSName& name) { return name.countLabels(); });
265✔
72
  d_lw->registerFunction<size_t(DNSName::*)()>("wireLength", [](const DNSName& name) { return name.wirelength(); });
265✔
73
  d_lw->registerFunction<size_t(DNSName::*)()>("wirelength", [](const DNSName& name) { return name.wirelength(); });
265✔
74
  d_lw->registerFunction<bool(DNSName::*)(const std::string&)>("equal", [](const DNSName& lhs, const std::string& rhs) { return lhs==DNSName(rhs); });
265✔
75
  d_lw->registerEqFunction(&DNSName::operator==);
265✔
76
  d_lw->registerToStringFunction<string(DNSName::*)()>([](const DNSName&dn ) { return dn.toString(); });
265✔
77
  d_lw->registerFunction<string(DNSName::*)()>("toString", [](const DNSName&dn ) { return dn.toString(); });
265✔
78
  d_lw->registerFunction<string(DNSName::*)()>("toStringNoDot", [](const DNSName&dn ) { return dn.toStringNoDot(); });
265✔
79
  d_lw->registerFunction<bool(DNSName::*)()>("chopOff", [](DNSName&dn ) { return dn.chopOff(); });
265✔
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){
265✔
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==);
265✔
95
  d_lw->registerFunction("__lt", &DNSResourceRecord::operator<);
265✔
96
  d_lw->registerToStringFunction<string(DNSResourceRecord::*)()>([](const DNSResourceRecord& rec) { return rec.getZoneRepresentation(); });
265✔
97
  d_lw->registerFunction<string(DNSResourceRecord::*)()>("toString", [](const DNSResourceRecord& rec) { return rec.getZoneRepresentation();} );
265✔
98
  d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("qname", [](DNSResourceRecord& rec) { return rec.qname; });
265✔
99
  d_lw->registerFunction<DNSName(DNSResourceRecord::*)()>("wildcardName", [](DNSResourceRecord& rec) { return rec.wildcardname; });
265✔
100
  d_lw->registerFunction<string(DNSResourceRecord::*)()>("content", [](DNSResourceRecord& rec) { return rec.content; });
265✔
101
  d_lw->registerFunction<time_t(DNSResourceRecord::*)()>("lastModified", [](DNSResourceRecord& rec) { return rec.last_modified; });
265✔
102
  d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("ttl", [](DNSResourceRecord& rec) { return rec.ttl; });
265✔
103
  d_lw->registerFunction<uint32_t(DNSResourceRecord::*)()>("signttl", [](DNSResourceRecord& rec) { return rec.signttl; });
265✔
104
  d_lw->registerFunction<int(DNSResourceRecord::*)()>("domainId", [](DNSResourceRecord& rec) { return rec.domain_id; });
265✔
105
  d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qtype", [](DNSResourceRecord& rec) { return rec.qtype.getCode(); });
265✔
106
  d_lw->registerFunction<uint16_t(DNSResourceRecord::*)()>("qclass", [](DNSResourceRecord& rec) { return rec.qclass; });
265✔
107
  d_lw->registerFunction<uint8_t(DNSResourceRecord::*)()>("scopeMask", [](DNSResourceRecord& rec) { return rec.scopeMask; });
265✔
108
  d_lw->registerFunction<bool(DNSResourceRecord::*)()>("auth", [](DNSResourceRecord& rec) { return rec.auth; });
265✔
109
  d_lw->registerFunction<bool(DNSResourceRecord::*)()>("disabled", [](DNSResourceRecord& rec) { return rec.disabled; });
265✔
110

111
  // ComboAddress
112
  d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv4", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET; });
265✔
113
  d_lw->registerFunction<bool(ComboAddress::*)()>("isIPv6", [](const ComboAddress& ca) { return ca.sin4.sin_family == AF_INET6; });
265✔
114
  d_lw->registerFunction<uint16_t(ComboAddress::*)()>("getPort", [](const ComboAddress& ca) { return ntohs(ca.sin4.sin_port); } );
265✔
115
  d_lw->registerFunction<bool(ComboAddress::*)()>("isMappedIPv4", [](const ComboAddress& ca) { return ca.isMappedIPv4(); });
265✔
116
  d_lw->registerFunction<ComboAddress(ComboAddress::*)()>("mapToIPv4", [](const ComboAddress& ca) { return ca.mapToIPv4(); });
265✔
117
  d_lw->registerFunction<void(ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& ca, unsigned int bits) { ca.truncate(bits); });
265✔
118
  d_lw->registerFunction<string(ComboAddress::*)()>("toString", [](const ComboAddress& ca) { return ca.toString(); });
265✔
119
  d_lw->registerToStringFunction<string(ComboAddress::*)()>([](const ComboAddress& ca) { return ca.toString(); });
265✔
120
  d_lw->registerFunction<string(ComboAddress::*)()>("toStringWithPort", [](const ComboAddress& ca) { return ca.toStringWithPort(); });
265✔
121
  d_lw->registerFunction<string(ComboAddress::*)()>("getRaw", [](const ComboAddress& ca) {
265✔
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); });
265✔
130
  d_lw->writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) {
265✔
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;
265✔
154
  d_lw->registerFunction<bool(ComboAddress::*)(const ComboAddress&)>("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); });
265✔
155

156
  // cas_t
157
  d_lw->writeFunction("newCAS", []{ return cas_t(); });
265✔
158
  d_lw->registerFunction<void(cas_t::*)(boost::variant<string,ComboAddress, vector<pair<unsigned int,string> > >)>("add",
265✔
159
    [](cas_t& cas, const boost::variant<string,ComboAddress,vector<pair<unsigned int,string> > >& in)
265✔
160
    {
265✔
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; });
265✔
178

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

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

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

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

211
    return nmg;
7✔
212
  });
7✔
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); });
265✔
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); } });
265!
216
  d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
265✔
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; });
265✔
220
  d_lw->registerMember("name", &DNSRecord::d_name);
265✔
221
  d_lw->registerMember("type", &DNSRecord::d_type);
265✔
222
  d_lw->registerMember("ttl", &DNSRecord::d_ttl);
265✔
223
  d_lw->registerMember("place", &DNSRecord::d_place);
265✔
224
  d_lw->registerFunction<string(DNSRecord::*)()>("getContent", [](const DNSRecord& dr) { return dr.getContent()->getZoneRepresentation(); });
265✔
225
  d_lw->registerFunction<boost::optional<ComboAddress>(DNSRecord::*)()>("getCA", [](const DNSRecord& dr) {
265✔
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))); });
265✔
235

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

245
  // certain constants
246

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

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

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

280
  for(const auto& n : QType::names)
265✔
281
    d_pd.push_back({n.first, n.second});
16,677✔
282

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

286
  postPrepareContext();
265✔
287

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

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

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

298
BaseLua4::~BaseLua4() = default;
265✔
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