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

PowerDNS / pdns / 19741624072

27 Nov 2025 03:45PM UTC coverage: 73.086% (+0.02%) from 73.065%
19741624072

Pull #16570

github

web-flow
Merge 08a2cdb1d into f94a3f63f
Pull Request #16570: rec: rewrite all unwrap calls in web.rs

38523 of 63408 branches covered (60.75%)

Branch coverage included in aggregate %.

128044 of 164496 relevant lines covered (77.84%)

6531485.83 hits per line

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

64.38
/pdns/dnsdistdist/dnsdist-lua-bindings.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 "bpf-filter.hh"
23
#include "config.h"
24
#include "dnsdist.hh"
25
#include "dnsdist-async.hh"
26
#include "dnsdist-dynblocks.hh"
27
#include "dnsdist-dynbpf.hh"
28
#include "dnsdist-frontend.hh"
29
#include "dnsdist-lua.hh"
30
#include "dnsdist-resolver.hh"
31
#include "dnsdist-svc.hh"
32
#include "dnsdist-xsk.hh"
33

34
#include "dolog.hh"
35
#include "xsk.hh"
36

37
void setupLuaBindingsLogging(LuaContext& luaCtx)
38
{
827✔
39
  luaCtx.writeFunction("vinfolog", [](const string& arg) {
827✔
40
    vinfolog("%s", arg);
×
41
  });
×
42
  luaCtx.writeFunction("infolog", [](const string& arg) {
827✔
43
    infolog("%s", arg);
×
44
  });
×
45
  luaCtx.writeFunction("errlog", [](const string& arg) {
827✔
46
    errlog("%s", arg);
×
47
  });
×
48
  luaCtx.writeFunction("warnlog", [](const string& arg) {
827✔
49
    warnlog("%s", arg);
×
50
  });
×
51
  luaCtx.writeFunction("show", [](const string& arg) {
827✔
52
    g_outputBuffer += arg;
×
53
    g_outputBuffer += "\n";
×
54
  });
×
55
}
827✔
56

57
// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
58
void setupLuaBindings(LuaContext& luaCtx, bool client, bool configCheck)
59
{
818✔
60
  /* Exceptions */
61
  luaCtx.registerFunction<string (std::exception_ptr::*)() const>("__tostring", [](const std::exception_ptr& eptr) -> std::string {
818✔
62
    try {
×
63
      if (eptr) {
×
64
        std::rethrow_exception(eptr);
×
65
      }
×
66
    }
×
67
    catch (const std::exception& e) {
×
68
      return {e.what()};
×
69
    }
×
70
    catch (const PDNSException& e) {
×
71
      return e.reason;
×
72
    }
×
73
    catch (...) {
×
74
      return {"Unknown exception"};
×
75
    }
×
76
    return {"No exception"};
×
77
  });
×
78
#ifndef DISABLE_POLICIES_BINDINGS
818✔
79
  /* ServerPolicy */
80
  luaCtx.writeFunction("newServerPolicy", [](const string& name, const ServerPolicy::policyfunc_t& policy) { return std::make_shared<ServerPolicy>(name, policy, true); });
818✔
81
  luaCtx.registerMember("name", &ServerPolicy::d_name);
818✔
82
  luaCtx.registerMember("policy", &ServerPolicy::d_policy);
818✔
83
  luaCtx.registerMember("ffipolicy", &ServerPolicy::d_ffipolicy);
818✔
84
  luaCtx.registerMember("isLua", &ServerPolicy::d_isLua);
818✔
85
  luaCtx.registerMember("isFFI", &ServerPolicy::d_isFFI);
818✔
86
  luaCtx.registerMember("isPerThread", &ServerPolicy::d_isPerThread);
818✔
87
  luaCtx.registerFunction("toString", &ServerPolicy::toString);
818✔
88
  luaCtx.registerFunction("__tostring", &ServerPolicy::toString);
818✔
89

90
  for (const auto& policy : dnsdist::lbpolicies::getBuiltInPolicies()) {
5,726✔
91
    luaCtx.writeVariable(policy->d_name, policy);
5,726✔
92
  }
5,726✔
93

94
#endif /* DISABLE_POLICIES_BINDINGS */
818✔
95

96
  /* ServerPool */
97
  luaCtx.registerFunction<void (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)(std::shared_ptr<DNSDistPacketCache>)>("setCache", [](const std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool, std::shared_ptr<DNSDistPacketCache> cache) {
818✔
98
    if (pool) {
122!
99
      dnsdist::configuration::updateRuntimeConfiguration([&pool, &cache](dnsdist::configuration::RuntimeConfiguration& config) {
122✔
100
        auto poolIt = config.d_pools.find(pool->poolName);
122✔
101
        if (poolIt == config.d_pools.end()) {
122!
102
          /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
103
          return;
×
104
        }
×
105
        poolIt->second.packetCache = std::move(cache);
122✔
106
      });
122✔
107
    }
122✔
108
  });
122✔
109
  luaCtx.registerFunction<std::shared_ptr<DNSDistPacketCache> (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)() const>("getCache", [](const std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool) {
818✔
110
    std::shared_ptr<DNSDistPacketCache> cache;
23✔
111
    if (pool) {
23!
112
      dnsdist::configuration::updateRuntimeConfiguration([&pool, &cache](dnsdist::configuration::RuntimeConfiguration& config) {
23✔
113
        auto poolIt = config.d_pools.find(pool->poolName);
23✔
114
        /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
115
        if (poolIt != config.d_pools.end()) {
23!
116
          cache = poolIt->second.packetCache;
23✔
117
        }
23✔
118
      });
23✔
119
    }
23✔
120
    return cache;
23✔
121
  });
23✔
122
  luaCtx.registerFunction<void (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)()>("unsetCache", [](const std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool) {
818✔
123
    if (pool) {
2!
124
      dnsdist::configuration::updateRuntimeConfiguration([&pool](dnsdist::configuration::RuntimeConfiguration& config) {
2✔
125
        auto poolIt = config.d_pools.find(pool->poolName);
2✔
126
        if (poolIt == config.d_pools.end()) {
2!
127
          /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
128
          return;
×
129
        }
×
130
        poolIt->second.packetCache.reset();
2✔
131
      });
2✔
132
    }
2✔
133
  });
2✔
134
  luaCtx.registerFunction<bool (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)() const>("getECS", [](const std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool) {
818✔
135
    bool ecs = false;
6✔
136
    if (pool) {
6!
137
      dnsdist::configuration::updateRuntimeConfiguration([&pool, &ecs](dnsdist::configuration::RuntimeConfiguration& config) {
6✔
138
        auto poolIt = config.d_pools.find(pool->poolName);
6✔
139
        /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
140
        if (poolIt != config.d_pools.end()) {
6!
141
          ecs = poolIt->second.getECS();
6✔
142
        }
6✔
143
      });
6✔
144
    }
6✔
145
    return ecs;
6✔
146
  });
6✔
147
  luaCtx.registerFunction<void (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)(bool ecs)>("setECS", [](std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool, bool ecs) {
818✔
148
    if (pool) {
6!
149
      dnsdist::configuration::updateRuntimeConfiguration([&pool, ecs](dnsdist::configuration::RuntimeConfiguration& config) {
6✔
150
        auto poolIt = config.d_pools.find(pool->poolName);
6✔
151
        if (poolIt == config.d_pools.end()) {
6!
152
          /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
153
          return;
×
154
        }
×
155
        poolIt->second.setECS(ecs);
6✔
156
      });
6✔
157
    }
6✔
158
  });
6✔
159
  luaCtx.registerFunction<bool (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)() const>("getZeroScope", [](const std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool) {
818✔
160
    bool zeroScope = false;
10✔
161
    if (pool) {
10!
162
      dnsdist::configuration::updateRuntimeConfiguration([&pool, &zeroScope](dnsdist::configuration::RuntimeConfiguration& config) {
10✔
163
        auto poolIt = config.d_pools.find(pool->poolName);
10✔
164
        /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
165
        if (poolIt != config.d_pools.end()) {
10!
166
          zeroScope = poolIt->second.getZeroScope();
10✔
167
        }
10✔
168
      });
10✔
169
    }
10✔
170
    return zeroScope;
10✔
171
  });
10✔
172
  luaCtx.registerFunction<void (std::shared_ptr<dnsdist::lua::LuaServerPoolObject>::*)(bool enabled)>("setZeroScope", [](std::shared_ptr<dnsdist::lua::LuaServerPoolObject>& pool, bool enabled) {
818✔
173
    if (pool) {
4!
174
      dnsdist::configuration::updateRuntimeConfiguration([&pool, enabled](dnsdist::configuration::RuntimeConfiguration& config) {
4✔
175
        auto poolIt = config.d_pools.find(pool->poolName);
4✔
176
        if (poolIt == config.d_pools.end()) {
4!
177
          /* this might happen if the Server Pool has been removed in the meantime, let's gracefully ignore it */
178
          return;
×
179
        }
×
180
        poolIt->second.setZeroScope(enabled);
4✔
181
      });
4✔
182
    }
4✔
183
  });
4✔
184

185
#ifndef DISABLE_DOWNSTREAM_BINDINGS
818✔
186
  /* DownstreamState */
187
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(int)>("setQPS", [](std::shared_ptr<DownstreamState>& state, int lim) {
818✔
188
    if (state) {
×
189
      if (lim > 0) {
×
190
        state->d_qpsLimiter = QPSLimiter(lim, lim);
191
      }
192
      else {
193
        state->d_qpsLimiter.reset();
194
      }
195
    }
196
  });
197
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(string)>("addPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
818✔
198
    if (state) {
16!
199
      addServerToPool(pool, state);
16✔
200
      state->d_config.pools.insert(pool);
16✔
201
    }
16✔
202
  });
