Coverage Report

Created: 2026-10-03 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsdistdist/dnsdist-lua-actions.cc
Line
Count
Source
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#include "config.h"
23
#include "dnsdist.hh"
24
#include "dnsdist-actions-factory.hh"
25
#include "dnsdist-dnsparser.hh"
26
#include "dnsdist-lua.hh"
27
#include "dnsdist-lua-ffi.hh"
28
#include "dnsdist-protobuf.hh"
29
#include "dnsdist-rule-chains.hh"
30
#include "dnstap.hh"
31
#include "dolog.hh"
32
#include "otlp_logger.hh"
33
#include "remote_logger.hh"
34
#include <memory>
35
#include <optional>
36
#include <stdexcept>
37
#include <variant>
38
#include <vector>
39
40
using responseParams_t = std::unordered_map<std::string, boost::variant<bool, uint32_t>>;
41
42
static dnsdist::ResponseConfig parseResponseConfig(std::optional<responseParams_t>& vars)
43
0
{
44
0
  dnsdist::ResponseConfig config;
45
0
  getOptionalValue<uint32_t>(vars, "ttl", config.ttl);
46
0
  getOptionalValue<bool>(vars, "aa", config.setAA);
47
0
  getOptionalValue<bool>(vars, "ad", config.setAD);
48
0
  getOptionalValue<bool>(vars, "ra", config.setRA);
49
0
  return config;
50
0
}
51
52
template <class T>
53
static std::vector<T> convertLuaArrayToRegular(const LuaArray<T>& luaArray)
54
0
{
55
0
  std::vector<T> out;
56
0
  out.reserve(luaArray.size());
57
0
  for (const auto& entry : luaArray) {
58
0
    out.emplace_back(entry.second);
59
0
  }
60
0
  return out;
61
0
}
62
63
// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
64
void setupLuaActions(LuaContext& luaCtx)
65
0
{
66
0
  luaCtx.writeFunction("newRuleAction", [](const luadnsrule_t& dnsrule, std::shared_ptr<DNSAction> action, std::optional<luaruleparams_t> params) {
67
0
    boost::uuids::uuid uuid{};
68
0
    uint64_t creationOrder = 0;
69
0
    std::string name;
70
0
    parseRuleParams(params, uuid, name, creationOrder);
71
0
    checkAllParametersConsumed("newRuleAction", params);
72
73
0
    auto rule = makeRule(dnsrule, "newRuleAction");
74
0
    dnsdist::rules::RuleAction ruleaction({std::move(rule), std::move(action), std::move(name), uuid, creationOrder});
75
0
    return std::make_shared<dnsdist::rules::RuleAction>(ruleaction);
76
0
  });
77
78
0
  luaCtx.registerFunction<void (DNSAction::*)() const>("printStats", [](const DNSAction& action) {
79
0
    setLuaNoSideEffect();
80
0
    auto stats = action.getStats();
81
0
    for (const auto& stat : stats) {
82
0
      g_outputBuffer += stat.first + "\t";
83
0
      double integral = 0;
84
0
      if (std::modf(stat.second, &integral) == 0.0 && stat.second < static_cast<double>(std::numeric_limits<uint64_t>::max())) {
85
0
        g_outputBuffer += std::to_string(static_cast<uint64_t>(stat.second)) + "\n";
86
0
      }
87
0
      else {
88
0
        g_outputBuffer += std::to_string(stat.second) + "\n";
89
0
      }
90
0
    }
91
0
  });
92
93
0
  luaCtx.registerFunction("getStats", &DNSAction::getStats);
94
0
  luaCtx.registerFunction("reload", &DNSAction::reload);
95
0
  luaCtx.registerFunction("reload", &DNSResponseAction::reload);
96
97
0
  luaCtx.writeFunction("LuaAction", [](dnsdist::actions::LuaActionFunction function) {
98
0
    return dnsdist::actions::getLuaAction(std::move(function));
99
0
  });
100
101
0
  luaCtx.writeFunction("LuaFFIAction", [](dnsdist::actions::LuaActionFFIFunction function) {
102
0
    return dnsdist::actions::getLuaFFIAction(std::move(function));
103
0
  });
104
105
0
  luaCtx.writeFunction("LuaResponseAction", [](dnsdist::actions::LuaResponseActionFunction function) {
106
0
    return dnsdist::actions::getLuaResponseAction(std::move(function));
107
0
  });
108
109
0
  luaCtx.writeFunction("LuaFFIResponseAction", [](dnsdist::actions::LuaResponseActionFFIFunction function) {
110
0
    return dnsdist::actions::getLuaFFIResponseAction(std::move(function));
111
0
  });
112
113
0
  luaCtx.writeFunction("SpoofAction", [](LuaTypeOrArrayOf<std::string> inp, std::optional<responseParams_t> vars) {
114
0
    vector<ComboAddress> addrs;
115
0
    if (auto* ipaddr = boost::get<std::string>(&inp)) {
116
0
      addrs.emplace_back(*ipaddr);
117
0
    }
118
0
    else {
119
0
      const auto& ipsArray = boost::get<LuaArray<std::string>>(inp);
120
0
      for (const auto& ipAddr : ipsArray) {
121
0
        addrs.emplace_back(ipAddr.second);
122
0
      }
123
0
    }
124
125
0
    auto responseConfig = parseResponseConfig(vars);
126
0
    checkAllParametersConsumed("SpoofAction", vars);
127
0
    auto ret = dnsdist::actions::getSpoofAction(addrs, responseConfig);
128
0
    return ret;
129
0
  });
130
131
0
  luaCtx.writeFunction("SpoofSVCAction", [](const LuaArray<SVCRecordParameters>& parameters, std::optional<responseParams_t> vars) {
132
0
    auto responseConfig = parseResponseConfig(vars);
133
0
    checkAllParametersConsumed("SpoofAction", vars);
134
0
    auto svcParams = convertLuaArrayToRegular(parameters);
135
0
    auto ret = dnsdist::actions::getSpoofSVCAction(svcParams, responseConfig);
136
0
    return ret;
137
0
  });
138
139
0
  luaCtx.writeFunction("SpoofCNAMEAction", [](const std::string& cname, std::optional<responseParams_t> vars) {
140
0
    auto responseConfig = parseResponseConfig(vars);
141
0
    checkAllParametersConsumed("SpoofCNAMEAction", vars);
142
0
    auto ret = dnsdist::actions::getSpoofAction(DNSName(cname), responseConfig);
143
0
    return ret;
144
0
  });
145
146
0
  luaCtx.writeFunction("SpoofRawAction", [](LuaTypeOrArrayOf<std::string> inp, std::optional<responseParams_t> vars) {
147
0
    vector<string> raws;
148
0
    if (const auto* str = boost::get<std::string>(&inp)) {
149
0
      raws.push_back(*str);
150
0
    }
151
0
    else {
152
0
      const auto& vect = boost::get<LuaArray<std::string>>(inp);
153
0
      for (const auto& raw : vect) {
154
0
        raws.push_back(raw.second);
155
0
      }
156
0
    }
157
0
    uint32_t qtypeForAny{0};
158
0
    getOptionalValue<uint32_t>(vars, "typeForAny", qtypeForAny);
159
0
    if (qtypeForAny > std::numeric_limits<uint16_t>::max()) {
160
0
      qtypeForAny = 0;
161
0
    }
162
0
    std::optional<uint16_t> qtypeForAnyParam;
163
0
    if (qtypeForAny > 0) {
164
0
      qtypeForAnyParam = static_cast<uint16_t>(qtypeForAny);
165
0
    }
166
0
    auto responseConfig = parseResponseConfig(vars);
167
0
    checkAllParametersConsumed("SpoofRawAction", vars);
168
0
    auto ret = dnsdist::actions::getSpoofAction(raws, qtypeForAnyParam, responseConfig);
169
0
    return ret;
170
0
  });
171
172
0
  luaCtx.writeFunction("SpoofPacketAction", [](const std::string& response, size_t len) {
173
0
    if (len < sizeof(dnsheader)) {
174
0
      throw std::runtime_error(std::string("SpoofPacketAction: given packet len is too small"));
175
0
    }
176
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
177
0
    auto ret = dnsdist::actions::getSpoofAction(PacketBuffer(response.data(), response.data() + len));
178
0
    return ret;
179
0
  });
180
181
0
  luaCtx.writeFunction("LimitTTLResponseAction", [](uint32_t min, uint32_t max, std::optional<LuaArray<uint16_t>> types) {
182
0
    std::unordered_set<QType> capTypes;
183
0
    if (types) {
184
0
      capTypes.reserve(types->size());
185
0
      for (const auto& [idx, type] : *types) {
186
0
        capTypes.insert(QType(type));
187
0
      }
188
0
    }
189
0
    return dnsdist::actions::getLimitTTLResponseAction(min, max, std::move(capTypes));
190
0
  });
191
192
0
  luaCtx.writeFunction("SetMinTTLResponseAction", [](uint32_t min) {
193
0
    return dnsdist::actions::getLimitTTLResponseAction(min);
194
0
  });
195
196
0
  luaCtx.writeFunction("SetMaxTTLResponseAction", [](uint32_t max) {
197
0
    return dnsdist::actions::getLimitTTLResponseAction(0, max);
198
0
  });
199
200
0
  luaCtx.writeFunction("SetMaxReturnedTTLAction", [](uint32_t max) {
201
0
    return dnsdist::actions::getSetMaxReturnedTTLAction(max);
202
0
  });
203
204
0
  luaCtx.writeFunction("SetMaxReturnedTTLResponseAction", [](uint32_t max) {
205
0
    return dnsdist::actions::getSetMaxReturnedTTLResponseAction(max);
206
0
  });
207
208
0
  luaCtx.writeFunction("SetReducedTTLResponseAction", [](uint8_t percentage) {
209
0
    if (percentage > 100) {
210
0
      throw std::runtime_error(std::string("SetReducedTTLResponseAction takes a percentage between 0 and 100."));
211
0
    }
212
0
    return dnsdist::actions::getSetReducedTTLResponseAction(percentage);
213
0
  });
214
215
0
  luaCtx.writeFunction("ClearRecordTypesResponseAction", [](LuaTypeOrArrayOf<int> types) {
216
0
    std::unordered_set<QType> qtypes{};
217
0
    if (types.type() == typeid(int)) {
218
0
      qtypes.insert(boost::get<int>(types));
219
0
    }
220
0
    else if (types.type() == typeid(LuaArray<int>)) {
221
0
      const auto& typesArray = boost::get<LuaArray<int>>(types);
222
0
      for (const auto& tpair : typesArray) {
223
0
        qtypes.insert(tpair.second);
224
0
      }
225
0
    }
226
0
    return dnsdist::actions::getClearRecordTypesResponseAction(std::move(qtypes));
227
0
  });
228
229
0
  luaCtx.writeFunction("RCodeAction", [](uint8_t rcode, std::optional<responseParams_t> vars) {
230
0
    auto responseConfig = parseResponseConfig(vars);
231
0
    checkAllParametersConsumed("RCodeAction", vars);
232
0
    auto ret = dnsdist::actions::getRCodeAction(rcode, responseConfig);
233
0
    return ret;
234
0
  });
235
236
0
  luaCtx.writeFunction("ERCodeAction", [](uint8_t rcode, std::optional<responseParams_t> vars) {
237
0
    auto responseConfig = parseResponseConfig(vars);
238
0
    checkAllParametersConsumed("ERCodeAction", vars);
239
0
    auto ret = dnsdist::actions::getERCodeAction(rcode, responseConfig);
240
0
    return ret;
241
0
  });
242
243
0
#ifndef DISABLE_PROTOBUF
244
0
  luaCtx.writeFunction("SetTraceAction", [](bool value, std::optional<LuaAssociativeTable<boost::variant<LuaAssociativeTable<std::shared_ptr<RemoteLoggerInterface>>, bool, uint16_t>>> options) {
245
0
    dnsdist::actions::SetTraceActionConfiguration config;
246
0
    config.value = value;
247
0
    if (options) {
248
0
      LuaAssociativeTable<std::shared_ptr<RemoteLoggerInterface>> remote_loggers;
249
0
      if (getOptionalValue<LuaAssociativeTable<std::shared_ptr<RemoteLoggerInterface>>>(options, "remoteLoggers", remote_loggers) < 0) {
250
0
        throw std::runtime_error("remoteLoggers in SetTraceAction are not remote loggers");
251
0
      }
252
0
      std::vector<std::shared_ptr<RemoteLoggerInterface>> loggers;
253
0
      for (auto& remote_logger : remote_loggers) {
254
0
        if (remote_logger.second != nullptr) {
255
          // avoids potentially-evaluated-expression warning with clang.
256
0
          RemoteLoggerInterface& remoteLoggerRef = *remote_logger.second;
257
0
          if (typeid(remoteLoggerRef) != typeid(RemoteLogger) && typeid(remoteLoggerRef) != typeid(OTLPLogger)) {
258
            // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
259
0
            throw std::runtime_error(std::string("SetTraceAction only takes RemoteLogger or OTLPLogger."));
260
0
          }
261
0
          loggers.push_back(remote_logger.second);
262
0
        }
263
0
      }
264
0
      config.remote_loggers = std::move(loggers);
265
0
      if (getOptionalValue<uint16_t>(options, "traceparentOptionCode", config.traceparentOptionCode) < 0) {
266
0
        throw std::runtime_error("TraceparentOptionCode in SetTraceAction is not a number");
267
0
      }
268
0
      if (config.traceparentOptionCode == 0) {
269
0
        config.traceparentOptionCode = EDNSOptionCode::TRACEPARENT;
270
0
      }
271
0
      if (getOptionalValue<bool>(options, "sendDownstreamTraceparent", config.sendDownstreamTraceparent) < 0) {
272
0
        throw std::runtime_error("sendDownstreamTraceparent in SetTraceAction is not a bool");
273
0
      }
274
0
      if (getOptionalValue<bool>(options, "useIncomingTraceparent", config.useIncomingTraceparent) < 0) {
275
0
        throw std::runtime_error("useIncomingTraceparent in SetTraceAction is not a bool");
276
0
      }
277
0
      if (getOptionalValue<bool>(options, "stripIncomingTraceparent", config.stripIncomingTraceparent) < 0) {
278
0
        throw std::runtime_error("stripIncomingTraceparent in SetTraceAction is not a bool");
279
0
      }
280
0
      checkAllParametersConsumed("SetTraceAction", options);
281
0
    }
282
0
    return dnsdist::actions::getSetTraceAction(config);
283
0
  });
284
285
  // Used for both RemoteLogAction and RemoteLogResponseAction
286
0
  static const std::array<std::string, 2> s_validIpEncryptMethods = {"legacy", "ipcrypt-pfx"};
287
288
0
  luaCtx.writeFunction("RemoteLogAction", [](std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::ProtobufAlterFunction> alterFunc, std::optional<LuaAssociativeTable<boost::variant<std::string, bool>>> vars, std::optional<LuaAssociativeTable<std::string>> metas) {
289
0
    if (logger) {
290
      // avoids potentially-evaluated-expression warning with clang.
291
0
      RemoteLoggerInterface& remoteLoggerRef = *logger;
292
0
      if (typeid(remoteLoggerRef) != typeid(RemoteLogger)) {
293
        // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
294
0
        throw std::runtime_error(std::string("RemoteLogAction only takes RemoteLogger. For other types, please look at DnstapLogAction."));
295
0
      }
296
0
    }
297
298
0
    std::string tags;
299
0
    std::string tagsPrefixes;
300
0
    dnsdist::actions::RemoteLogActionConfiguration config;
301
0
    config.logger = std::move(logger);
302
0
    if (alterFunc) {
303
0
      config.alterQueryFunc = std::move(*alterFunc);
304
0
    }
305
0
    if (getOptionalValue<std::string>(vars, "serverID", config.serverID) < 0) {
306
0
      throw std::runtime_error("serverID in RemoteLogAction is not a string");
307
0
    }
308
0
    if (getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey) < 0) {
309
0
      throw std::runtime_error("ipEncryptKey in RemoteLogAction is not a string");
310
0
    }
311
0
    if (getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod) < 0) {
312
0
      throw std::runtime_error("ipEncryptMethod in RemoteLogAction is not a string");
313
0
    }
314
0
    if (getOptionalValue<std::string>(vars, "exportTags", tags) < 0) {
315
0
      throw std::runtime_error("exportTags in RemoteLogAction is not a string");
316
0
    }
317
0
    if (getOptionalValue<std::string>(vars, "exportTagsPrefixes", tagsPrefixes) < 0) {
318
0
      throw std::runtime_error("exportTagsPrefixes in RemoteLogAction is not a string");
319
0
    }
320
0
    if (getOptionalValue<bool>(vars, "exportTagsKeyOnly", config.tagsExportKeyOnly) < 0) {
321
0
      throw std::runtime_error("exportTagsKeyOnly in RemoteLogAction is not a boolean");
322
0
    }
323
0
    if (getOptionalValue<bool>(vars, "exportTagsStripPrefixes", config.tagsStripPrefixes) < 0) {
324
0
      throw std::runtime_error("exportTagsStripPrefixes in RemoteLogAction is not a boolean");
325
0
    }
326
0
    if (getOptionalValue<bool>(vars, "useServerID", config.useServerID) < 0) {
327
0
      throw std::runtime_error("useServerID in RemoteLogAction is not a boolean");
328
0
    }
329
330
0
    if (config.useServerID && !config.serverID.empty()) {
331
0
      SLOG(warnlog("useServerID and serverID set in RemoteLogAction configuration. value for serverID will not be used"),
332
0
           dnsdist::logging::getTopLogger("RemoteLogAction")->info(Logr::Warning, "useServerID and serverID set in RemoteLogAction configuration. value for serverID will not be used"));
333
0
    }
334
335
0
    if (metas) {
336
0
      for (const auto& [key, value] : *metas) {
337
0
        config.metas.emplace_back(key, ProtoBufMetaKey(value));
338
0
      }
339
0
    }
340
341
0
    if (std::find(s_validIpEncryptMethods.begin(), s_validIpEncryptMethods.end(), config.ipEncryptMethod) == s_validIpEncryptMethods.end()) {
342
0
      throw std::runtime_error("Invalid IP Encryption method in RemoteLogAction");
343
0
    }
344
345
0
    if (!tags.empty()) {
346
0
      config.tagsToExport = std::unordered_set<std::string>();
347
0
      if (tags != "*") {
348
0
        std::vector<std::string> tokens;
349
0
        stringtok(tokens, tags, ",");
350
0
        for (auto& token : tokens) {
351
0
          config.tagsToExport->emplace(std::move(token));
352
0
        }
353
0
      }
354
0
    }
355
356
0
    if (!tagsPrefixes.empty()) {
357
0
      std::vector<std::string> tokens;
358
0
      stringtok(tokens, tagsPrefixes, ",");
359
0
      for (auto& token : tokens) {
360
0
        config.tagsPrefixesToExport.emplace(std::move(token));
361
0
      }
362
0
    }
363
364
0
    checkAllParametersConsumed("RemoteLogAction", vars);
365
366
0
    return dnsdist::actions::getRemoteLogAction(std::move(config));
367
0
  });
