type: "String"
description: "The EDNS0 option raw content"
- name: "SetExtendedDNSError"
+ description: "Set an Extended DNS Error status that will be set to the response corresponding to the current query. This will clear any previously set Extended DNS Errors. Subsequent rules are processed after this action"
+ parameters:
+ - name: "info_code"
+ type: "u16"
+ description: "The EDNS Extended DNS Error code"
+ - name: "extra_text"
+ type: "String"
+ default: ""
+ optional: false
+ description: "The optional EDNS Extended DNS Error extra text"
+- name: "AddExtendedDNSError"
description: "Set an Extended DNS Error status that will be added to the response corresponding to the current query. Subsequent rules are processed after this action"
parameters:
- name: "info_code"
PacketBuffer newContent;
newContent.reserve(dnsquestion->getData().size());
- if (!slowRewriteEDNSOptionInQueryWithRecords(dnsquestion->getData(), newContent, ednsAdded, d_code, optionAdded, true, optRData)) {
+ if (!slowRewriteEDNSOptionInQueryWithRecords(dnsquestion->getData(), newContent, ednsAdded, d_code, optionAdded, true, false, optRData)) {
return Action::None;
}
DNSAction::Action operator()(DNSQuestion* dnsQuestion, std::string* ruleresult) const override
{
(void)ruleresult;
- dnsQuestion->ids.d_extendedError = std::make_unique<EDNSExtendedError>(d_ede);
+ dnsQuestion->ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({d_ede}));
return DNSAction::Action::None;
}
DNSResponseAction::Action operator()(DNSResponse* dnsResponse, std::string* ruleresult) const override
{
(void)ruleresult;
- dnsResponse->ids.d_extendedError = std::make_unique<EDNSExtendedError>(d_ede);
+ dnsResponse->ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({d_ede}));
return DNSResponseAction::Action::None;
}
EDNSExtendedError d_ede;
};
+class AddExtendedDNSErrorAction : public DNSAction
+{
+public:
+ // this action does not stop the processing
+ AddExtendedDNSErrorAction(uint16_t infoCode, const std::string& extraText)
+ {
+ d_ede.infoCode = infoCode;
+ d_ede.extraText = extraText;
+ }
+
+ DNSAction::Action operator()(DNSQuestion* dnsQuestion, std::string* ruleresult) const override
+ {
+ (void)ruleresult;
+ if (!dnsQuestion->ids.d_extendedErrors) {
+ dnsQuestion->ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({d_ede}));
+ }
+ else {
+ dnsQuestion->ids.d_extendedErrors->emplace_back(d_ede);
+ }
+
+ return DNSAction::Action::None;
+ }
+
+ [[nodiscard]] std::string toString() const override
+ {
+ return "add EDNS Extended DNS Error to " + std::to_string(d_ede.infoCode) + (d_ede.extraText.empty() ? std::string() : std::string(": \"") + d_ede.extraText + std::string("\""));
+ }
+
+private:
+ EDNSExtendedError d_ede;
+};
+
+class AddExtendedDNSErrorResponseAction : public DNSResponseAction
+{
+public:
+ // this action does not stop the processing
+ AddExtendedDNSErrorResponseAction(uint16_t infoCode, const std::string& extraText)
+ {
+ d_ede.infoCode = infoCode;
+ d_ede.extraText = extraText;
+ }
+
+ DNSResponseAction::Action operator()(DNSResponse* dnsResponse, std::string* ruleresult) const override
+ {
+ (void)ruleresult;
+ if (!dnsResponse->ids.d_extendedErrors) {
+ dnsResponse->ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({d_ede}));
+ }
+ else {
+ dnsResponse->ids.d_extendedErrors->emplace_back(d_ede);
+ }
+
+ return DNSResponseAction::Action::None;
+ }
+
+ [[nodiscard]] std::string toString() const override
+ {
+ return "add EDNS Extended DNS Error to " + std::to_string(d_ede.infoCode) + (d_ede.extraText.empty() ? std::string() : std::string(": \"") + d_ede.extraText + std::string("\""));
+ }
+
+private:
+ EDNSExtendedError d_ede;
+};
+
class LimitTTLResponseAction : public DNSResponseAction, public boost::noncopyable
{
public:
{"addDynamicBlock", true, "address, message[, action [, seconds [, clientIPMask [, clientIPPortMask]]]]", "block the supplied address with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)"},
{"addDynBlocks", true, "addresses, message[, seconds[, action]]", "block the set of addresses with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)"},
{"addDynBlockSMT", true, "names, message[, seconds [, action]]", "block the set of names with message `msg`, for `seconds` seconds (10 by default), applying `action` (default to the one set with `setDynBlocksAction()`)"},
+ {"AddExtendedDNSErrorAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to the response corresponding to the current query. Subsequent rules are processed after this action"},
+ {"AddExtendedDNSErrorResponseAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to this response. Subsequent rules are processed after this action"},
{"addLocal", true, R"(addr [, {doTCP=true, reusePort=false, tcpFastOpenQueueSize=0, interface="", cpus={}}])", "add `addr` to the list of addresses we listen on"},
{"addMaintenanceCallback", true, "callback", "register a function to be called as part of the maintenance hook, every second"},
{"addExitCallback", true, "callback", "register a function to be called when DNSdist exits"},
{"SetMacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action"},
{"SetEDNSOptionAction", true, "option, data", "Add arbitrary EDNS option and data to the query. Subsequent rules are processed after this action"},
{"SetEDNSOptionResponseAction", true, "option, data", "Add arbitrary EDNS option and data to the response. Subsequent rules are processed after this action"},
- {"SetExtendedDNSErrorAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to the response corresponding to the current query. Subsequent rules are processed after this action"},
- {"SetExtendedDNSErrorResponseAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be added to this response. Subsequent rules are processed after this action"},
+ {"SetExtendedDNSErrorAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be set to the response corresponding to the current query. This will clear any previously set Extended DNS Errors. Subsequent rules are processed after this action"},
+ {"SetExtendedDNSErrorResponseAction", true, "infoCode [, extraText]", "Set an Extended DNS Error status that will be set to this response. This will clear any previously set Extended DNS Errors. Subsequent rules are processed after this action"},
{"SetNoRecurseAction", true, "", "strip RD bit from the question, let it go through"},
{"setOutgoingDoHWorkerThreads", true, "n", "Number of outgoing DoH worker threads"},
{"SetProxyProtocolValuesAction", true, "values", "Set the Proxy-Protocol values for this queries to 'values'"},
return 0;
}
-static bool addOrReplaceEDNSOption(std::vector<std::pair<uint16_t, std::string>>& options, uint16_t optionCode, bool& optionAdded, bool overrideExisting, const string& newOptionContent)
+static bool addOrReplaceEDNSOption(std::vector<std::pair<uint16_t, std::string>>& options, uint16_t optionCode, bool& optionAdded, bool overrideExisting, bool allowMultiple, const string& newOptionContent)
{
- for (auto it = options.begin(); it != options.end();) {
- if (it->first == optionCode) {
- optionAdded = false;
+ if (!allowMultiple) {
+ for (auto it = options.begin(); it != options.end();) {
+ if (it->first == optionCode) {
+ optionAdded = false;
- if (!overrideExisting) {
- return false;
- }
+ if (!overrideExisting) {
+ return false;
+ }
- it = options.erase(it);
- }
- else {
- ++it;
+ it = options.erase(it);
+ }
+ else {
+ ++it;
+ }
}
}
return true;
}
-bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent)
+bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, bool allowMultiple, const string& newOptionContent)
{
if (initialPacket.size() < sizeof(dnsheader)) {
return false;
/* addOrReplaceEDNSOption will set it to false if there is already an existing option */
optionAdded = true;
- addOrReplaceEDNSOption(options, optionToReplace, optionAdded, overrideExisting, newOptionContent);
+ addOrReplaceEDNSOption(options, optionToReplace, optionAdded, overrideExisting, allowMultiple, newOptionContent);
packetWriter.addOpt(recordHeader.d_class, edns0.extRCode, ntohs(edns0.extFlags), options, edns0.version);
}
}
PacketBuffer newContent;
newContent.reserve(packet.size());
- if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::ECS, ecsAdded, overrideExisting, newECSOption)) {
+ if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::ECS, ecsAdded, overrideExisting, false, newECSOption)) {
return false;
}
PacketBuffer newContent;
newContent.reserve(dnsQuestion.getData().size());
- if (!slowRewriteEDNSOptionInQueryWithRecords(dnsQuestion.getData(), newContent, ednsAdded, ednsCode, optionAdded, true, optRData)) {
+ if (!slowRewriteEDNSOptionInQueryWithRecords(dnsQuestion.getData(), newContent, ednsAdded, ednsCode, optionAdded, true, false, optRData)) {
return false;
}
static const size_t optRecordMinimumSize = 11;
int rewriteResponseWithoutEDNS(const PacketBuffer& initialPacket, PacketBuffer& newContent);
-bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, const string& newOptionContent);
+bool slowRewriteEDNSOptionInQueryWithRecords(const PacketBuffer& initialPacket, PacketBuffer& newContent, bool& ednsAdded, uint16_t optionToReplace, bool& optionAdded, bool overrideExisting, bool allowMultiple, const string& newOptionContent);
int locateEDNSOptRR(const PacketBuffer& packet, uint16_t* optStart, size_t* optLen, bool* last);
bool generateOptRR(const std::string& optRData, PacketBuffer& res, size_t maximumSize, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK);
void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength);
PacketBuffer newContent;
bool ednsAdded = false;
bool edeAdded = false;
- if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::EXTENDEDERROR, edeAdded, true, edeOption)) {
+ if (!slowRewriteEDNSOptionInQueryWithRecords(packet, newContent, ednsAdded, EDNSOptionCode::EXTENDEDERROR, edeAdded, false, true, edeOption)) {
return false;
}
#ifndef DISABLE_PROTOBUF
std::vector<std::pair<std::string, std::shared_ptr<RemoteLoggerInterface>>> delayedResponseMsgs;
#endif
- std::unique_ptr<EDNSExtendedError> d_extendedError{nullptr};
+ std::unique_ptr<std::vector<EDNSExtendedError>> d_extendedErrors{nullptr};
std::optional<uint32_t> tempFailureTTL{std::nullopt}; // 8
ClientState* cs{nullptr}; // 8
std::unique_ptr<DOHUnitInterface> du; // 8
if (extraText) {
ede.extraText = *extraText;
}
- dnsQuestion.ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ dnsQuestion.ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({ede}));
+ });
+
+ luaCtx.registerFunction<void (DNSQuestion::*)(uint16_t infoCode, const std::optional<std::string>& extraText)>("addExtendedDNSError", [](DNSQuestion& dnsQuestion, uint16_t infoCode, const std::optional<std::string>& extraText) {
+ EDNSExtendedError ede;
+ ede.infoCode = infoCode;
+ if (extraText) {
+ ede.extraText = *extraText;
+ }
+ if (!dnsQuestion.ids.d_extendedErrors) {
+ dnsQuestion.ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({ede}));
+ }
+ else {
+ dnsQuestion.ids.d_extendedErrors->emplace_back(ede);
+ }
});
luaCtx.registerFunction<bool (DNSQuestion::*)(uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)>("suspend", [](DNSQuestion& dnsQuestion, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs) {
if (extraText) {
ede.extraText = *extraText;
}
- dnsResponse.ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ dnsResponse.ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({ede}));
});
luaCtx.registerFunction<bool (DNSResponse::*)(uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs)>("suspend", [](DNSResponse& dnsResponse, uint16_t asyncID, uint16_t queryID, uint32_t timeoutMs) {
if (extraText != nullptr && extraTextSize > 0) {
ede.extraText = std::string(extraText, extraTextSize);
}
- dnsQuestion->dq->ids.d_extendedError = std::make_unique<EDNSExtendedError>(ede);
+ dnsQuestion->dq->ids.d_extendedErrors = std::make_unique<std::vector<EDNSExtendedError>>(std::initializer_list<EDNSExtendedError>({ede}));
}
void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
type: "String"
description: "The EDNS0 option raw content"
- name: "SetExtendedDNSError"
+ description: "Set an Extended DNS Error status that will be set to the response. This will clear any previously set Extended DNS Errors. Subsequent rules are processed after this action"
+ parameters:
+ - name: "info_code"
+ type: "u16"
+ description: "The EDNS Extended DNS Error code"
+ - name: "extra_text"
+ type: "String"
+ default: ""
+ optional: false
+ description: "The optional EDNS Extended DNS Error extra text"
+- name: "AddExtendedDNSError"
description: "Set an Extended DNS Error status that will be added to the response. Subsequent rules are processed after this action"
parameters:
- name: "info_code"
return true;
}
- if (dnsResponse.ids.d_extendedError) {
- dnsdist::edns::addExtendedDNSError(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.d_extendedError->infoCode, dnsResponse.ids.d_extendedError->extraText);
+ if (dnsResponse.ids.d_extendedErrors) {
+ for (auto ede : *dnsResponse.ids.d_extendedErrors) {
+ dnsdist::edns::addExtendedDNSError(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), ede.infoCode, ede.extraText);
+ }
}
return true;
dnsdist::PacketMangling::restrictDNSPacketTTLs(dnsResponse.getMutableData(), 0, dnsResponse.ids.ttlCap);
}
- if (dnsResponse.ids.d_extendedError) {
- dnsdist::edns::addExtendedDNSError(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.d_extendedError->infoCode, dnsResponse.ids.d_extendedError->extraText);
+ if (dnsResponse.ids.d_extendedErrors) {
+ for (auto ede : *dnsResponse.ids.d_extendedErrors) {
+ dnsdist::edns::addExtendedDNSError(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), ede.infoCode, ede.extraText);
+ }
}
#ifdef HAVE_DNSCRYPT
dnsdist::PacketMangling::restrictDNSPacketTTLs(dnsResponse.getMutableData(), 0, dnsResponse.ids.ttlCap);
}
- if (dnsResponse.ids.d_extendedError) {
- dnsdist::edns::addExtendedDNSError(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), dnsResponse.ids.d_extendedError->infoCode, dnsResponse.ids.d_extendedError->extraText);
+ if (dnsResponse.ids.d_extendedErrors) {
+ for (auto ede : *dnsResponse.ids.d_extendedErrors) {
+ dnsdist::edns::addExtendedDNSError(dnsResponse.getMutableData(), dnsResponse.getMaximumSize(), ede.infoCode, ede.extraText);
+ }
}
if (cacheHit) {
The following actions exist.
+.. function:: AddExtendedDNSErrorAction(infoCode [, extraText])
+
+ .. versionadded:: 2.1.0
+
+ Set an Extended DNS Error status that will be added to the response corresponding to the current query.
+ Subsequent rules are processed after this action.
+
+ :param int infoCode: The EDNS Extended DNS Error code
+ :param string extraText: The optional EDNS Extended DNS Error extra text
+
+.. function:: AddExtendedDNSErrorResponseAction(infoCode [, extraText])
+
+ .. versionadded:: 2.1.0
+
+ Set an Extended DNS Error status that will be added to this response.
+ Subsequent rules are processed after this action.
+
+ :param int infoCode: The EDNS Extended DNS Error code
+ :param string extraText: The optional EDNS Extended DNS Error extra text
+
.. function:: AllowAction()
Let these packets go through.
.. versionadded:: 1.9.0
- Set an Extended DNS Error status that will be added to the response corresponding to the current query.
- Subsequent rules are processed after this action.
+ Set an Extended DNS Error status that will be set to the response corresponding to the current query.
+ This will clear any previously set Extended DNS Errors. Subsequent rules are processed after this action.
:param int infoCode: The EDNS Extended DNS Error code
:param string extraText: The optional EDNS Extended DNS Error extra text
.. versionadded:: 1.9.0
- Set an Extended DNS Error status that will be added to this response.
- Subsequent rules are processed after this action.
+ Set an Extended DNS Error status that will be set to this response.
+ This will clear any previously set Extended DNS Errors. Subsequent rules are processed after this action.
:param int infoCode: The EDNS Extended DNS Error code
:param string extraText: The optional EDNS Extended DNS Error extra text