16✔
203
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(string)>("rmPool", [](const std::shared_ptr<DownstreamState>& state, const string& pool) {
818✔
204
    if (state) {
4!
205
      removeServerFromPool(pool, state);
4✔
206
      state->d_config.pools.erase(pool);
4✔
207
    }
4✔
208
  });
4✔
209
  luaCtx.registerFunction<uint64_t (std::shared_ptr<DownstreamState>::*)() const>("getOutstanding", [](const std::shared_ptr<DownstreamState>& state) -> uint64_t {
818✔
210
    if (state) {
×
211
      return state->outstanding.load();
212
    }
213
    return 0U;
214
  });
215
  luaCtx.registerFunction<uint64_t (std::shared_ptr<DownstreamState>::*)() const>("getDrops", [](const std::shared_ptr<DownstreamState>& state) -> uint64_t {
818✔
216
    if (state) {
×
217
      return state->reuseds.load();
218
    }
219
    return 0U;
220
  });
221
  luaCtx.registerFunction<uint64_t (std::shared_ptr<DownstreamState>::*)() const>("getQueries", [](const std::shared_ptr<DownstreamState>& state) -> uint64_t {
818✔
222
    if (state) {
×
223
      return state->queries.load();
224
    }
225
    return 0U;
226
  });
227
  luaCtx.registerFunction<double (std::shared_ptr<DownstreamState>::*)() const>("getLatency", [](const std::shared_ptr<DownstreamState>& state) -> double {
818✔
228
    if (state) {
×
229
      return state->getRelevantLatencyUsec();
230
    }
231
    return 0.0;
232
  });
233
  luaCtx.registerFunction<bool (std::shared_ptr<DownstreamState>::*)() const>("isUp", [](const std::shared_ptr<DownstreamState>& state) -> bool {
818✔
234
    if (!state) {
30!
235
      return false;
236
    }
237
    return state->isUp();
30✔
238
  });
30✔
239
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)()>("setDown", [](const std::shared_ptr<DownstreamState>& state) {
818✔
240
    if (state) {
30!
241
      state->setDown();
30✔
242
    }
30✔
243
  });
30✔
244
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)()>("setUp", [](const std::shared_ptr<DownstreamState>& state) {
818✔
245
    if (state) {
148!
246
      state->setUp();
148✔
247
    }
148✔
248
  });
148✔
249
  luaCtx.registerFunction<std::string (std::shared_ptr<DownstreamState>::*)() const>("getHealthCheckMode", [](const std::shared_ptr<DownstreamState>& state) -> std::string {
818✔
250
    if (!state) {
7!
251
      return "";
252
    }
253
    if (state->d_config.d_healthCheckMode == DownstreamState::HealthCheckMode::Active) {
7✔
254
      return "active";
5✔
255
    }
5✔
256
    return "lazy";
2✔
257
  });
7✔
258
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(boost::optional<bool> newStatus)>("setAuto", [](std::shared_ptr<DownstreamState>& state, boost::optional<bool> newStatus) {
818✔
259
    if (!state) {
10!
260
      return;
261
    }
262
    if (newStatus) {
10✔
263
      state->setUpStatus(*newStatus);
3✔
264
    }
3✔
265
    state->setAuto();
10✔
266
  });
10✔
267
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(boost::optional<bool> newStatus)>("setActiveAuto", [](std::shared_ptr<DownstreamState>& state, boost::optional<bool> newStatus) {
818✔
268
    if (!state) {
1!
269
      return;
270
    }
271
    if (newStatus) {
1!
272
      state->setUpStatus(*newStatus);
273
    }
274
    state->setActiveAuto();
1✔
275
  });
1✔
276
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(boost::optional<bool> newStatus)>("setLazyAuto", [](std::shared_ptr<DownstreamState>& state, boost::optional<bool> newStatus) {
818✔
277
    if (!state) {
1!
278
      return;
279
    }
280
    if (newStatus) {
1!
281
      state->setUpStatus(*newStatus);
282
    }
283
    state->setLazyAuto();
1✔
284
  });
1✔
285
  luaCtx.registerFunction<void (std::shared_ptr<DownstreamState>::*)(boost::optional<LuaAssociativeTable<boost::variant<size_t>>>)>("setHealthCheckParams", [](std::shared_ptr<DownstreamState>& state, boost::optional<LuaAssociativeTable<boost::variant<size_t>>> vars) {
818✔
286
    if (!state) {
3!
287
      return;
288
    }
289
    size_t value = 0;
3✔
290
    getOptionalValue<size_t>(vars, "maxCheckFailures", value);
3✔
291
    if (value > 0) {
3✔
292
      state->d_config.maxCheckFailures.store(value);
1✔
293
    }
1✔
294
    getOptionalValue<size_t>(vars, "rise", value);
3✔
295
    if (value > 0) {
3✔
296
      state->d_config.minRiseSuccesses.store(value);
1✔
297
    }
1✔
298
    getOptionalValue<size_t>(vars, "checkTimeout", value);
3✔
299
    if (value > 0) {
3✔
300
      state->d_config.checkTimeout.store(value);
2✔
301
    }
2✔
302
    getOptionalValue<size_t>(vars, "checkInterval", value);
3✔
303
    if (value > 0) {
3!
304
      state->d_config.checkInterval.store(value);
3✔
305
    }
3✔
306
  });