368
369
0
  luaCtx.writeFunction("RemoteLogResponseAction", [](std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::ProtobufAlterResponseFunction> alterFunc, std::optional<bool> includeCNAME, std::optional<LuaAssociativeTable<boost::variant<std::string, bool>>> vars, std::optional<LuaAssociativeTable<std::string>> metas, std::optional<bool> delay) {
370
0
    if (logger) {
371
      // avoids potentially-evaluated-expression warning with clang.
372
0
      RemoteLoggerInterface& remoteLoggerRef = *logger;
373
0
      if (typeid(remoteLoggerRef) != typeid(RemoteLogger)) {
374
        // We could let the user do what he wants, but wrapping PowerDNS Protobuf inside a FrameStream tagged as dnstap is logically wrong.
375
0
        throw std::runtime_error("RemoteLogResponseAction only takes RemoteLogger. For other types, please look at DnstapLogResponseAction.");
376
0
      }
377
0
    }
378
379
0
    std::string tags;
380
0
    std::string tagsPrefixes;
381
0
    dnsdist::actions::RemoteLogActionConfiguration config;
382
0
    config.logger = std::move(logger);
383
0
    if (alterFunc) {
384
0
      config.alterResponseFunc = std::move(*alterFunc);
385
0
    }
386
0
    config.includeCNAME = includeCNAME ? *includeCNAME : false;
387
0
    if (getOptionalValue<std::string>(vars, "serverID", config.serverID) < 0) {
388
0
      throw std::runtime_error("serverID in RemoteLogResponseAction is not a string");
389
0
    }
390
0
    if (getOptionalValue<std::string>(vars, "ipEncryptKey", config.ipEncryptKey) < 0) {
391
0
      throw std::runtime_error("ipEncryptKey in RemoteLogResponseAction is not a string");
392
0
    }
393
0
    if (getOptionalValue<std::string>(vars, "ipEncryptMethod", config.ipEncryptMethod) < 0) {
394
0
      throw std::runtime_error("ipEncryptMethod in RemoteLogResponseAction is not a string");
395
0
    }
396
0
    if (getOptionalValue<std::string>(vars, "exportTags", tags) < 0) {
397
0
      throw std::runtime_error("exportTags in RemoteLogResponseAction is not a string");
398
0
    }
399
0
    if (getOptionalValue<std::string>(vars, "exportTagsPrefixes", tagsPrefixes) < 0) {
400
0
      throw std::runtime_error("exportTagsPrefixes in RemoteLogAction is not a string");
401
0
    }
402
0
    if (getOptionalValue<bool>(vars, "exportTagsKeyOnly", config.tagsExportKeyOnly) < 0) {
403
0
      throw std::runtime_error("exportTagsKeyOnly in RemoteLogAction is not a boolean");
404
0
    }
405
0
    if (getOptionalValue<bool>(vars, "exportTagsStripPrefixes", config.tagsStripPrefixes) < 0) {
406
0
      throw std::runtime_error("exportTagsStripPrefixes in RemoteLogAction is not a boolean");
407
0
    }
408
0
    if (getOptionalValue<std::string>(vars, "exportExtendedErrorsToMeta", config.exportExtendedErrorsToMeta) < 0) {
409
0
      throw std::runtime_error("exportExtendedErrorsToMeta in RemoteLogResponseAction is not a string");
410
0
    }
411
0
    if (getOptionalValue<bool>(vars, "useServerID", config.useServerID) < 0) {
412
0
      throw std::runtime_error("useServerID in RemoteLogResponseAction is not a boolean");
413
0
    }
414
415
0
    if (config.useServerID && !config.serverID.empty()) {
416
0
      SLOG(warnlog("useServerID and serverID set in RemoteLogResponseAction configuration. value for serverID will not be used"),
417
0
           dnsdist::logging::getTopLogger("RemoteLogResponseAction")->info(Logr::Warning, "useServerID and serverID set in RemoteLogResponseAction configuration. value for serverID will not be used"));
418
0
    }
419
420
0
    if (metas) {
421
0
      for (const auto& [key, value] : *metas) {
422
0
        config.metas.emplace_back(key, ProtoBufMetaKey(value));
423
0
      }
424
0
    }
425
426
0
    if (delay) {
427
0
      config.delay = *delay;
428
0
    }
429
430
0
    if (!tags.empty()) {
431
0
      config.tagsToExport = std::unordered_set<std::string>();
432
0
      if (tags != "*") {
433
0
        std::vector<std::string> tokens;
434
0
        stringtok(tokens, tags, ",");
435
0
        for (auto& token : tokens) {
436
0
          config.tagsToExport->emplace(std::move(token));
437
0
        }
438
0
      }
439
0
    }
440
441
0
    if (!tagsPrefixes.empty()) {
442
0
      std::vector<std::string> tokens;
443
0
      stringtok(tokens, tagsPrefixes, ",");
444
0
      for (auto& token : tokens) {
445
0
        config.tagsPrefixesToExport.emplace(std::move(token));
446
0
      }
447
0
    }
448
449
0
    if (std::find(s_validIpEncryptMethods.begin(), s_validIpEncryptMethods.end(), config.ipEncryptMethod) == s_validIpEncryptMethods.end()) {
450
0
      throw std::runtime_error("Invalid IP Encryption method in RemoteLogResponseAction");
451
0
    }
452
453
0
    checkAllParametersConsumed("RemoteLogResponseAction", vars);
454
455
0
    return dnsdist::actions::getRemoteLogResponseAction(std::move(config));
456
0
  });
