* nsec3dig: Calculate the correctness of NSEC3 proofs
* pdns_notify: Simple tool for sending DNS notifies
* saxfr: AXFR zones and show extra information
- * sdig: dig-like tool supporting DoH, DoT, PROXY-protocol and XPF
+ * sdig: dig-like tool supporting DoH, DoT and PROXY-protocol
* stubquery: Stub resolver query tool
Package: pdns-ixfrdist
dnsdist-tcp-upstream.hh \
dnsdist-tcp.cc dnsdist-tcp.hh \
dnsdist-web.cc dnsdist-web.hh \
- dnsdist-xpf.cc dnsdist-xpf.hh \
dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.cc dnsdist.hh \
dnslabeltext.cc \
threadname.hh threadname.cc \
uuid-utils.hh uuid-utils.cc \
views.hh \
- xpf.cc xpf.hh \
xsk.cc xsk.hh
testrunner_SOURCES = \
dnsdist-svc.cc dnsdist-svc.hh \
dnsdist-tcp-downstream.cc \
dnsdist-tcp.cc dnsdist-tcp.hh \
- dnsdist-xpf.cc dnsdist-xpf.hh \
dnsdist-xsk.cc dnsdist-xsk.hh \
dnsdist.hh \
dnslabeltext.cc \
testrunner.cc \
threadname.hh threadname.cc \
uuid-utils.hh uuid-utils.cc \
- xpf.cc xpf.hh \
xsk.cc xsk.hh
dnsdist_LDFLAGS = \
dnsdist_ffi_protocol_type dnsdist_ffi_dnsquestion_get_protocol(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_get_skip_cache(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_get_use_ecs(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
-bool dnsdist_ffi_dnsquestion_get_add_xpf(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
uint16_t dnsdist_ffi_dnsquestion_get_ecs_prefix_length(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
bool dnsdist_ffi_dnsquestion_is_temp_failure_ttl_set(const dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
return dq->dq->useECS;
}
-bool dnsdist_ffi_dnsquestion_get_add_xpf(const dnsdist_ffi_dnsquestion_t* dq)
-{
- return dq->dq->addXPF;
-}
-
bool dnsdist_ffi_dnsquestion_get_ecs_override(const dnsdist_ffi_dnsquestion_t* dq)
{
return dq->dq->ecsOverride;
getOptionalValue<bool>(vars, "disableZeroScope", config.disableZeroScope);
getOptionalValue<bool>(vars, "ipBindAddrNoPort", config.ipBindAddrNoPort);
- getOptionalIntegerValue("newServer", vars, "addXPF", config.xpfRRCode);
-
getOptionalValue<bool>(vars, "reconnectOnUp", config.reconnectOnUp);
LuaArray<string> cpuMap;
#include "dnsdist-tcp-downstream.hh"
#include "dnsdist-downstream-connection.hh"
#include "dnsdist-tcp-upstream.hh"
-#include "dnsdist-xpf.hh"
#include "dnsparser.hh"
#include "dolog.hh"
#include "gettime.hh"
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "dnsdist-xpf.hh"
-
-#include "dnsdist-dnsparser.hh"
-#include "dnsparser.hh"
-#include "xpf.hh"
-
-bool addXPF(DNSQuestion& dnsQuestion, uint16_t optionCode)
-{
- std::string payload = generateXPFPayload(dnsQuestion.overTCP(), dnsQuestion.ids.origRemote, dnsQuestion.ids.origDest);
- uint8_t root = '\0';
- dnsrecordheader drh{};
- drh.d_type = htons(optionCode);
- drh.d_class = htons(QClass::IN);
- drh.d_ttl = 0;
- drh.d_clen = htons(payload.size());
- size_t recordHeaderLen = sizeof(root) + sizeof(drh);
-
- if (!dnsQuestion.hasRoomFor(payload.size() + recordHeaderLen)) {
- return false;
- }
-
- size_t xpfSize = sizeof(root) + sizeof(drh) + payload.size();
- auto& data = dnsQuestion.getMutableData();
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- uint32_t realPacketLen = getDNSPacketLength(reinterpret_cast<const char*>(data.data()), data.size());
- data.resize(realPacketLen + xpfSize);
-
- size_t pos = realPacketLen;
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- memcpy(reinterpret_cast<char*>(&data.at(pos)), &root, sizeof(root));
- pos += sizeof(root);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- memcpy(reinterpret_cast<char*>(&data.at(pos)), &drh, sizeof(drh));
- pos += sizeof(drh);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- memcpy(reinterpret_cast<char*>(&data.at(pos)), payload.data(), payload.size());
- pos += payload.size();
- (void)pos;
-
- dnsdist::PacketMangling::editDNSHeaderFromPacket(dnsQuestion.getMutableData(), [](dnsheader& header) {
- header.arcount = htons(ntohs(header.arcount) + 1);
- return true;
- });
- return true;
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#pragma once
-
-#include "dnsdist.hh"
-
-bool addXPF(DNSQuestion& dnsQuestion, uint16_t optionCode);
#include "dnsdist-secpoll.hh"
#include "dnsdist-tcp.hh"
#include "dnsdist-web.hh"
-#include "dnsdist-xpf.hh"
#include "dnsdist-xsk.hh"
#include "base64.hh"
/* save the DNS flags as sent to the backend so we can cache the answer with the right flags later */
dnsQuestion.ids.cacheFlags = *getFlagsFromDNSHeader(dnsQuestion.getHeader().get());
- if (dnsQuestion.addXPF && selectedBackend->d_config.xpfRRCode != 0) {
- addXPF(dnsQuestion, selectedBackend->d_config.xpfRRCode);
- }
-
if (selectedBackend->d_config.useProxyProtocol && dnsQuestion.getProtocol().isEncrypted() && selectedBackend->d_config.d_proxyProtocolAdvertiseTLS) {
if (!dnsQuestion.proxyProtocolValues) {
dnsQuestion.proxyProtocolValues = std::make_unique<std::vector<ProxyProtocolValue>>();
uint8_t ednsRCode{0};
bool ecsOverride;
bool useECS{true};
- bool addXPF{true};
bool asynchronous{false};
};
QType checkType{QType::A};
uint16_t checkClass{QClass::IN};
uint16_t d_retries{5};
- uint16_t xpfRRCode{0};
uint16_t checkTimeout{1000}; /* in milliseconds */
uint16_t d_lazyHealthCheckSampleSize{100};
uint16_t d_lazyHealthCheckMinSampleCount{1};
In effect this means that for the EDNS Client Subnet option to be added to the request, ``useClientSubnet`` should be set to ``true`` for the backend used (default to ``false``) and ECS should not have been disabled by calling :func:`SetDisableECSAction` or setting ``dq.useECS`` to ``false`` (default to true).
-Note that any trailing data present in the incoming query is removed when an OPT (or XPF) record has to be inserted.
+Note that any trailing data present in the incoming query is removed when an OPT record has to be inserted.
In addition to the drawback that it can only pass the source IP address, and the fact that it needs to override any existing ECS option, adding that option requires parsing and editing the query, as well as parsing and editing the response in most cases.
| Response, EDNS with ECS | remove or edit the ECS option if needed |
+----------------------------+-------------------------------------------------+
-X-Proxied-For
--------------
-
-.. note::
- This is a deprecated feature that will be removed in the near future.
-
-The experimental XPF record (from `draft-bellis-dnsop-xpf <https://datatracker.ietf.org/doc/draft-bellis-dnsop-xpf/>`_) is an alternative to the use of EDNS Client Subnet which has the advantages of preserving any existing EDNS Client Subnet value sent by the client, and of passing along the original destination address, as well as the initial source and destination ports.
-
-In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``addXPF`` parameter can be used when creating a :func:`new server <newServer>`.
-This parameter indicates whether an XPF record shall be added to the query. Since that record is experimental, there is currently no option code assigned to it, and therefore one needs to be specified as an argument to the ``addXPF`` parameter.
-
-If the incoming request already contains a XPF record, it will not be overwritten. Instead a new one will be added to the query and the existing one will be preserved.
-That might be an issue by allowing clients to spoof their source address by adding a forged XPF record to their query. That can be prevented by using a rule to drop incoming queries containing a XPF record (in that example the 65280 option code has been assigned to XPF):
-
-.. code-block:: lua
-
- addAction(RecordsTypeCountRule(DNSSection.Additional, 65280, 1, 65535), DropAction())
-
Proxy Protocol
--------------
Both the PowerDNS Authoritative Server and the Recursor can parse PROXYv2 headers, if configured to do so with their `proxy-protocol-from` setting.
+X-Proxied-For
+-------------
+
+.. note::
+ XPF support has been removed in 2.0.0.
+
+The experimental XPF record (from `draft-bellis-dnsop-xpf <https://datatracker.ietf.org/doc/draft-bellis-dnsop-xpf/>`_) is an alternative to the use of EDNS Client Subnet which has the advantages of preserving any existing EDNS Client Subnet value sent by the client, and of passing along the original destination address, as well as the initial source and destination ports.
+
+In order to provide the downstream server with the address of the real client, or at least the one talking to dnsdist, the ``addXPF`` parameter can be used when creating a :func:`new server <newServer>`.
+This parameter indicates whether an XPF record shall be added to the query. Since that record is experimental, there is currently no option code assigned to it, and therefore one needs to be specified as an argument to the ``addXPF`` parameter.
+
+If the incoming request already contains a XPF record, it will not be overwritten. Instead a new one will be added to the query and the existing one will be preserved.
+That might be an issue by allowing clients to spoof their source address by adding a forged XPF record to their query. That can be prevented by using a rule to drop incoming queries containing a XPF record (in that example the 65280 option code has been assigned to XPF):
+
+.. code-block:: lua
+
+ addAction(RecordsTypeCountRule(DNSSection.Additional, 65280, 1, 65535), DropAction())
+
Influence on caching
--------------------
That feature is enabled by setting ``disableZeroScope=false`` on :func:`newServer` (default) and ``parseECS=true`` on :func:`newPacketCache` (not the default).
-Things are different for XPF and the proxy protocol, because dnsdist then does the cache lookup **before** adding the payload. It means that caching can still be enabled as long as the response is not source-dependent, but should be disabled otherwise.
+Things are different for the proxy protocol, because dnsdist then does the cache lookup **before** adding the payload. It means that caching can still be enabled as long as the response is not source-dependent, but should be disabled otherwise.
+------------------+----------+---------------------+----------------+------------------------+
| Protocol | Standard | Require DNS parsing | Contains ports | Caching |
+------------------+----------+---------------------+----------------+------------------------+
| ECS (zero-scope) | Yes | Query and response | No | Yes |
+------------------+----------+---------------------+----------------+------------------------+
-| XPF | No | Query | Yes | Depends on the backend |
-+------------------+----------+---------------------+----------------+------------------------+
| Proxy Protocol | No | No | Yes | Depends on the backend |
+------------------+----------+---------------------+----------------+------------------------+
.. versionchanged:: 1.9.0
Added ``MACAddr``, ``proxyProtocolAdvertiseTLS`` and ``xskSockets`` to server_table.
+ .. versionchanged:: 2.0.0
+ Removed ``addXPF`` from server_table.
+
:param str server_string: A simple IP:PORT string.
:param table server_table: A table with at least an ``address`` key
- address, e.g. ``""192.0.2.2""``
- interface name, e.g. ``""eth0""``
- address@interface, e.g. ``""192.0.2.2@eth0""`` "
- ``addXPF`` ``number`` "Add the client's IP address and port to the query, along with the original destination address and port, using the experimental XPF record from `draft-bellis-dnsop-xpf <https://datatracker.ietf.org/doc/draft-bellis-dnsop-xpf/>`_ and the specified option code. Default is disabled (0). This is a deprecated feature that will be removed in the near future."
``sockets`` ``number`` "Number of UDP sockets (and thus source ports) used toward the backend server, defaults to a single one. Note that for backends which are multithreaded, this setting will have an effect on the number of cores that will be used to process traffic from dnsdist. For example you may want to set 'sockets' to a number somewhat higher than the number of worker threads configured in the backend, particularly if the Linux kernel is being used to distribute traffic to multiple threads listening on the same socket (via `reuseport`). See also :func:`setRandomizedOutgoingSockets`."
``disableZeroScope`` ``bool`` "Disable the EDNS Client Subnet 'zero scope' feature, which does a cache lookup for an answer valid for all subnets (ECS scope of 0) before adding ECS information to the query and doing the regular lookup. This requires the ``parseECS`` option of the corresponding cache to be set to true"
``rise`` ``number`` "Require ``number`` consecutive successful checks before declaring the backend up, default: 1"
#include "dnsdist-metrics.hh"
#include "dnsdist-proxy-protocol.hh"
#include "dnsdist-rules.hh"
-#include "dnsdist-xpf.hh"
#include "libssl.hh"
#include "threadname.hh"
BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_use_ecs(&lightDQ), false);
}
- {
- BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_add_xpf(&lightDQ), true);
- }
-
{
BOOST_CHECK_EQUAL(dnsdist_ffi_dnsquestion_get_ecs_override(&lightDQ), false);
dnsdist_ffi_dnsquestion_set_ecs_override(&lightDQ, true);
#include "dnsdist-ecs.hh"
#include "dnsdist-internal-queries.hh"
#include "dnsdist-tcp.hh"
-#include "dnsdist-xpf.hh"
#include "dnsdist-xsk.hh"
#include "dolog.hh"
static const uint16_t ECSSourcePrefixV4 = 24;
static const uint16_t ECSSourcePrefixV6 = 56;
-static void validateQuery(const PacketBuffer& packet, bool hasEdns = true, bool hasXPF = false, uint16_t additionals = 0, uint16_t answers = 0, uint16_t authorities = 0)
+static void validateQuery(const PacketBuffer& packet, bool hasEdns = true, uint16_t additionals = 0, uint16_t answers = 0, uint16_t authorities = 0)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.ancount, answers);
BOOST_CHECK_EQUAL(mdp.d_header.nscount, authorities);
- uint16_t expectedARCount = additionals + (hasEdns ? 1U : 0U) + (hasXPF ? 1U : 0U);
+ uint16_t expectedARCount = additionals + (hasEdns ? 1U : 0U);
BOOST_CHECK_EQUAL(mdp.d_header.arcount, expectedARCount);
}
BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1U : 0U) + additionalCount);
}
-BOOST_AUTO_TEST_CASE(test_addXPF)
-{
- static const uint16_t xpfOptionCode = 65422;
-
- DNSName name("www.powerdns.com.");
- InternalQueryState ids;
- ids.protocol = dnsdist::Protocol::DoUDP;
- ids.origRemote = ComboAddress("::1");
- ids.origDest = ComboAddress("::1");
-
- PacketBuffer query;
- GenericDNSPacketWriter<PacketBuffer> packetWriter(query, name, QType::A, QClass::IN, 0);
- packetWriter.getHeader()->rd = 1;
- PacketBuffer queryWithXPF;
-
- {
- PacketBuffer packet = query;
-
- /* large enough packet */
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
- DNSQuestion dnsQuestion(ids, const_cast<PacketBuffer&>(packet));
- BOOST_CHECK_EQUAL(ids.qname, name);
- BOOST_CHECK(ids.qtype == QType::A);
-
- BOOST_CHECK(addXPF(dnsQuestion, xpfOptionCode));
- BOOST_CHECK(packet.size() > query.size());
- validateQuery(packet, false, true);
- queryWithXPF = packet;
- }
-
- {
- PacketBuffer packet = query;
-
- /* packet is already too large for the 4096 limit over UDP */
- packet.resize(4096);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
- DNSQuestion dnsQuestion(ids, const_cast<PacketBuffer&>(packet));
- BOOST_CHECK_EQUAL(ids.qname, name);
- BOOST_CHECK(ids.qtype == QType::A);
-
- BOOST_REQUIRE(!addXPF(dnsQuestion, xpfOptionCode));
- BOOST_CHECK_EQUAL(packet.size(), 4096U);
- packet.resize(query.size());
- validateQuery(packet, false, false);
- }
-
- {
- PacketBuffer packet = query;
-
- /* packet with trailing data (overriding it) */
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
- ids.qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &ids.qtype, &ids.qclass);
- // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
- DNSQuestion dnsQuestion(ids, const_cast<PacketBuffer&>(packet));
- BOOST_CHECK_EQUAL(ids.qname, name);
- BOOST_CHECK(ids.qtype == QType::A);
-
- /* add trailing data */
- const size_t trailingDataSize = 10;
- /* Making sure we have enough room to allow for fake trailing data */
- packet.resize(packet.size() + trailingDataSize);
- for (size_t idx = 0; idx < trailingDataSize; idx++) {
- packet.push_back('A');
- }
-
- BOOST_CHECK(addXPF(dnsQuestion, xpfOptionCode));
- BOOST_CHECK_EQUAL(packet.size(), queryWithXPF.size());
- BOOST_CHECK_EQUAL(memcmp(queryWithXPF.data(), packet.data(), queryWithXPF.size()), 0);
- validateQuery(packet, false, true);
- }
-}
-
BOOST_AUTO_TEST_CASE(addECSWithoutEDNS)
{
bool ednsAdded = false;
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, true);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, true, false, 0, 1);
+ validateQuery(packet, true, 0, 1);
validateECS(packet, remote);
PacketBuffer queryWithEDNS = packet;
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
packet.resize(query.size());
- validateQuery(packet, false, false, 0, 1);
+ validateQuery(packet, false, 0, 1);
/* packet with trailing data (overriding it) */
packet = query;
BOOST_CHECK_EQUAL(memcmp(queryWithEDNS.data(), packet.data(), queryWithEDNS.size()), 0);
BOOST_CHECK_EQUAL(ednsAdded, true);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, true, false, 0, 1);
+ validateQuery(packet, true, 0, 1);
}
BOOST_AUTO_TEST_CASE(addECSWithoutEDNSAlreadyParsed)
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 1);
+ validateQuery(packet, true, 1);
validateECS(packet, remote);
/* not large enough packet */
BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 1);
+ validateQuery(packet, true, 1);
}
BOOST_AUTO_TEST_CASE(replaceECSAfterAN)
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 0, 1, 0);
+ validateQuery(packet, true, 0, 1, 0);
validateECS(packet, remote);
/* not large enough packet */
BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 0, 1, 0);
+ validateQuery(packet, true, 0, 1, 0);
}
BOOST_AUTO_TEST_CASE(replaceECSAfterAuth)
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 0, 0, 1);
+ validateQuery(packet, true, 0, 0, 1);
validateECS(packet, remote);
/* not large enough packet */
BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 0, 0, 1);
+ validateQuery(packet, true, 0, 0, 1);
}
BOOST_AUTO_TEST_CASE(replaceECSBetweenTwoRecords)
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 2);
+ validateQuery(packet, true, 2);
validateECS(packet, remote);
/* not large enough packet */
BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 2);
+ validateQuery(packet, true, 2);
}
BOOST_AUTO_TEST_CASE(insertECSInEDNSBetweenTwoRecords)
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, true, false, 2);
+ validateQuery(packet, true, 2);
validateECS(packet, remote);
/* not large enough packet */
BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false, 2);
+ validateQuery(packet, true, 2);
}
BOOST_AUTO_TEST_CASE(insertECSAfterTSIG)
BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, true);
BOOST_CHECK_EQUAL(ecsAdded, true);
- /* the MOADNSParser does not allow anything except XPF after a TSIG */
- BOOST_CHECK_THROW(validateQuery(packet, true, false, 1), MOADNSException);
+ /* the MOADNSParser does not allow anything after a TSIG */
+ BOOST_CHECK_THROW(validateQuery(packet, true, 1), MOADNSException);
validateECS(packet, remote);
/* not large enough packet */
BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, true, false);
+ validateQuery(packet, true);
}
BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst)
+++ /dev/null
-../xpf.cc
\ No newline at end of file
+++ /dev/null
-../xpf.hh
\ No newline at end of file
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
-#include <iostream>
+#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
#include <boost/functional/hash.hpp>
bool DNSPacket::s_doEDNSCookieProcessing;
string DNSPacket::s_EDNSCookieKey;
uint16_t DNSPacket::s_udpTruncationThreshold;
-
+
DNSPacket::DNSPacket(bool isQuery): d_isQuery(isQuery)
{
memset(&d, 0, sizeof(d));
if(b) {
d_rawpacket.assign(12,(char)0);
memset((void *)&d,0,sizeof(d));
-
+
d.qr=b;
}
}
pw.getHeader()->id=d.id;
pw.getHeader()->rd=d.rd;
pw.getHeader()->tc=d.tc;
-
+
DNSPacketWriter::optvect_t opts;
/* optsize is expected to hold an upper bound of data that will be
- added after actual record data - i.e. OPT, TSIG, perhaps one day
- XPF. Because of the way `pw` incrementally writes the packet, we
+ added after actual record data - i.e. OPT, TSIG.
+ Because of the way `pw` incrementally writes the packet, we
cannot easily 'go back' and remove a few records. So, to prevent
going over our maximum size, we keep our (potential) extra data
in mind.
if(!d_rrs.empty()) pw.commit();
noCommit:;
-
+
if(d_haveednssubnet) {
EDNSSubnetOpts eso = d_eso;
// use the scopeMask from the resolver, if it is greater - issue #5469
maxScopeMask = max(maxScopeMask, eso.scope.getBits());
eso.scope = Netmask(eso.source.getNetwork(), maxScopeMask);
-
+
string opt = makeEDNSSubnetOptsString(eso);
opts.emplace_back(8, opt); // 'EDNS SUBNET'
}
throw;
}
}
-
+
if(d_trc.d_algoName.countLabels())
addTSIG(pw, d_trc, d_tsigkeyname, d_tsigsecret, d_tsigprevious, d_tsigtimersonly);
-
+
d_rawpacket.assign((char*)&packet[0], packet.size()); // XXX we could do this natively on a vector..
// copy RR counts so they can be read later
r->setAnswer(true); // this implies the allocation of the header
r->setA(true); // and we are authoritative
r->setRA(false); // no recursion available
- r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it
+ r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it
r->setID(d.id);
r->setOpcode(d.opcode);
void DNSPacket::spoofQuestion(const DNSPacket& qd)
{
d_wrapped=true; // if we do this, don't later on wrapup
-
+
int labellen;
string::size_type i=sizeof(d);
int DNSPacket::noparse(const char *mesg, size_t length)
{
- d_rawpacket.assign(mesg,length);
- if(length < 12) {
+ d_rawpacket.assign(mesg,length);
+ if(length < 12) {
g_log << Logger::Debug << "Ignoring packet: too short ("<<length<<" < 12) from "
<< getRemoteStringWithPort();
return -1;
int DNSPacket::parse(const char *mesg, size_t length)
try
{
- d_rawpacket.assign(mesg,length);
+ d_rawpacket.assign(mesg,length);
d_wrapped=true;
- if(length < 12) {
+ if(length < 12) {
g_log << Logger::Debug << "Ignoring packet: too short from "
<< getRemoteString() << endl;
return -1;
if(getEDNSSubnetOptsFromString(option.second, &d_eso)) {
//cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
d_haveednssubnet=true;
- }
+ }
}
else if (s_doEDNSCookieProcessing && option.first == EDNSOptionCode::COOKIE) {
d_haveednscookie = true;
return -1;
}
}
-
+
qtype=mdp.d_qtype;
qclass=mdp.d_qclass;
}
}
#endif
-
dr.setContent(DNSRecordContent::make(dr, pr, d_header.opcode));
}
- /* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned:
- if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG && dr.d_type != QType::XPF)
- */
if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG) {
- /* only XPF records are allowed after a TSIG */
throw MOADNSException("Packet ("+d_qname.toString()+"|#"+std::to_string(d_qtype)+") has an unexpected record ("+std::to_string(dr.d_type)+") after a TSIG one.");
}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "xpf.hh"
-
-std::string generateXPFPayload(bool tcp, const ComboAddress& source, const ComboAddress& destination)
-{
- if (source.sin4.sin_family != destination.sin4.sin_family) {
- throw std::runtime_error("The XPF destination and source addresses must be of the same family");
- }
-
- std::string ret;
- const uint8_t version = source.isIPv4() ? 4 : 6;
- const uint8_t protocol = tcp ? 6 : 17;
- const size_t addrSize = source.isIPv4() ? sizeof(source.sin4.sin_addr.s_addr) : sizeof(source.sin6.sin6_addr.s6_addr);
- const uint16_t sourcePort = source.sin4.sin_port;
- const uint16_t destinationPort = destination.sin4.sin_port;
-
- ret.reserve(sizeof(version) + sizeof(protocol) + (addrSize * 2) + sizeof(sourcePort) + sizeof(destinationPort));
-
- ret.append(reinterpret_cast<const char*>(&version), sizeof(version));
- ret.append(reinterpret_cast<const char*>(&protocol), sizeof(protocol));
-
- // We already established source and destination sin_family equivalence
- if (source.isIPv4()) {
- assert(addrSize == sizeof(source.sin4.sin_addr.s_addr));
- ret.append(reinterpret_cast<const char*>(&source.sin4.sin_addr.s_addr), addrSize);
- assert(addrSize == sizeof(destination.sin4.sin_addr.s_addr));
- ret.append(reinterpret_cast<const char*>(&destination.sin4.sin_addr.s_addr), addrSize);
- }
- else {
- assert(addrSize == sizeof(source.sin6.sin6_addr.s6_addr));
- ret.append(reinterpret_cast<const char*>(&source.sin6.sin6_addr.s6_addr), addrSize);
- assert(addrSize == sizeof(destination.sin6.sin6_addr.s6_addr));
- ret.append(reinterpret_cast<const char*>(&destination.sin6.sin6_addr.s6_addr), addrSize);
- }
-
- ret.append(reinterpret_cast<const char*>(&sourcePort), sizeof(sourcePort));
- ret.append(reinterpret_cast<const char*>(&destinationPort), sizeof(destinationPort));
-
- return ret;
-}
-
-bool parseXPFPayload(const char* payload, size_t len, ComboAddress& source, ComboAddress* destination)
-{
- static const size_t addr4Size = sizeof(source.sin4.sin_addr.s_addr);
- static const size_t addr6Size = sizeof(source.sin6.sin6_addr.s6_addr);
- uint8_t version;
- uint8_t protocol;
- uint16_t sourcePort;
- uint16_t destinationPort;
-
- if (len != (sizeof(version) + sizeof(protocol) + (addr4Size * 2) + sizeof(sourcePort) + sizeof(destinationPort)) &&
- len != (sizeof(version) + sizeof(protocol) + (addr6Size * 2) + sizeof(sourcePort) + sizeof(destinationPort))) {
- return false;
- }
-
- size_t pos = 0;
-
- memcpy(&version, payload + pos, sizeof(version));
- pos += sizeof(version);
-
- if (version != 4 && version != 6) {
- return false;
- }
-
- memcpy(&protocol, payload + pos, sizeof(protocol));
- pos += sizeof(protocol);
-
- if (protocol != 6 && protocol != 17) {
- return false;
- }
-
- const size_t addrSize = version == 4 ? sizeof(source.sin4.sin_addr.s_addr) : sizeof(source.sin6.sin6_addr.s6_addr);
- if (len - pos != ((addrSize * 2) + sizeof(sourcePort) + sizeof(destinationPort))) {
- return false;
- }
-
- source = makeComboAddressFromRaw(version, payload + pos, addrSize);
- pos += addrSize;
- if (destination != nullptr) {
- *destination = makeComboAddressFromRaw(version, payload + pos, addrSize);
- }
- pos += addrSize;
-
- memcpy(&sourcePort, payload + pos, sizeof(sourcePort));
- pos += sizeof(sourcePort);
- source.sin4.sin_port = sourcePort;
-
- memcpy(&destinationPort, payload + pos, sizeof(destinationPort));
- pos += sizeof(destinationPort);
- (void) pos;
-
- if (destination != nullptr) {
- destination->sin4.sin_port = destinationPort;
- }
-
- return true;
-}
+++ /dev/null
-/*
- * This file is part of PowerDNS or dnsdist.
- * Copyright -- PowerDNS.COM B.V. and its contributors
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * In addition, for the avoidance of any doubt, permission is granted to
- * link this program with OpenSSL and to (re)distribute the binaries
- * produced as the result of such linking.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#pragma once
-
-#include <iputils.hh>
-
-std::string generateXPFPayload(bool tcp, const ComboAddress& source, const ComboAddress& destination);
-bool parseXPFPayload(const char* payload, size_t len, ComboAddress& source, ComboAddress* destination);
-
+++ /dev/null
-#!/usr/bin/env python
-
-import dns
-from dnsdisttests import DNSDistTest
-
-class XPFTest(DNSDistTest):
- """
- dnsdist is configured to add XPF to the query
- """
-
- _xpfCode = 65422
- _config_template = """
- newServer{address="127.0.0.1:%d", addXPF=%d}
- """
- _config_params = ['_testServerPort', '_xpfCode']
-
- def checkMessageHasXPF(self, msg, expectedValue):
- self.assertGreaterEqual(len(msg.additional), 1)
-
- found = False
- for add in msg.additional:
- if add.rdtype == self._xpfCode:
- found = True
- self.assertEqual(add.rdclass, dns.rdataclass.IN)
- self.assertEqual(add.ttl, 0)
- xpfData = add.to_rdataset()[0].to_text()
- # skip the ports
- self.assertEqual(xpfData[:26], expectedValue[:26])
-
- self.assertTrue(found)
-
- def testXPF(self):
- """
- XPF
- """
- name = 'xpf.tests.powerdns.com.'
- query = dns.message.make_query(name, 'A', 'IN')
-
- expectedQuery = dns.message.make_query(name, 'A', 'IN')
- # 0x04 is IPv4, 0x11 (17) is UDP then 127.0.0.1 as source and destination
- # and finally the ports, zeroed because we have no way to know them beforehand
- xpfData = "\\# 14 04117f0000017f00000100000000"
- rdata = dns.rdata.from_text(dns.rdataclass.IN, self._xpfCode, xpfData)
- rrset = dns.rrset.from_rdata(".", 0, rdata)
- expectedQuery.additional.append(rrset)
-
- response = dns.message.make_response(expectedQuery)
-
- (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
- self.assertTrue(receivedQuery)
- self.assertTrue(receivedResponse)
- receivedQuery.id = expectedQuery.id
- receivedResponse.id = response.id
-
- self.checkMessageHasXPF(receivedQuery, xpfData)
- self.assertEqual(response, receivedResponse)
-
- expectedQuery = dns.message.make_query(name, 'A', 'IN')
- # 0x04 is IPv4, 0x06 (6) is TCP then 127.0.0.1 as source and destination
- # and finally the ports, zeroed because we have no way to know them beforehand
- xpfData = "\\# 14 04067f0000017f00000100000000"
- rdata = dns.rdata.from_text(dns.rdataclass.IN, self._xpfCode, xpfData)
- rrset = dns.rrset.from_rdata(".", 0, rdata)
- expectedQuery.additional.append(rrset)
-
- response = dns.message.make_response(expectedQuery)
-
- (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
- self.assertTrue(receivedQuery)
- self.assertTrue(receivedResponse)
- receivedQuery.id = expectedQuery.id
- receivedResponse.id = response.id
-
- self.checkMessageHasXPF(receivedQuery, xpfData)
- self.assertEqual(response, receivedResponse)