3✔
307
  luaCtx.registerFunction<std::string (std::shared_ptr<DownstreamState>::*)() const>("getName", [](const std::shared_ptr<DownstreamState>& state) -> const std::string& {
818✔
308
    static const std::string empty;
309
    if (!state) {
×
310
      return empty;
311
    }
312
    return state->getName();
313
  });
314
  luaCtx.registerFunction<std::string (std::shared_ptr<DownstreamState>::*)() const>("getNameWithAddr", [](const std::shared_ptr<DownstreamState>& state) -> const std::string& {
818✔
315
    static const std::string empty;
101✔
316
    if (!state) {
101!
317
      return empty;
318
    }
319
    return state->getNameWithAddr();
101✔
320
  });
101✔
321
  luaCtx.registerMember<bool(std::shared_ptr<DownstreamState>::*)>(
818✔
322
    "upStatus",
818✔
323
    [](const std::shared_ptr<DownstreamState>& state) -> bool {
818✔
324
      if (!state) {
×
325
        return false;
326
      }
327
      return state->upStatus.load(std::memory_order_relaxed);
328
    },
329
    [](std::shared_ptr<DownstreamState>& state, bool newStatus) {
818✔
330
      if (state) {
×
331
        state->upStatus.store(newStatus);
332
      }
333
    });
334
  luaCtx.registerMember<int(std::shared_ptr<DownstreamState>::*)>(
818✔
335
    "weight",
818✔
336
    [](const std::shared_ptr<DownstreamState>& state) -> int {
818✔
337
      if (!state) {
×
338
        return 0;
339
      }
340
      return state->d_config.d_weight;
341
    },
342
    [](std::shared_ptr<DownstreamState>& state, int newWeight) {
818✔
343
      if (state) {
×
344
        state->setWeight(newWeight);
345
      }
346
    });
347
  luaCtx.registerMember<int(std::shared_ptr<DownstreamState>::*)>(
818✔
348
    "order",
818✔
349
    [](const std::shared_ptr<DownstreamState>& state) -> int {
818✔
350
      if (!state) {
×
351
        return 0;
352
      }
353
      return state->d_config.order;
354
    },
355
    [](std::shared_ptr<DownstreamState>& state, int newOrder) {
818✔
356
      if (state) {
×
357
        state->d_config.order = newOrder;
358
      }
359
    });
360
  luaCtx.registerMember<const std::string(std::shared_ptr<DownstreamState>::*)>(
818✔
361
    "name",
818✔
362
    [](const std::shared_ptr<DownstreamState>& backend) -> std::string {
818✔
363
      if (!backend) {
16!
364
        return "";
365
      }
366
      return backend->getName();
16✔
367
    },
16✔
368
    [](std::shared_ptr<DownstreamState>& backend, const std::string& newName) {
818✔
369
      if (backend) {
×
370
        backend->setName(newName);
371
      }
372
    });
373
  luaCtx.registerFunction<std::string (std::shared_ptr<DownstreamState>::*)() const>("getID", [](const std::shared_ptr<DownstreamState>& state) -> std::string {
818✔
374
    if (!state) {
×
375
      return "";
376
    }
377
    return boost::uuids::to_string(*state->d_config.id);
378
  });
379
#endif /* DISABLE_DOWNSTREAM_BINDINGS */
818✔
380

381
#ifndef DISABLE_DNSHEADER_BINDINGS
818✔
382
  /* dnsheader */
383
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setRD", [](dnsheader& dnsHeader, bool value) {
818✔
384
    dnsHeader.rd = value;
385
  });
386

387
  luaCtx.registerFunction<bool (dnsheader::*)() const>("getRD", [](const dnsheader& dnsHeader) {
818✔
388
    return (bool)dnsHeader.rd;
6✔
389
  });
6✔
390

391
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setRA", [](dnsheader& dnsHeader, bool value) {
818✔
392
    dnsHeader.ra = value;
393
  });
394

395
  luaCtx.registerFunction<bool (dnsheader::*)() const>("getRA", [](const dnsheader& dnsHeader) {
818✔
396
    return (bool)dnsHeader.ra;
397
  });
398

399
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setAD", [](dnsheader& dnsHeader, bool value) {
818✔
400
    dnsHeader.ad = value;
401
  });
402

403
  luaCtx.registerFunction<bool (dnsheader::*)() const>("getAD", [](const dnsheader& dnsHeader) {
818✔
404
    return (bool)dnsHeader.ad;
405
  });
406

407
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setAA", [](dnsheader& dnsHeader, bool value) {
818✔
408
    dnsHeader.aa = value;
4✔
409
  });
4✔
410

411
  luaCtx.registerFunction<bool (dnsheader::*)() const>("getAA", [](const dnsheader& dnsHeader) {
818✔
412
    return (bool)dnsHeader.aa;
413
  });
414

415
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setCD", [](dnsheader& dnsHeader, bool value) {
818✔
416
    dnsHeader.cd = value;
4✔
417
  });
4✔
418

419
  luaCtx.registerFunction<bool (dnsheader::*)() const>("getCD", [](const dnsheader& dnsHeader) {
818✔
420
    return (bool)dnsHeader.cd;
421
  });
422

423
  luaCtx.registerFunction<uint16_t (dnsheader::*)() const>("getID", [](const dnsheader& dnsHeader) {
818✔
424
    return ntohs(dnsHeader.id);
184✔
425
  });
184✔
426

427
  luaCtx.registerFunction<bool (dnsheader::*)() const>("getTC", [](const dnsheader& dnsHeader) {
818✔
428
    return (bool)dnsHeader.tc;
4✔
429
  });
4✔
430

431
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setTC", [](dnsheader& dnsHeader, bool value) {
818✔
432
    dnsHeader.tc = value;
2✔
433
    if (value) {
2!
434
      dnsHeader.ra = dnsHeader.rd; // you'll always need this, otherwise TC=1 gets ignored
2✔
435
    }
2✔
436
  });
2✔
437

438
  luaCtx.registerFunction<void (dnsheader::*)(bool)>("setQR", [](dnsheader& dnsHeader, bool value) {
818✔
439
    dnsHeader.qr = value;
6✔
440
  });
6✔
441
#endif /* DISABLE_DNSHEADER_BINDINGS */
818✔
442

443
#ifndef DISABLE_COMBO_ADDR_BINDINGS
818✔
444
  /* ComboAddress */
445
  luaCtx.writeFunction("newCA", [](const std::string& name) { return ComboAddress(name); });
818✔
446
  luaCtx.writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional<uint16_t> port) {
818✔
447
    if (raw.size() == 4) {
×
448
      sockaddr_in sin4{};
449
      memset(&sin4, 0, sizeof(sin4));
450
      sin4.sin_family = AF_INET;
451
      memcpy(&sin4.sin_addr.s_addr, raw.c_str(), raw.size());
452
      if (port) {
×
453
        sin4.sin_port = htons(*port);
454
      }
455
      return ComboAddress(&sin4);
456
    }
457
    if (raw.size() == 16) {
×
458
      sockaddr_in6 sin6{};
459
      memset(&sin6, 0, sizeof(sin6));
460
      sin6.sin6_family = AF_INET6;
461
      memcpy(&sin6.sin6_addr.s6_addr, raw.c_str(), raw.size());
462
      if (port) {
×
463
        sin6.sin6_port = htons(*port);
464
      }
465
      return ComboAddress(&sin6);
466
    }
467
    return ComboAddress();
468
  });
469
  luaCtx.registerFunction<string (ComboAddress::*)() const>("tostring", [](const ComboAddress& addr) { return addr.toString(); });