457
458
0
  luaCtx.writeFunction("DnstapLogAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::DnstapAlterFunction> alterFunc) {
459
0
    return dnsdist::actions::getDnstapLogAction(identity, std::move(logger), alterFunc ? std::move(*alterFunc) : std::optional<dnsdist::actions::DnstapAlterFunction>());
460
0
  });
461
462
0
  luaCtx.writeFunction("DnstapLogResponseAction", [](const std::string& identity, std::shared_ptr<RemoteLoggerInterface> logger, std::optional<dnsdist::actions::DnstapAlterResponseFunction> alterFunc) {
463
0
    return dnsdist::actions::getDnstapLogResponseAction(identity, std::move(logger), alterFunc ? std::move(*alterFunc) : std::optional<dnsdist::actions::DnstapAlterResponseFunction>());
464
0
  });
465
0
#endif /* DISABLE_PROTOBUF */
466
467
0
  luaCtx.writeFunction("TeeAction", [](const std::string& remote, std::optional<bool> addECS, std::optional<std::string> local, std::optional<bool> addProxyProtocol) {
468
0
    std::optional<ComboAddress> localAddr;
469
0
    if (local) {
470
0
      localAddr = ComboAddress(*local, 0);
471
0
    }
472
473
0
    return dnsdist::actions::getTeeAction(ComboAddress(remote, 53), localAddr, addECS ? *addECS : false, addProxyProtocol ? *addProxyProtocol : false);
474
0
  });