818✔
470
  luaCtx.registerFunction<string (ComboAddress::*)() const>("tostringWithPort", [](const ComboAddress& addr) { return addr.toStringWithPort(); });
818✔
471
  luaCtx.registerFunction<string (ComboAddress::*)() const>("__tostring", [](const ComboAddress& addr) { return addr.toString(); });
818✔
472
  luaCtx.registerFunction<string (ComboAddress::*)() const>("toString", [](const ComboAddress& addr) { return addr.toString(); });
818✔
473
  luaCtx.registerFunction<string (ComboAddress::*)() const>("toStringWithPort", [](const ComboAddress& addr) { return addr.toStringWithPort(); });
818✔
474
  luaCtx.registerFunction<string (ComboAddress::*)() const>("getRaw", [](const ComboAddress& addr) { return addr.toByteString(); });
818✔
475
  luaCtx.registerFunction<uint16_t (ComboAddress::*)() const>("getPort", [](const ComboAddress& addr) { return ntohs(addr.sin4.sin_port); });
818✔
476
  luaCtx.registerFunction<void (ComboAddress::*)(unsigned int)>("truncate", [](ComboAddress& addr, unsigned int bits) { addr.truncate(bits); });
818✔
477
  luaCtx.registerFunction<bool (ComboAddress::*)() const>("isIPv4", [](const ComboAddress& addr) { return addr.sin4.sin_family == AF_INET; });
818✔
478
  luaCtx.registerFunction<bool (ComboAddress::*)() const>("isIPv6", [](const ComboAddress& addr) { return addr.sin4.sin_family == AF_INET6; });
818✔
479
  luaCtx.registerFunction<bool (ComboAddress::*)() const>("isMappedIPv4", [](const ComboAddress& addr) { return addr.isMappedIPv4(); });
818✔
480
  luaCtx.registerFunction<ComboAddress (ComboAddress::*)() const>("mapToIPv4", [](const ComboAddress& addr) { return addr.mapToIPv4(); });
818✔
481
#ifndef DISABLE_DYNBLOCKS
818✔
482
  luaCtx.registerFunction<bool (ClientAddressDynamicRules::*)(const ComboAddress&) const>("match", [](const ClientAddressDynamicRules& set, const ComboAddress& addr) { return set.match(addr); });
818✔
483
#endif /* DISABLE_DYNBLOCKS */
818✔
484
#endif /* DISABLE_COMBO_ADDR_BINDINGS */
818✔
485

486
#ifndef DISABLE_DNSNAME_BINDINGS
818✔
487
  /* DNSName */
488
  luaCtx.registerFunction("isPartOf", &DNSName::isPartOf);
818✔
489
  luaCtx.registerFunction<bool (DNSName::*)()>("chopOff", [](DNSName& name) { return name.chopOff(); });
818✔
490
  luaCtx.registerFunction<unsigned int (DNSName::*)() const>("countLabels", [](const DNSName& name) { return name.countLabels(); });
818✔
491
  luaCtx.registerFunction<size_t (DNSName::*)() const>("hash", [](const DNSName& name) { return name.hash(); });
818✔
492
  luaCtx.registerFunction<size_t (DNSName::*)() const>("wirelength", [](const DNSName& name) { return name.wirelength(); });
818✔
493
  luaCtx.registerFunction<string (DNSName::*)() const>("tostring", [](const DNSName& name) { return name.toString(); });
818✔
494
  luaCtx.registerFunction<string (DNSName::*)() const>("toString", [](const DNSName& name) { return name.toString(); });
818✔
495
  luaCtx.registerFunction<string (DNSName::*)() const>("toStringNoDot", [](const DNSName& name) { return name.toStringNoDot(); });
818✔
496
  luaCtx.registerFunction<string (DNSName::*)() const>("__tostring", [](const DNSName& name) { return name.toString(); });
818✔
497
  luaCtx.registerFunction<string (DNSName::*)() const>("toDNSString", [](const DNSName& name) { return name.toDNSString(); });
818✔
498
  luaCtx.registerFunction<DNSName (DNSName::*)(const DNSName&) const>("makeRelative", [](const DNSName& name, const DNSName& relTo) { return name.makeRelative(relTo); });
818✔
499
  luaCtx.writeFunction("newDNSName", [](const std::string& name) { return DNSName(name); });
818✔
500
  luaCtx.writeFunction("newDNSNameFromRaw", [](const std::string& name) { return DNSName(name.c_str(), name.size(), 0, false); });
818✔
501
  luaCtx.writeFunction("newSuffixMatchNode", []() { return SuffixMatchNode(); });
818✔
502
  luaCtx.writeFunction("newDNSNameSet", []() { return DNSNameSet(); });
818✔
503

504
  /* DNSNameSet */
505
  luaCtx.registerFunction<string (DNSNameSet::*)() const>("toString", [](const DNSNameSet& dns) { return dns.toString(); });
818✔
506
  luaCtx.registerFunction<string (DNSNameSet::*)() const>("__tostring", [](const DNSNameSet& dns) { return dns.toString(); });
818✔
507
  luaCtx.registerFunction<void (DNSNameSet::*)(DNSName&)>("add", [](DNSNameSet& dns, DNSName& name) { dns.insert(name); });
818✔
508
  luaCtx.registerFunction<bool (DNSNameSet::*)(DNSName&)>("check", [](DNSNameSet& dns, DNSName& name) { return dns.find(name) != dns.end(); });
818✔
509
  // clang-format off
510
  luaCtx.registerFunction("delete", (size_t (DNSNameSet::*)(const DNSName&)) &DNSNameSet::erase);
818✔
511
  luaCtx.registerFunction("size", (size_t (DNSNameSet::*)() const) &DNSNameSet::size);
818✔
512
  luaCtx.registerFunction("clear", (void (DNSNameSet::*)()) &DNSNameSet::clear);
818✔
513
  luaCtx.registerFunction("empty", (bool (DNSNameSet::*)() const) &DNSNameSet::empty);
818✔
514
  // clang-format on
515
#endif /* DISABLE_DNSNAME_BINDINGS */
818✔
516

517
#ifndef DISABLE_SUFFIX_MATCH_BINDINGS
818✔
518
  /* SuffixMatchNode */
519
  luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, std::string, LuaArray<DNSName>, LuaArray<std::string>>& name)>("add", [](SuffixMatchNode& smn, const boost::variant<DNSName, std::string, LuaArray<DNSName>, LuaArray<std::string>>& name) {
818✔
520
    if (name.type() == typeid(DNSName)) {
23✔
521
      const auto& actualName = boost::get<DNSName>(name);
9✔
522
      smn.add(actualName);
9✔
523
      return;
9✔
524
    }
9✔
525
    if (name.type() == typeid(std::string)) {
14✔
526
      const auto& actualName = boost::get<std::string>(name);
12✔
527
      smn.add(actualName);
12✔
528
      return;
12✔
529
    }
12✔
530
    if (name.type() == typeid(LuaArray<DNSName>)) {
2✔
531
      const auto& names = boost::get<LuaArray<DNSName>>(name);
1✔
532
      for (const auto& actualName : names) {
2✔
533
        smn.add(actualName.second);
2✔
534
      }
2✔
535
      return;
1✔
536
    }
1✔
537
    if (name.type() == typeid(LuaArray<std::string>)) {
1!
538
      const auto& names = boost::get<LuaArray<string>>(name);
1✔
539
      for (const auto& actualName : names) {
2✔
540
        smn.add(actualName.second);
2✔
541
      }
2✔
542
      return;
1✔
543
    }
1✔
544
  });
1✔
545
  luaCtx.registerFunction<void (SuffixMatchNode::*)(const boost::variant<DNSName, string, LuaArray<DNSName>, LuaArray<std::string>>& name)>("remove", [](SuffixMatchNode& smn, const boost::variant<DNSName, string, LuaArray<DNSName>, LuaArray<std::string>>& name) {
818✔
546
    if (name.type() == typeid(DNSName)) {
×
547
      const auto& actualName = boost::get<DNSName>(name);
548
      smn.remove(actualName);
549
      return;
550
    }
551
    if (name.type() == typeid(string)) {
×
552
      const auto& actualName = boost::get<string>(name);
553
      DNSName dnsName(actualName);
554
      smn.remove(dnsName);
555
      return;
556
    }
557
    if (name.type() == typeid(LuaArray<DNSName>)) {
×
558
      const auto& names = boost::get<LuaArray<DNSName>>(name);
559
      for (const auto& actualName : names) {
×
560
        smn.remove(actualName.second);
561
      }
562
      return;
563
    }
564
    if (name.type() == typeid(LuaArray<std::string>)) {
×
565
      const auto& names = boost::get<LuaArray<std::string>>(name);
566
      for (const auto& actualName : names) {
×
567
        DNSName dnsName(actualName.second);
568
        smn.remove(dnsName);
569
      }
570
      return;
571
    }
572
  });
573

574
  // clang-format off
575
  luaCtx.registerFunction("check", (bool (SuffixMatchNode::*)(const DNSName&) const) &SuffixMatchNode::check);
818✔
576
  // clang-format on
577
  luaCtx.registerFunction<boost::optional<DNSName> (SuffixMatchNode::*)(const DNSName&) const>("getBestMatch", [](const SuffixMatchNode& smn, const DNSName& needle) {
818✔
578
    boost::optional<DNSName> result{boost::none};
579
    auto res = smn.getBestMatch(needle);
580
    if (res) {
×
581
      result = *res;
582
    }
583
    return result;
584
  });
585
#endif /* DISABLE_SUFFIX_MATCH_BINDINGS */
818✔
586

587
#ifndef DISABLE_NETMASK_BINDINGS
818✔
588
  /* Netmask */
589
  luaCtx.writeFunction("newNetmask", [](boost::variant<std::string, ComboAddress> addrOrStr, boost::optional<uint8_t> bits) {
818✔
590
    if (addrOrStr.type() == typeid(ComboAddress)) {
×
591
      const auto& comboAddr = boost::get<ComboAddress>(addrOrStr);
592
      if (bits) {
×
593
        return Netmask(comboAddr, *bits);
594
      }
595
      return Netmask(comboAddr);
596
    }
597
    if (addrOrStr.type() == typeid(std::string)) {
×
598
      const auto& str = boost::get<std::string>(addrOrStr);
599
      return Netmask(str);
600
    }
601
    throw std::runtime_error("Invalid parameter passed to 'newNetmask()'");
602
  });
603
  luaCtx.registerFunction("empty", &Netmask::empty);
818✔
604
  luaCtx.registerFunction("getBits", &Netmask::getBits);
818✔
605
  luaCtx.registerFunction<ComboAddress (Netmask::*)() const>("getNetwork", [](const Netmask& netmask) { return netmask.getNetwork(); }); // const reference makes this necessary
818✔
606
  luaCtx.registerFunction<ComboAddress (Netmask::*)() const>("getMaskedNetwork", [](const Netmask& netmask) { return netmask.getMaskedNetwork(); });
818✔
607
  luaCtx.registerFunction("isIpv4", &Netmask::isIPv4);
818✔
608
  luaCtx.registerFunction("isIPv4", &Netmask::isIPv4);
818✔
609
  luaCtx.registerFunction("isIpv6", &Netmask::isIPv6);
818✔
610
  luaCtx.registerFunction("isIPv6", &Netmask::isIPv6);
818✔
611
  // clang-format off
612
  luaCtx.registerFunction("match", (bool (Netmask::*)(const string&) const) &Netmask::match);
818✔
613
  // clang-format on
614
  luaCtx.registerFunction("toString", &Netmask::toString);
818✔
615
  luaCtx.registerFunction("__tostring", &Netmask::toString);
818✔
616
  luaCtx.registerEqFunction(&Netmask::operator==);
818✔
617
  luaCtx.registerToStringFunction(&Netmask::toString);
818✔
618

619
  /* NetmaskGroup */
620
  luaCtx.writeFunction("newNMG", []() { return NetmaskGroup(); });
818✔
621
  luaCtx.registerFunction<void (NetmaskGroup::*)(const std::string& mask)>("addMask", [](NetmaskGroup& nmg, const std::string& mask) {
818✔
622
    nmg.addMask(mask);
8✔
623
  });
8✔
624
  luaCtx.registerFunction<void (NetmaskGroup::*)(const NetmaskGroup& otherNMG)>("addNMG", [](NetmaskGroup& nmg, const NetmaskGroup& otherNMG) {
818✔
625
    /* this is not going to be very efficient, sorry */
626
    auto entries = otherNMG.toStringVector();
2✔
627
    for (const auto& entry : entries) {
2✔
628
      nmg.addMask(entry);
2✔
629
    }
2✔
630
  });
2✔
631
  luaCtx.registerFunction<void (NetmaskGroup::*)(const std::map<ComboAddress, int>& map)>("addMasks", [](NetmaskGroup& nmg, const std::map<ComboAddress, int>& map) {
818✔
632
    for (const auto& entry : map) {
×
633
      nmg.addMask(Netmask(entry.first));
634
    }
635
  });
636

637
  // clang-format off
638
  luaCtx.registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const) &NetmaskGroup::match);
818✔
639
  // clang-format on
640
  luaCtx.registerFunction("size", &NetmaskGroup::size);
818✔
641
  luaCtx.registerFunction("clear", &NetmaskGroup::clear);
818✔
642
  luaCtx.registerFunction<string (NetmaskGroup::*)() const>("toString", [](const NetmaskGroup& nmg) { return "NetmaskGroup " + nmg.toString(); });
818✔
643
  luaCtx.registerFunction<string (NetmaskGroup::*)() const>("__tostring", [](const NetmaskGroup& nmg) { return "NetmaskGroup " + nmg.toString(); });
818✔
644
#endif /* DISABLE_NETMASK_BINDINGS */
818✔
645

646
#ifndef DISABLE_QPS_LIMITER_BINDINGS
818✔
647
  /* QPSLimiter */
648
  luaCtx.writeFunction("newQPSLimiter", [](int rate, int burst) { return QPSLimiter(rate, burst); });
818✔
649
  luaCtx.registerFunction("check", &QPSLimiter::check);
818✔
650
#endif /* DISABLE_QPS_LIMITER_BINDINGS */
818✔
651

652
#ifndef DISABLE_CLIENT_STATE_BINDINGS
818✔
653
  /* ClientState */
654
  luaCtx.registerFunction<std::string (ClientState::*)() const>("toString", [](const ClientState& frontend) {
818✔
655
    setLuaNoSideEffect();
656
    return frontend.local.toStringWithPort();
657
  });
658
  luaCtx.registerFunction<std::string (ClientState::*)() const>("__tostring", [](const ClientState& frontend) {
818✔
659
    setLuaNoSideEffect();
660
    return frontend.local.toStringWithPort();
661
  });
662
  luaCtx.registerFunction<std::string (ClientState::*)() const>("getType", [](const ClientState& frontend) {
818✔
663
    setLuaNoSideEffect();
664
    return frontend.getType();
665
  });