475
476
0
  luaCtx.writeFunction("SetECSAction", [](const std::string& v4Netmask, std::optional<std::string> v6Netmask) {
477
0
    if (v6Netmask) {
478
0
      return dnsdist::actions::getSetECSAction(v4Netmask, *v6Netmask);
479
0
    }
480
0
    return dnsdist::actions::getSetECSAction(v4Netmask);
481
0
  });
482
483
0
  luaCtx.writeFunction("ContinueAction", [](std::shared_ptr<DNSAction> action) {
484
0
    return dnsdist::actions::getContinueAction(std::move(action));
485
0
  });
486
487
#ifdef HAVE_DNS_OVER_HTTPS
488
  luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, std::optional<std::string> contentType, std::optional<responseParams_t> vars) {
489
    auto responseConfig = parseResponseConfig(vars);
490
    checkAllParametersConsumed("HTTPStatusAction", vars);
491
    auto ret = dnsdist::actions::getHTTPStatusAction(status, PacketBuffer(body.begin(), body.end()), contentType ? *contentType : "", responseConfig);
492
    return ret;
493
  });
494
#endif /* HAVE_DNS_OVER_HTTPS */
495
496
#if defined(HAVE_LMDB) || defined(HAVE_CDB)
497
  luaCtx.writeFunction("KeyValueStoreLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
498
    return dnsdist::actions::getKeyValueStoreLookupAction(kvs, lookupKey, destinationTag);
499
  });