666
  luaCtx.registerFunction<std::string (ClientState::*)() const>("getConfiguredTLSProvider", [](const ClientState& frontend) {
818✔
667
    setLuaNoSideEffect();
668
    if (frontend.doqFrontend != nullptr || frontend.doh3Frontend != nullptr) {
×
669
      return std::string("BoringSSL");
670
    }
671
    if (frontend.tlsFrontend != nullptr) {
×
672
      return frontend.tlsFrontend->getRequestedProvider();
673
    }
674
    if (frontend.dohFrontend != nullptr) {
×
675
      return std::string("openssl");
676
    }
677
    return std::string();
678
  });
679
  luaCtx.registerFunction<std::string (ClientState::*)() const>("getEffectiveTLSProvider", [](const ClientState& frontend) {
818✔
680
    setLuaNoSideEffect();
7✔
681
    if (frontend.doqFrontend != nullptr || frontend.doh3Frontend != nullptr) {
7!
682
      return std::string("BoringSSL");
683
    }
684
    if (frontend.tlsFrontend != nullptr) {
7!
685
      return frontend.tlsFrontend->getEffectiveProvider();
7✔
686
    }
7✔
687
    if (frontend.dohFrontend != nullptr) {
×
688
      return std::string("openssl");
689
    }
690
    return std::string();
691
  });
692
  luaCtx.registerMember("muted", &ClientState::muted);
818✔
693
#ifdef HAVE_EBPF
818✔
694
  luaCtx.registerFunction<void (ClientState::*)(std::shared_ptr<BPFFilter>)>("attachFilter", [](ClientState& frontend, std::shared_ptr<BPFFilter> bpf) {
818✔
695
    if (bpf) {
×
696
      frontend.attachFilter(bpf, frontend.getSocket());
697
    }
698
  });
699
  luaCtx.registerFunction<void (ClientState::*)()>("detachFilter", [](ClientState& frontend) {
818✔
700
    frontend.detachFilter(frontend.getSocket());
701
  });
702
#endif /* HAVE_EBPF */
818✔
703
#endif /* DISABLE_CLIENT_STATE_BINDINGS */
818✔
704

705
  /* BPF Filter */
706
#ifdef HAVE_EBPF
818✔
707
  using bpfopts_t = LuaAssociativeTable<boost::variant<bool, uint32_t, std::string>>;
818✔
708
  luaCtx.writeFunction("newBPFFilter", [client](bpfopts_t opts) {
818✔
709
    if (client) {
4!
710
      return std::shared_ptr<BPFFilter>(nullptr);
711
    }
712
    std::unordered_map<std::string, BPFFilter::MapConfiguration> mapsConfig;
4✔
713

714
    const auto convertParamsToConfig = [&](const std::string& name, BPFFilter::MapType type) {
20✔
715
      BPFFilter::MapConfiguration config;
20✔
716
      config.d_type = type;
20✔
717
      if (const string key = name + "MaxItems"; opts.count(key)) {
20✔
718
        const auto& tmp = opts.at(key);
12✔
719
        if (tmp.type() != typeid(uint32_t)) {
12!
720
          throw std::runtime_error("params is invalid");
721
        }
722
        const auto& params = boost::get<uint32_t>(tmp);
12✔
723
        config.d_maxItems = params;
12✔
724
      }
12✔
725

726
      if (const string key = name + "PinnedPath"; opts.count(key)) {
20!
727
        auto& tmp = opts.at(key);
728
        if (tmp.type() != typeid(string)) {
×
729
          throw std::runtime_error("params is invalid");
730
        }
731
        auto& params = boost::get<string>(tmp);
732
        config.d_pinnedPath = std::move(params);
733
      }
734
      mapsConfig[name] = std::move(config);
20✔
735
    };
20✔
736

737
    convertParamsToConfig("ipv4", BPFFilter::MapType::IPv4);
4✔
738
    convertParamsToConfig("ipv6", BPFFilter::MapType::IPv6);
4✔
739
    convertParamsToConfig("qnames", BPFFilter::MapType::QNames);
4✔
740
    convertParamsToConfig("cidr4", BPFFilter::MapType::CIDR4);
4✔
741
    convertParamsToConfig("cidr6", BPFFilter::MapType::CIDR6);
4✔
742

743
    BPFFilter::MapFormat format = BPFFilter::MapFormat::Legacy;
4✔
744
    bool external = false;
4✔
745
    if (opts.count("external") != 0) {
4!
746
      const auto& tmp = opts.at("external");
747
      if (tmp.type() != typeid(bool)) {
×
748
        throw std::runtime_error("params is invalid");
749
      }
750
      external = boost::get<bool>(tmp);
751
      if (external) {
×
752
        format = BPFFilter::MapFormat::WithActions;
753
      }
754
    }
755

756
    return std::make_shared<BPFFilter>(mapsConfig, format, external);
4✔
757
  });
4✔
758

759
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const ComboAddress& addr, boost::optional<uint32_t> action)>("block", [](const std::shared_ptr<BPFFilter>& bpf, const ComboAddress& addr, boost::optional<uint32_t> action) {
818✔
760
    if (bpf) {
3!
761
      if (!action) {
3!
762
        return bpf->block(addr, BPFFilter::MatchAction::Drop);
3✔
763
      }
3✔
764
      BPFFilter::MatchAction match{};
765

766
      switch (*action) {
767
      case 0:
×
768
        match = BPFFilter::MatchAction::Pass;
769
        break;
770
      case 1:
×
771
        match = BPFFilter::MatchAction::Drop;
772
        break;
773
      case 2:
×
774
        match = BPFFilter::MatchAction::Truncate;
775
        break;
776
      default:
×
777
        throw std::runtime_error("Unsupported action for BPFFilter::block");
778
      }
779
      return bpf->block(addr, match);
780
    }
781
  });
3✔
782
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const string& range, uint32_t action, boost::optional<bool> force)>("addRangeRule", [](const std::shared_ptr<BPFFilter>& bpf, const string& range, uint32_t action, boost::optional<bool> force) {
818✔
783
    if (!bpf) {
×
784
      return;
785
    }
786
    BPFFilter::MatchAction match{};
787
    switch (action) {
788
    case 0:
×
789
      match = BPFFilter::MatchAction::Pass;
790
      break;
791
    case 1:
×
792
      match = BPFFilter::MatchAction::Drop;
793
      break;
794
    case 2:
×
795
      match = BPFFilter::MatchAction::Truncate;
796
      break;
797
    default:
×
798
      throw std::runtime_error("Unsupported action for BPFFilter::block");
799
    }
800
    return bpf->addRangeRule(Netmask(range), force ? *force : false, match);
×
801
  });
802
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype, boost::optional<uint32_t> action)>("blockQName", [](const std::shared_ptr<BPFFilter>& bpf, const DNSName& qname, boost::optional<uint16_t> qtype, boost::optional<uint32_t> action) {
818✔
803
    if (bpf) {
6!
804
      if (!action) {
6!
805
        return bpf->block(qname, BPFFilter::MatchAction::Drop, qtype ? *qtype : 65535);
6!
806
      }
6✔
807
      BPFFilter::MatchAction match{};
808

809
      switch (*action) {
810
      case 0:
×
811
        match = BPFFilter::MatchAction::Pass;
812
        break;
813
      case 1:
×
814
        match = BPFFilter::MatchAction::Drop;
815
        break;
816
      case 2:
×
817
        match = BPFFilter::MatchAction::Truncate;
818
        break;
819
      default:
×
820
        throw std::runtime_error("Unsupported action for BPFFilter::blockQName");
821
      }
822
      return bpf->block(qname, match, qtype ? *qtype : 65535);
×
823
    }
824
  });
6✔
825

826
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const ComboAddress& addr)>("unblock", [](const std::shared_ptr<BPFFilter>& bpf, const ComboAddress& addr) {
818✔
827
    if (bpf) {
6!
828
      return bpf->unblock(addr);
6✔
829
    }
6✔
830
  });
6✔
831
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const string& range)>("rmRangeRule", [](const std::shared_ptr<BPFFilter>& bpf, const string& range) {
818✔
832
    if (!bpf) {
×
833
      return;
834
    }
835
    bpf->rmRangeRule(Netmask(range));
836
  });
837
  luaCtx.registerFunction<std::string (std::shared_ptr<BPFFilter>::*)() const>("lsRangeRule", [](const std::shared_ptr<BPFFilter>& bpf) {
818✔
838
    setLuaNoSideEffect();
839
    std::string res;
840
    if (!bpf) {
×
841
      return res;
842
    }
843
    const auto rangeStat = bpf->getRangeRule();
844
    for (const auto& value : rangeStat) {
×
845
      if (value.first.isIPv4()) {
×
846
        res += BPFFilter::toString(value.second.action) + "\t " + value.first.toString() + "\n";
847
      }
848
      else if (value.first.isIPv6()) {
×
849
        res += BPFFilter::toString(value.second.action) + "\t[" + value.first.toString() + "]\n";
850
      }
851
    }
852
    return res;
853
  });
854
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)(const DNSName& qname, boost::optional<uint16_t> qtype)>("unblockQName", [](const std::shared_ptr<BPFFilter>& bpf, const DNSName& qname, boost::optional<uint16_t> qtype) {
818✔
855
    if (bpf) {
2!
856
      return bpf->unblock(qname, qtype ? *qtype : 65535);
2!
857
    }
2✔
858
  });
2✔
859

860
  luaCtx.registerFunction<std::string (std::shared_ptr<BPFFilter>::*)() const>("getStats", [](const std::shared_ptr<BPFFilter>& bpf) {
818✔
861
    setLuaNoSideEffect();
2✔
862
    std::string res;
2✔
863
    if (bpf) {
2!
864
      auto stats = bpf->getAddrStats();
2✔
865
      for (const auto& value : stats) {
2✔
866
        if (value.first.sin4.sin_family == AF_INET) {
2!
867
          res += value.first.toString() + ": " + std::to_string(value.second) + "\n";
868
        }
869
        else if (value.first.sin4.sin_family == AF_INET6) {
2!
870
          res += "[" + value.first.toString() + "]: " + std::to_string(value.second) + "\n";
2✔
871
        }
2✔
872
      }
2✔
873
      const auto rangeStat = bpf->getRangeRule();
2✔
874
      for (const auto& value : rangeStat) {
2!
875
        if (value.first.isIPv4()) {
×
876
          res += BPFFilter::toString(value.second.action) + "\t " + value.first.toString() + ": " + std::to_string(value.second.counter) + "\n";
877
        }
878
        else if (value.first.isIPv6()) {
×
879
          res += BPFFilter::toString(value.second.action) + "\t[" + value.first.toString() + "]: " + std::to_string(value.second.counter) + "\n";
880
        }
881
      }
882
      auto qstats = bpf->getQNameStats();
2✔
883
      for (const auto& value : qstats) {
2✔
884
        res += std::get<0>(value).toString() + " " + std::to_string(std::get<1>(value)) + ": " + std::to_string(std::get<2>(value)) + "\n";
2✔
885
      }
2✔
886
    }
2✔
887
    return res;
2✔
888
  });
2✔
889

890
  luaCtx.registerFunction<void (std::shared_ptr<BPFFilter>::*)()>("attachToAllBinds", [](std::shared_ptr<BPFFilter>& bpf) {
818✔
891
    std::string res;
892
    if (!dnsdist::configuration::isImmutableConfigurationDone()) {
×
893
      throw std::runtime_error("attachToAllBinds() cannot be used at configuration time!");
894
      return;
895
    }
896
    if (bpf) {
×
897
      for (const auto& frontend : dnsdist::getFrontends()) {
×
898
        frontend->attachFilter(bpf, frontend->getSocket());
899
      }
900
    }
901
  });
902

903
  luaCtx.writeFunction("newDynBPFFilter", [client](std::shared_ptr<BPFFilter>& bpf) {
818✔
904
    if (client) {
×
905
      return std::shared_ptr<DynBPFFilter>(nullptr);
906
    }
907
    return std::make_shared<DynBPFFilter>(bpf);
908
  });
909

910
  luaCtx.registerFunction<void (std::shared_ptr<DynBPFFilter>::*)(const ComboAddress& addr, boost::optional<int> seconds)>("block", [](const std::shared_ptr<DynBPFFilter>& dbpf, const ComboAddress& addr, boost::optional<int> seconds) {
818✔
911
    if (dbpf) {
×
912
      timespec until{};
913
      clock_gettime(CLOCK_MONOTONIC, &until);
914
      until.tv_sec += seconds ? *seconds : 10;
×
915
      dbpf->block(addr, until);
916
    }
917
  });
918

919
  luaCtx.registerFunction<void (std::shared_ptr<DynBPFFilter>::*)()>("purgeExpired", [](const std::shared_ptr<DynBPFFilter>& dbpf) {
818✔
920
    if (dbpf) {
×
921
      timespec now{};
922
      clock_gettime(CLOCK_MONOTONIC, &now);
923
      dbpf->purgeExpired(now);
924
    }
925
  });
926

927
  luaCtx.registerFunction<void (std::shared_ptr<DynBPFFilter>::*)(LuaTypeOrArrayOf<std::string>)>("excludeRange", [](const std::shared_ptr<DynBPFFilter>& dbpf, LuaTypeOrArrayOf<std::string> ranges) {
818✔
928
    if (!dbpf) {
×
929
      return;
930
    }
931

932
    if (ranges.type() == typeid(LuaArray<std::string>)) {
×
933
      for (const auto& range : *boost::get<LuaArray<std::string>>(&ranges)) {
×
934
        dbpf->excludeRange(Netmask(range.second));
935
      }
936
    }
937
    else {
938
      dbpf->excludeRange(Netmask(*boost::get<std::string>(&ranges)));
939
    }
940
  });
941

942
  luaCtx.registerFunction<void (std::shared_ptr<DynBPFFilter>::*)(LuaTypeOrArrayOf<std::string>)>("includeRange", [](const std::shared_ptr<DynBPFFilter>& dbpf, LuaTypeOrArrayOf<std::string> ranges) {
818✔
943
    if (!dbpf) {
×
944
      return;
945
    }
946

947
    if (ranges.type() == typeid(LuaArray<std::string>)) {
×
948
      for (const auto& range : *boost::get<LuaArray<std::string>>(&ranges)) {
×
949
        dbpf->includeRange(Netmask(range.second));
950
      }
951
    }
952
    else {
953
      dbpf->includeRange(Netmask(*boost::get<std::string>(&ranges)));
954
    }
955
  });
956
#endif /* HAVE_EBPF */
818✔
957
#ifdef HAVE_XSK
818✔
958
  using xskopt_t = LuaAssociativeTable<boost::variant<uint32_t, std::string>>;