500
501
  luaCtx.writeFunction("KeyValueStoreRangeLookupAction", [](std::shared_ptr<KeyValueStore>& kvs, std::shared_ptr<KeyValueLookupKey>& lookupKey, const std::string& destinationTag) {
502
    return dnsdist::actions::getKeyValueStoreRangeLookupAction(kvs, lookupKey, destinationTag);
503
  });
504
#endif /* defined(HAVE_LMDB) || defined(HAVE_CDB) */
505
506
0
  luaCtx.writeFunction("NegativeAndSOAAction", [](bool nxd, const std::string& zone, uint32_t ttl, const std::string& mname, const std::string& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum, std::optional<responseParams_t> vars) {
507
0
    bool soaInAuthoritySection = false;
508
0
    getOptionalValue<bool>(vars, "soaInAuthoritySection", soaInAuthoritySection);
509
0
    auto responseConfig = parseResponseConfig(vars);
510
0
    checkAllParametersConsumed("NegativeAndSOAAction", vars);
511
0
    dnsdist::actions::SOAParams params{
512
0
      .serial = serial,
513
0
      .refresh = refresh,
514
0
      .retry = retry,
515
0
      .expire = expire,
516
0
      .minimum = minimum};
517
0
    auto ret = dnsdist::actions::getNegativeAndSOAAction(nxd, DNSName(zone), ttl, DNSName(mname), DNSName(rname), params, soaInAuthoritySection, responseConfig);
518
0
    return ret;
519
0
  });
520
521
0
  luaCtx.writeFunction("SetProxyProtocolValuesAction", [](const std::vector<std::pair<uint8_t, std::string>>& values) {
522
0
    return dnsdist::actions::getSetProxyProtocolValuesAction(values);
523
0
  });
524
525
0
#include "dnsdist-lua-actions-generated-body.hh"
526
0
#include "dnsdist-lua-response-actions-generated-body.hh"
527
0
}