818✔
959
  luaCtx.writeFunction("newXsk", [client](xskopt_t opts) {
818✔
960
    if (dnsdist::configuration::isImmutableConfigurationDone()) {
×
961
      throw std::runtime_error("newXsk() only can be used at configuration time!");
×
962
    }
×
963
    if (client) {
×
964
      return std::shared_ptr<XskSocket>(nullptr);
×
965
    }
×
966
    uint32_t queue_id{};
×
967
    uint32_t frameNums{65536};
×
968
    std::string ifName;
×
969
    std::string path("/sys/fs/bpf/dnsdist/xskmap");
×
970
    if (opts.count("ifName") == 1) {
×
971
      ifName = boost::get<std::string>(opts.at("ifName"));
×
972
    }
×
973
    else {
×
974
      throw std::runtime_error("ifName field is required!");
×
975
    }
×
976
    if (opts.count("NIC_queue_id") == 1) {
×
977
      queue_id = boost::get<uint32_t>(opts.at("NIC_queue_id"));
×
978
    }
×
979
    else {
×
980
      throw std::runtime_error("NIC_queue_id field is required!");
×
981
    }
×
982
    if (opts.count("frameNums") == 1) {
×
983
      frameNums = boost::get<uint32_t>(opts.at("frameNums"));
×
984
    }
×
985
    if (opts.count("xskMapPath") == 1) {
×
986
      path = boost::get<std::string>(opts.at("xskMapPath"));
×
987
    }
×
988
    auto socket = std::make_shared<XskSocket>(frameNums, ifName, queue_id, path);
×
989
    dnsdist::xsk::g_xsk.push_back(socket);
×
990
    return socket;
×
991
  });
×
992
  luaCtx.registerFunction<std::string (std::shared_ptr<XskSocket>::*)() const>("getMetrics", [](const std::shared_ptr<XskSocket>& xsk) -> std::string {
818✔
993
    if (!xsk) {
×
994
      return {};
×
995
    }
×
996
    return xsk->getMetrics();
×
997
  });
×
998
#endif /* HAVE_XSK */
818✔
999
  /* EDNSOptionView */
1000
  luaCtx.registerFunction<size_t (EDNSOptionView::*)() const>("count", [](const EDNSOptionView& option) {
818✔
1001
    return option.values.size();
32✔
1002
  });
32✔
1003
  luaCtx.registerFunction<std::vector<string> (EDNSOptionView::*)() const>("getValues", [](const EDNSOptionView& option) {
818✔
1004
    std::vector<string> values;
36✔
1005
    values.reserve(values.size());
36✔
1006
    for (const auto& value : option.values) {
44✔
1007
      values.emplace_back(value.content, value.size);
44✔
1008
    }
44✔
1009
    return values;
36✔
1010
  });
36✔
1011

1012
  luaCtx.writeFunction("newDOHResponseMapEntry", [](const std::string& regex, uint64_t status, const std::string& content, boost::optional<LuaAssociativeTable<std::string>> customHeaders) {
818✔
1013
    checkParameterBound("newDOHResponseMapEntry", status, std::numeric_limits<uint16_t>::max());
6✔
1014
    boost::optional<LuaAssociativeTable<std::string>> headers{boost::none};
6✔
1015
    if (customHeaders) {
6!
1016
      headers = LuaAssociativeTable<std::string>();
6✔
1017
      for (const auto& header : *customHeaders) {
6✔
1018
        (*headers)[boost::to_lower_copy(header.first)] = header.second;
6✔
1019
      }
6✔
1020
    }
6✔
1021
    return std::make_shared<DOHResponseMapEntry>(regex, status, PacketBuffer(content.begin(), content.end()), headers);
6✔
1022
  });
6✔
1023

1024
  luaCtx.writeFunction("newSVCRecordParameters", [](uint64_t priority, const std::string& target, boost::optional<svcParamsLua_t> additionalParameters) {
818✔
1025
    checkParameterBound("newSVCRecordParameters", priority, std::numeric_limits<uint16_t>::max());
14✔
1026
    SVCRecordParameters parameters;
14✔
1027
    if (additionalParameters) {
14!
1028
      parameters = parseSVCParameters(*additionalParameters);
14✔
1029
    }
14✔
1030
    parameters.priority = priority;
14✔
1031
    parameters.target = DNSName(target);
14✔
1032

1033
    return parameters;
14✔
1034
  });
14✔
1035

1036
  luaCtx.writeFunction("getListOfNetworkInterfaces", []() {
818✔
1037
    LuaArray<std::string> result;
×
1038
    auto itfs = getListOfNetworkInterfaces();
×
1039
    int counter = 1;
×
1040
    for (const auto& itf : itfs) {
×
1041
      result.emplace_back(counter++, itf);
×
1042
    }
×
1043
    return result;
×
1044
  });
×
1045

1046
  luaCtx.writeFunction("getListOfAddressesOfNetworkInterface", [](const std::string& itf) {
818✔
1047
    LuaArray<std::string> result;
×
1048
    auto addrs = getListOfAddressesOfNetworkInterface(itf);
×
1049
    int counter = 1;
×
1050
    for (const auto& addr : addrs) {
×
1051
      result.emplace_back(counter++, addr.toString());
×
1052
    }
×
1053
    return result;
×
1054
  });
×
1055

1056
  luaCtx.writeFunction("getListOfRangesOfNetworkInterface", [](const std::string& itf) {
818✔
1057
    LuaArray<std::string> result;
×
1058
    auto addrs = getListOfRangesOfNetworkInterface(itf);
×
1059
    int counter = 1;
×
1060
    for (const auto& addr : addrs) {
×
1061
      result.emplace_back(counter++, addr.toString());
×
1062
    }
×
1063
    return result;
×
1064
  });
×
1065

1066
  luaCtx.writeFunction("getMACAddress", [](const std::string& addr) {
818✔
1067
    return getMACAddress(ComboAddress(addr));
×
1068
  });
×
1069

1070
  luaCtx.writeFunction("getCurrentTime", []() -> timespec {
818✔
1071
    timespec now{};
4✔
1072
    if (gettime(&now, true) < 0) {
4!
1073
      unixDie("Getting timestamp");
×
1074
    }
×
1075
    return now;
4✔
1076
  });
4✔
1077

1078
  luaCtx.writeFunction("getAddressInfo", [client, configCheck](std::string hostname, std::function<void(const std::string& hostname, const LuaArray<ComboAddress>& ips)> callback) {
818✔
1079
    if (client || configCheck) {
2!
1080
      return;
1✔
1081
    }
1✔
1082
    std::thread newThread(dnsdist::resolver::asynchronousResolver, std::move(hostname), [callback = std::move(callback)](const std::string& resolvedHostname, std::vector<ComboAddress>& ips) mutable {
1✔
1083
      LuaArray<ComboAddress> result;
1✔
1084
      result.reserve(ips.size());
1✔
1085
      for (const auto& entry : ips) {
2✔
1086
        result.emplace_back(result.size() + 1, entry);
2✔
1087
      }
2✔
1088
      {
1✔
1089
        auto lua = g_lua.lock();
1✔
1090
        try {
1✔
1091
          callback(resolvedHostname, result);
1✔
1092
        }
1✔
1093
        catch (const std::exception& exp) {
1✔
1094
          vinfolog("Error during execution of getAddressInfo callback: %s", exp.what());
×
1095
        }
×
1096
        // this _needs_ to be done while we are holding the lock,
1097
        // otherwise the destructor will corrupt the stack
1098
        callback = nullptr;
1✔
1099
        dnsdist::handleQueuedAsynchronousEvents();
1✔
1100
      }
1✔
1101
    });
1✔
1102
    newThread.detach();
1✔
1103
  });
1✔
1104

1105
  luaCtx.writeFunction("refreshRuntimeConfiguration", []() {
818✔
1106
    dnsdist::configuration::refreshLocalRuntimeConfiguration();
×
1107
  });
×
1108
}
818✔
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

© 2025 Coveralls, Inc