throw std::runtime_error("No inactive certificate found with this serial");
}
-bool DNSCryptQuery::parsePlaintextQuery(const char * packet, uint16_t packetSize)
+bool DNSCryptQuery::parsePlaintextQuery(const std::vector<uint8_t>& packet)
{
assert(d_ctx != nullptr);
- if (packetSize < sizeof(dnsheader)) {
+ if (packet.size() < sizeof(dnsheader)) {
return false;
}
- const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet);
+ const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet.data());
if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query)
return false;
- unsigned int consumed;
+ unsigned int qnameWireLength;
uint16_t qtype, qclass;
- DNSName qname(packet, packetSize, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- if ((packetSize - sizeof(dnsheader)) < (consumed + sizeof(qtype) + sizeof(qclass)))
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength);
+ if ((packet.size() - sizeof(dnsheader)) < (qnameWireLength + sizeof(qtype) + sizeof(qclass))) {
return false;
+ }
- if (qtype != QType::TXT || qclass != QClass::IN)
+ if (qtype != QType::TXT || qclass != QClass::IN) {
return false;
+ }
- if (qname != d_ctx->getProviderName())
+ if (qname != d_ctx->getProviderName()) {
return false;
+ }
d_qname = qname;
d_id = dh->id;
return false;
}
-bool DNSCryptQuery::isEncryptedQuery(const char * packet, uint16_t packetSize, bool tcp, time_t now)
+bool DNSCryptQuery::isEncryptedQuery(const std::vector<uint8_t>& packet, bool tcp, time_t now)
{
assert(d_ctx != nullptr);
d_encrypted = false;
- if (packetSize < sizeof(DNSCryptQueryHeader)) {
+ if (packet.size() < sizeof(DNSCryptQueryHeader)) {
return false;
}
- if (!tcp && packetSize < DNSCryptQuery::s_minUDPLength) {
+ if (!tcp && packet.size() < DNSCryptQuery::s_minUDPLength) {
return false;
}
- const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet);
+ const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet.data());
d_header = *header;
return true;
}
-void DNSCryptQuery::getDecrypted(bool tcp, char* packet, uint16_t packetSize, uint16_t* decryptedQueryLen)
+void DNSCryptQuery::getDecrypted(bool tcp, std::vector<uint8_t>& packet)
{
- assert(decryptedQueryLen != nullptr);
assert(d_encrypted);
assert(d_pair != nullptr);
assert(d_valid == false);
#ifdef DNSCRYPT_STRICT_PADDING_LENGTH
- if (tcp && ((packetSize - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) {
- vinfolog("Dropping encrypted query with invalid size of %d (should be a multiple of %d)", (packetSize - sizeof(DNSCryptQueryHeader)), DNSCRYPT_PADDED_BLOCK_SIZE);
+ if (tcp && ((packet.size() - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) {
+ vinfolog("Dropping encrypted query with invalid size of %d (should be a multiple of %d)", (packet.size() - sizeof(DNSCryptQueryHeader)), DNSCRYPT_PADDED_BLOCK_SIZE);
return;
}
#endif
const DNSCryptExchangeVersion version = getVersion();
if (version == DNSCryptExchangeVersion::VERSION1) {
- res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet),
- reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
- packetSize - sizeof(DNSCryptQueryHeader),
+ res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()),
+ reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
+ packet.size() - sizeof(DNSCryptQueryHeader),
nonce,
d_sharedKey);
}
else if (version == DNSCryptExchangeVersion::VERSION2) {
#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
- res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet),
- reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
- packetSize - sizeof(DNSCryptQueryHeader),
+ res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()),
+ reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
+ packet.size() - sizeof(DNSCryptQueryHeader),
nonce,
d_sharedKey);
#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
}
#else /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
- int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet),
- reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
- packetSize - sizeof(DNSCryptQueryHeader),
+ int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet.data()),
+ reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
+ packet.size() - sizeof(DNSCryptQueryHeader),
nonce,
d_header.clientPK,
d_pair->privateKey.key);
return;
}
- *decryptedQueryLen = packetSize - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE;
- uint16_t pos = *decryptedQueryLen;
- assert(pos < packetSize);
- d_paddedLen = *decryptedQueryLen;
+ uint16_t decryptedQueryLen = packet.size() - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE;
+ uint16_t pos = decryptedQueryLen;
+ assert(pos < packet.size());
+ d_paddedLen = decryptedQueryLen;
- while(pos > 0 && packet[pos - 1] == 0) pos--;
+ while (pos > 0 && packet.at(pos - 1) == 0) pos--;
- if (pos == 0 || static_cast<uint8_t>(packet[pos - 1]) != 0x80) {
+ if (pos == 0 || packet.at(pos - 1) != 0x80) {
vinfolog("Dropping encrypted query with invalid padding value");
return;
}
pos--;
- size_t paddingLen = *decryptedQueryLen - pos;
- *decryptedQueryLen = pos;
+ size_t paddingLen = decryptedQueryLen - pos;
+ packet.resize(pos);
if (tcp && paddingLen > DNSCRYPT_MAX_TCP_PADDING_SIZE) {
vinfolog("Dropping encrypted query with too long padding size");
d_ctx->getCertificateResponse(now, d_qname, d_id, response);
}
-void DNSCryptQuery::parsePacket(char* packet, uint16_t packetSize, bool tcp, uint16_t* decryptedQueryLen, time_t now)
+void DNSCryptQuery::parsePacket(std::vector<uint8_t>& packet, bool tcp, time_t now)
{
- assert(packet != nullptr);
- assert(decryptedQueryLen != nullptr);
-
d_valid = false;
/* might be a plaintext certificate request or an authenticated request */
- if (isEncryptedQuery(packet, packetSize, tcp, now)) {
- getDecrypted(tcp, packet, packetSize, decryptedQueryLen);
+ if (isEncryptedQuery(packet, tcp, now)) {
+ getDecrypted(tcp, packet);
}
else {
- parsePlaintextQuery(packet, packetSize);
+ parsePlaintextQuery(packet);
}
}
return result;
}
-int DNSCryptQuery::encryptResponse(char* response, uint16_t responseLen, uint16_t responseSize, bool tcp, uint16_t* encryptedResponseLen)
+int DNSCryptQuery::encryptResponse(std::vector<uint8_t>& response, size_t maxResponseSize, bool tcp)
{
struct DNSCryptResponseHeader responseHeader;
- assert(response != nullptr);
- assert(responseLen > 0);
- assert(responseSize >= responseLen);
- assert(encryptedResponseLen != nullptr);
+ assert(response.size() > 0);
+ assert(maxResponseSize >= response.size());
assert(d_encrypted == true);
assert(d_pair != nullptr);
- if (!tcp && d_paddedLen < responseLen) {
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response);
+ /* a DNSCrypt UDP response can't be larger than the (padded) DNSCrypt query */
+ if (!tcp && d_paddedLen < response.size()) {
+ /* so we need to truncate it */
size_t questionSize = 0;
- if (responseLen > sizeof(dnsheader)) {
- unsigned int consumed = 0;
- DNSName tempQName(response, responseLen, sizeof(dnsheader), false, 0, 0, &consumed);
- if (consumed > 0) {
- questionSize = consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
+ if (response.size() > sizeof(dnsheader)) {
+ unsigned int qnameWireLength = 0;
+ DNSName tempQName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength);
+ if (qnameWireLength > 0) {
+ questionSize = qnameWireLength + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
}
}
- responseLen = sizeof(dnsheader) + questionSize;
+ response.resize(sizeof(dnsheader) + questionSize);
- if (responseLen > d_paddedLen) {
- responseLen = d_paddedLen;
+ if (response.size() > d_paddedLen) {
+ /* that does not seem right but let's truncate even more */
+ response.resize(d_paddedLen);
}
+ struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
dh->ancount = dh->arcount = dh->nscount = 0;
dh->tc = 1;
}
- size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + responseLen;
- size_t maxSize = (responseSize > (requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE)) ? (requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE) : responseSize;
+ size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + response.size();
+ size_t maxSize = std::min(maxResponseSize, requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE);
uint16_t paddingSize = computePaddingSize(requiredSize, maxSize);
requiredSize += paddingSize;
- if (requiredSize > responseSize)
+ if (requiredSize > maxResponseSize) {
return ENOBUFS;
+ }
memcpy(&responseHeader.nonce, &d_header.clientNonce, sizeof d_header.clientNonce);
fillServerNonce(&(responseHeader.nonce[sizeof(d_header.clientNonce)]));
+ size_t responseLen = response.size();
/* moving the existing response after the header + MAC */
- memmove(response + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE, response, responseLen);
+ response.resize(requiredSize);
+ std::copy_backward(response.begin(), response.begin() + responseLen, response.begin() + responseLen + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE);
uint16_t pos = 0;
/* copying header */
- memcpy(response + pos, &responseHeader, sizeof(responseHeader));
+ memcpy(&response.at(pos), &responseHeader, sizeof(responseHeader));
pos += sizeof(responseHeader);
/* setting MAC bytes to 0 */
- memset(response + pos, 0, DNSCRYPT_MAC_SIZE);
+ memset(&response.at(pos), 0, DNSCRYPT_MAC_SIZE);
pos += DNSCRYPT_MAC_SIZE;
uint16_t toEncryptPos = pos;
/* skipping response */
pos += responseLen;
/* padding */
- response[pos] = static_cast<uint8_t>(0x80);
+ response.at(pos) = static_cast<uint8_t>(0x80);
pos++;
- memset(response + pos, 0, paddingSize - 1);
+ memset(&response.at(pos), 0, paddingSize - 1);
pos += (paddingSize - 1);
/* encrypting */
const DNSCryptExchangeVersion version = getVersion();
if (version == DNSCryptExchangeVersion::VERSION1) {
- res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
- reinterpret_cast<unsigned char*>(response + toEncryptPos),
+ res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
+ reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
responseLen + paddingSize,
responseHeader.nonce,
d_sharedKey);
}
else if (version == DNSCryptExchangeVersion::VERSION2) {
#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
- res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
- reinterpret_cast<unsigned char*>(response + toEncryptPos),
+ res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
+ reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
responseLen + paddingSize,
responseHeader.nonce,
d_sharedKey);
res = -1;
}
#else
- int res = crypto_box_easy(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
- reinterpret_cast<unsigned char*>(response + toEncryptPos),
+ int res = crypto_box_easy(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
+ reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
responseLen + paddingSize,
responseHeader.nonce,
d_header.clientPK,
if (res == 0) {
assert(pos == requiredSize);
- *encryptedResponseLen = requiredSize;
}
return res;
}
-int DNSCryptContext::encryptQuery(char* query, uint16_t queryLen, uint16_t querySize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, uint16_t* encryptedResponseLen, const std::shared_ptr<DNSCryptCert>& cert) const
+int DNSCryptContext::encryptQuery(std::vector<uint8_t>& packet, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const
{
- assert(query != nullptr);
- assert(queryLen > 0);
- assert(querySize >= queryLen);
- assert(encryptedResponseLen != nullptr);
+ assert(packet.size() > 0);
assert(cert != nullptr);
+ size_t queryLen = packet.size();
unsigned char nonce[DNSCRYPT_NONCE_SIZE];
size_t requiredSize = sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE + queryLen;
/* this is not optimal, we should compute a random padding size, multiple of DNSCRYPT_PADDED_BLOCK_SIZE,
requiredSize = DNSCryptQuery::s_minUDPLength;
}
- if (requiredSize > querySize)
+ if (requiredSize > maximumSize) {
return ENOBUFS;
+ }
/* moving the existing query after the header + MAC */
- memmove(query + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE, query, queryLen);
+ packet.resize(requiredSize);
+ std::copy_backward(packet.begin(), packet.begin() + queryLen, packet.begin() + queryLen + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE);
size_t pos = 0;
/* client magic */
- memcpy(query + pos, cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic));
+ memcpy(&packet.at(pos), cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic));
pos += sizeof(cert->signedData.clientMagic);
/* client PK */
- memcpy(query + pos, clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE);
+ memcpy(&packet.at(pos), clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE);
pos += DNSCRYPT_PUBLIC_KEY_SIZE;
/* client nonce */
- memcpy(query + pos, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
+ memcpy(&packet.at(pos), clientNonce, DNSCRYPT_NONCE_SIZE / 2);
pos += DNSCRYPT_NONCE_SIZE / 2;
size_t encryptedPos = pos;
/* clear the MAC bytes */
- memset(query + pos, 0, DNSCRYPT_MAC_SIZE);
+ memset(&packet.at(pos), 0, DNSCRYPT_MAC_SIZE);
pos += DNSCRYPT_MAC_SIZE;
/* skipping data */
pos += queryLen;
/* padding */
- query[pos] = static_cast<uint8_t>(0x80);
+ packet.at(pos) = static_cast<uint8_t>(0x80);
pos++;
- memset(query + pos, 0, paddingSize - 1);
+ memset(&packet.at(pos), 0, paddingSize - 1);
pos += paddingSize - 1;
memcpy(nonce, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
int res = -1;
if (version == DNSCryptExchangeVersion::VERSION1) {
- res = crypto_box_easy(reinterpret_cast<unsigned char*>(query + encryptedPos),
- reinterpret_cast<unsigned char*>(query + encryptedPos + DNSCRYPT_MAC_SIZE),
+ res = crypto_box_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)),
+ reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)),
queryLen + paddingSize,
nonce,
cert->signedData.resolverPK,
}
else if (version == DNSCryptExchangeVersion::VERSION2) {
#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
- res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(query + encryptedPos),
- reinterpret_cast<unsigned char*>(query + encryptedPos + DNSCRYPT_MAC_SIZE),
+ res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)),
+ reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)),
queryLen + paddingSize,
nonce,
cert->signedData.resolverPK,
if (res == 0) {
assert(pos == requiredSize);
- *encryptedResponseLen = requiredSize;
}
return res;
d_pair = pair;
}
- void parsePacket(char* packet, uint16_t packetSize, bool tcp, uint16_t* decryptedQueryLen, time_t now);
- void getDecrypted(bool tcp, char* packet, uint16_t packetSize, uint16_t* decryptedQueryLen);
+ void parsePacket(std::vector<uint8_t>& packet, bool tcp, time_t now);
+ void getDecrypted(bool tcp, std::vector<uint8_t>& packet);
void getCertificateResponse(time_t now, std::vector<uint8_t>& response) const;
- int encryptResponse(char* response, uint16_t responseLen, uint16_t responseSize, bool tcp, uint16_t* encryptedResponseLen);
+ int encryptResponse(std::vector<uint8_t>& response, size_t maxResponseSize, bool tcp);
static const size_t s_minUDPLength = 256;
#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
void fillServerNonce(unsigned char* dest) const;
uint16_t computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const;
- bool parsePlaintextQuery(const char * packet, uint16_t packetSize);
- bool isEncryptedQuery(const char * packet, uint16_t packetSize, bool tcp, time_t now);
+ bool parsePlaintextQuery(const std::vector<uint8_t>& packet);
+ bool isEncryptedQuery(const std::vector<uint8_t>& packet, bool tcp, time_t now);
DNSCryptQueryHeader d_header;
#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
std::vector<std::shared_ptr<DNSCryptCertificatePair>> getCertificates() { return d_certs; };
const DNSName& getProviderName() const { return providerName; }
- int encryptQuery(char* query, uint16_t queryLen, uint16_t querySize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, uint16_t* encryptedResponseLen, const std::shared_ptr<DNSCryptCert>& cert) const;
+ int encryptQuery(std::vector<uint8_t>& query, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const;
bool magicMatchesAPublicKey(DNSCryptQuery& query, time_t now);
void getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, std::vector<uint8_t>& response);
}
}
-bool DNSDistPacketCache::getClientSubnet(const char* packet, unsigned int consumed, uint16_t len, boost::optional<Netmask>& subnet)
+bool DNSDistPacketCache::getClientSubnet(const std::vector<uint8_t>& packet, size_t qnameWireLength, boost::optional<Netmask>& subnet)
{
uint16_t optRDPosition;
size_t remaining = 0;
- int res = getEDNSOptionsStart(const_cast<char*>(packet), consumed, len, &optRDPosition, &remaining);
+ int res = getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
if (res == 0) {
- char * ecsOptionStart = nullptr;
+ size_t ecsOptionStartPosition = 0;
size_t ecsOptionSize = 0;
- res = getEDNSOption(const_cast<char*>(packet) + optRDPosition, remaining, EDNSOptionCode::ECS, &ecsOptionStart, &ecsOptionSize);
+ res = getEDNSOption(reinterpret_cast<const char*>(&packet.at(optRDPosition)), remaining, EDNSOptionCode::ECS, &ecsOptionStartPosition, &ecsOptionSize);
if (res == 0 && ecsOptionSize > (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) {
EDNSSubnetOpts eso;
- if (getEDNSSubnetOptsFromString(ecsOptionStart + (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), ecsOptionSize - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), &eso) == true) {
+ if (getEDNSSubnetOptsFromString(reinterpret_cast<const char*>(&packet.at(optRDPosition + ecsOptionStartPosition + (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE))), ecsOptionSize - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), &eso) == true) {
subnet = eso.source;
return true;
}
value = newValue;
}
-void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
+void DNSDistPacketCache::insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::vector<uint8_t>& response, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL)
{
- if (responseLen < sizeof(dnsheader)) {
+ if (response.size() < sizeof(dnsheader)) {
return;
}
}
else {
bool seenAuthSOA = false;
- minTTL = getMinTTL(response, responseLen, &seenAuthSOA);
+ minTTL = getMinTTL(reinterpret_cast<const char*>(response.data()), response.size(), &seenAuthSOA);
/* no TTL found, we don't want to cache this */
if (minTTL == std::numeric_limits<uint32_t>::max()) {
newValue.qtype = qtype;
newValue.qclass = qclass;
newValue.queryFlags = queryFlags;
- newValue.len = responseLen;
+ newValue.len = response.size();
newValue.validity = newValidity;
newValue.added = now;
newValue.tcp = tcp;
newValue.dnssecOK = dnssecOK;
- newValue.value = std::string(response, responseLen);
+ newValue.value = std::string(response.begin(), response.end());
newValue.subnet = subnet;
auto& shard = d_shards.at(shardIndex);
}
}
-bool DNSDistPacketCache::get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, uint32_t allowExpired, bool skipAging)
+bool DNSDistPacketCache::get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, uint32_t allowExpired, bool skipAging)
{
const auto& dnsQName = dq.qname->getStorage();
- uint32_t key = getKey(dnsQName, consumed, reinterpret_cast<const unsigned char*>(dq.dh), dq.len, dq.tcp);
+ uint32_t key = getKey(dnsQName, dq.qname->wirelength(), dq.getData(), dq.tcp);
if (keyOut) {
*keyOut = key;
}
if (d_parseECS) {
- getClientSubnet(reinterpret_cast<const char*>(dq.dh), consumed, dq.len, subnet);
+ getClientSubnet(dq.getData(), dq.qname->wirelength(), subnet);
}
uint32_t shardIndex = getShardIndex(key);
time_t now = time(nullptr);
time_t age;
bool stale = false;
+ auto& response = dq.getMutableData();
auto& shard = d_shards.at(shardIndex);
auto& map = shard.d_map;
{
}
}
- if (*responseLen < value.len || value.len < sizeof(dnsheader)) {
+ if (value.len < sizeof(dnsheader)) {
return false;
}
/* check for collision */
- if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.dh)), *dq.qname, dq.qtype, dq.qclass, dq.tcp, dnssecOK, subnet)) {
+ if (!cachedValueMatches(value, *(getFlagsFromDNSHeader(dq.getHeader())), *dq.qname, dq.qtype, dq.qclass, dq.tcp, dnssecOK, subnet)) {
d_lookupCollisions++;
return false;
}
- memcpy(response, &queryId, sizeof(queryId));
- memcpy(response + sizeof(queryId), value.value.c_str() + sizeof(queryId), sizeof(dnsheader) - sizeof(queryId));
+ response.resize(value.len);
+ memcpy(&response.at(0), &queryId, sizeof(queryId));
+ memcpy(&response.at(sizeof(queryId)), &value.value.at(sizeof(queryId)), sizeof(dnsheader) - sizeof(queryId));
if (value.len == sizeof(dnsheader)) {
/* DNS header only, our work here is done */
- *responseLen = value.len;
d_hits++;
return true;
}
return false;
}
- memcpy(response + sizeof(dnsheader), dnsQName.c_str(), dnsQNameLen);
+ memcpy(&response.at(sizeof(dnsheader)), dnsQName.c_str(), dnsQNameLen);
if (value.len > (sizeof(dnsheader) + dnsQNameLen)) {
- memcpy(response + sizeof(dnsheader) + dnsQNameLen, value.value.c_str() + sizeof(dnsheader) + dnsQNameLen, value.len - (sizeof(dnsheader) + dnsQNameLen));
+ memcpy(&response.at(sizeof(dnsheader) + dnsQNameLen), &value.value.at(sizeof(dnsheader) + dnsQNameLen), value.len - (sizeof(dnsheader) + dnsQNameLen));
}
- *responseLen = value.len;
+
if (!stale) {
age = now - value.added;
}
}
if (!d_dontAge && !skipAging) {
- ageDNSPacket(response, *responseLen, age);
+ ageDNSPacket(reinterpret_cast<char *>(&response[0]), response.size(), age);
}
d_hits++;
return getDNSPacketMinTTL(packet, length, seenNoDataSOA);
}
-uint32_t DNSDistPacketCache::getKey(const DNSName::string_t& qname, uint16_t consumed, const unsigned char* packet, uint16_t packetLen, bool tcp)
+uint32_t DNSDistPacketCache::getKey(const DNSName::string_t& qname, size_t qnameWireLength, const std::vector<uint8_t>& packet, bool tcp)
{
uint32_t result = 0;
/* skip the query ID */
- if (packetLen < sizeof(dnsheader)) {
- throw std::range_error("Computing packet cache key for an invalid packet size (" + std::to_string(packetLen) +")");
+ if (packet.size() < sizeof(dnsheader)) {
+ throw std::range_error("Computing packet cache key for an invalid packet size (" + std::to_string(packet.size()) +")");
}
- result = burtle(packet + 2, sizeof(dnsheader) - 2, result);
+ result = burtle(&packet.at(2), sizeof(dnsheader) - 2, result);
result = burtleCI((const unsigned char*) qname.c_str(), qname.length(), result);
- if (packetLen < sizeof(dnsheader) + consumed) {
- throw std::range_error("Computing packet cache key for an invalid packet (" + std::to_string(packetLen) + " < " + std::to_string(sizeof(dnsheader) + consumed) + ")");
+ if (packet.size() < sizeof(dnsheader) + qnameWireLength) {
+ throw std::range_error("Computing packet cache key for an invalid packet (" + std::to_string(packet.size()) + " < " + std::to_string(sizeof(dnsheader) + qnameWireLength) + ")");
}
- if (packetLen > ((sizeof(dnsheader) + consumed))) {
+ if (packet.size() > ((sizeof(dnsheader) + qnameWireLength))) {
if (!d_cookieHashing) {
/* skip EDNS Cookie options if any */
- result = PacketCache::hashAfterQname(pdns_string_view(reinterpret_cast<const char*>(packet), packetLen), result, sizeof(dnsheader) + consumed, false);
+ result = PacketCache::hashAfterQname(pdns_string_view(reinterpret_cast<const char*>(packet.data()), packet.size()), result, sizeof(dnsheader) + qnameWireLength, false);
}
else {
- result = burtle(packet + sizeof(dnsheader) + consumed, packetLen - (sizeof(dnsheader) + consumed), result);
+ result = burtle(&packet.at(sizeof(dnsheader) + qnameWireLength), packet.size() - (sizeof(dnsheader) + qnameWireLength), result);
}
}
result = burtle((const unsigned char*) &tcp, sizeof(tcp), result);
DNSDistPacketCache(size_t maxEntries, uint32_t maxTTL=86400, uint32_t minTTL=0, uint32_t tempFailureTTL=60, uint32_t maxNegativeTTL=3600, uint32_t staleTTL=60, bool dontAge=false, uint32_t shards=1, bool deferrableInsertLock=true, bool parseECS=false);
~DNSDistPacketCache();
- void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const char* response, uint16_t responseLen, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
- bool get(const DNSQuestion& dq, uint16_t consumed, uint16_t queryId, char* response, uint16_t* responseLen, uint32_t* keyOut, boost::optional<Netmask>& subnetOut, bool dnssecOK, uint32_t allowExpired=0, bool skipAging=false);
+ void insert(uint32_t key, const boost::optional<Netmask>& subnet, uint16_t queryFlags, bool dnssecOK, const DNSName& qname, uint16_t qtype, uint16_t qclass, const std::vector<uint8_t>& response, bool tcp, uint8_t rcode, boost::optional<uint32_t> tempFailureTTL);
+ bool get(DNSQuestion& dq, uint16_t queryId, uint32_t* keyOut, boost::optional<Netmask>& subnet, bool dnssecOK, uint32_t allowExpired = 0, bool skipAging = false);
size_t purgeExpired(size_t upTo=0);
size_t expunge(size_t upTo=0);
size_t expungeByName(const DNSName& name, uint16_t qtype=QType::ANY, bool suffixMatch=false);
d_parseECS = enabled;
}
- uint32_t getKey(const DNSName::string_t& qname, uint16_t consumed, const unsigned char* packet, uint16_t packetLen, bool tcp);
+ uint32_t getKey(const DNSName::string_t& qname, size_t qnameWireLength, const std::vector<uint8_t>& packet, bool tcp);
static uint32_t getMinTTL(const char* packet, uint16_t length, bool* seenNoDataSOA);
- static bool getClientSubnet(const char* packet, unsigned int consumed, uint16_t len, boost::optional<Netmask>& subnet);
+ static bool getClientSubnet(const std::vector<uint8_t>& packet, size_t qnameWireLength, boost::optional<Netmask>& subnet);
private:
#include "dnscrypt.hh"
#ifdef HAVE_DNSCRYPT
-int handleDNSCryptQuery(char* packet, uint16_t len, std::shared_ptr<DNSCryptQuery> query, uint16_t* decryptedQueryLen, bool tcp, time_t now, std::vector<uint8_t>& response)
+int handleDNSCryptQuery(std::vector<uint8_t>& packet, std::shared_ptr<DNSCryptQuery>& query, bool tcp, time_t now, std::vector<uint8_t>& response)
{
- query->parsePacket(packet, len, tcp, decryptedQueryLen, now);
+ query->parsePacket(packet, tcp, now);
if (query->isValid() == false) {
vinfolog("Dropping DNSCrypt invalid query");
return false;
}
- if(*decryptedQueryLen < static_cast<uint16_t>(sizeof(struct dnsheader))) {
+ if (packet.size() < static_cast<uint16_t>(sizeof(struct dnsheader))) {
++g_stats.nonCompliantQueries;
return false;
}
return true;
}
-static bool slowParseEDNSOptions(const char* packet, uint16_t const len, std::shared_ptr<std::map<uint16_t, EDNSOptionView> >& options)
+static bool slowParseEDNSOptions(const std::vector<uint8_t>& packet, std::shared_ptr<std::map<uint16_t, EDNSOptionView> >& options)
{
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+ if (packet.size() < sizeof(dnsheader)) {
+ return false;
+ }
+
+ const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
- if (len < sizeof(dnsheader) || ntohs(dh->qdcount) == 0)
- {
+ if (ntohs(dh->qdcount) == 0) {
return false;
}
try {
uint64_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
- DNSPacketMangler dpm(const_cast<char*>(packet), len);
+ DNSPacketMangler dpm(const_cast<char*>(reinterpret_cast<const char*>(&packet.at(0))), packet.size());
uint64_t n;
for(n=0; n < ntohs(dh->qdcount) ; ++n) {
dpm.skipDomainName();
if(section == 3 && dnstype == QType::OPT) {
uint32_t offset = dpm.getOffset();
- if (offset >= len) {
+ if (offset >= packet.size()) {
return false;
}
/* if we survive this call, we can parse it safely */
dpm.skipRData();
- return getEDNSOptions(packet + offset, len - offset, *options) == 0;
+ return getEDNSOptions(reinterpret_cast<const char*>(&packet.at(offset)), packet.size() - offset, *options) == 0;
}
else {
dpm.skipRData();
}
/* extract the start of the OPT RR in a QUERY packet if any */
-int getEDNSOptionsStart(const char* packet, const size_t offset, const size_t len, uint16_t* optRDPosition, size_t * remaining)
+int getEDNSOptionsStart(const std::vector<uint8_t>& packet, const size_t offset, uint16_t* optRDPosition, size_t* remaining)
{
- assert(packet != nullptr);
assert(optRDPosition != nullptr);
assert(remaining != nullptr);
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+ const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
- if (offset >= len) {
+ if (offset >= packet.size()) {
return ENOENT;
}
size_t pos = sizeof(dnsheader) + offset;
pos += DNS_TYPE_SIZE + DNS_CLASS_SIZE;
- if (pos >= len)
+ if (pos >= packet.size())
return ENOENT;
- if ((pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE) >= len) {
+ if ((pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE) >= packet.size()) {
return ENOENT;
}
}
pos += 1;
- uint16_t qtype = (reinterpret_cast<const unsigned char*>(packet)[pos])*256 + reinterpret_cast<const unsigned char*>(packet)[pos+1];
+ uint16_t qtype = packet.at(pos)*256 + packet.at(pos+1);
pos += DNS_TYPE_SIZE;
pos += DNS_CLASS_SIZE;
- if(qtype != QType::OPT || (len - pos) < (DNS_TTL_SIZE + DNS_RDLENGTH_SIZE))
+ if (qtype != QType::OPT || (packet.size() - pos) < (DNS_TTL_SIZE + DNS_RDLENGTH_SIZE)) {
return ENOENT;
+ }
pos += DNS_TTL_SIZE;
*optRDPosition = pos;
- *remaining = len - pos;
+ *remaining = packet.size() - pos;
return 0;
}
res.append(optRData.c_str(), optRData.length());
}
-static bool replaceEDNSClientSubnetOption(char * const packet, const size_t packetSize, uint16_t * const len, char * const oldEcsOptionStart, size_t const oldEcsOptionSize, unsigned char * const optRDLen, const string& newECSOption)
+static bool replaceEDNSClientSubnetOption(std::vector<uint8_t>& packet, size_t maximumSize, size_t const oldEcsOptionStartPosition, size_t const oldEcsOptionSize, size_t const optRDLenPosition, const string& newECSOption)
{
- assert(packet != NULL);
- assert(len != NULL);
- assert(oldEcsOptionStart != NULL);
- assert(optRDLen != NULL);
+ assert(oldEcsOptionStartPosition < packet.size());
+ assert(optRDLenPosition < packet.size());
if (newECSOption.size() == oldEcsOptionSize) {
/* same size as the existing option */
- memcpy(oldEcsOptionStart, newECSOption.c_str(), oldEcsOptionSize);
+ memcpy(&packet.at(oldEcsOptionStartPosition), newECSOption.c_str(), oldEcsOptionSize);
}
else {
/* different size than the existing option */
- const unsigned int newPacketLen = *len + (newECSOption.length() - oldEcsOptionSize);
- const size_t beforeOptionLen = oldEcsOptionStart - packet;
- const size_t dataBehindSize = *len - beforeOptionLen - oldEcsOptionSize;
+ const unsigned int newPacketLen = packet.size() + (newECSOption.length() - oldEcsOptionSize);
+ const size_t beforeOptionLen = oldEcsOptionStartPosition;
+ const size_t dataBehindSize = packet.size() - beforeOptionLen - oldEcsOptionSize;
/* check that it fits in the existing buffer */
- if (newPacketLen > packetSize) {
- return false;
+ if (newPacketLen > packet.size()) {
+ if (newPacketLen > maximumSize) {
+ return false;
+ }
+
+ packet.resize(newPacketLen);
}
/* fix the size of ECS Option RDLen */
- uint16_t newRDLen = (optRDLen[0] * 256) + optRDLen[1];
+ uint16_t newRDLen = (packet.at(optRDLenPosition) * 256) + packet.at(optRDLenPosition + 1);
newRDLen += (newECSOption.size() - oldEcsOptionSize);
- optRDLen[0] = newRDLen / 256;
- optRDLen[1] = newRDLen % 256;
+ packet.at(optRDLenPosition) = newRDLen / 256;
+ packet.at(optRDLenPosition + 1) = newRDLen % 256;
if (dataBehindSize > 0) {
- memmove(oldEcsOptionStart, oldEcsOptionStart + oldEcsOptionSize, dataBehindSize);
+ memmove(&packet.at(oldEcsOptionStartPosition), &packet.at(oldEcsOptionStartPosition + oldEcsOptionSize), dataBehindSize);
}
- memcpy(oldEcsOptionStart + dataBehindSize, newECSOption.c_str(), newECSOption.size());
- *len = newPacketLen;
+ memcpy(&packet.at(oldEcsOptionStartPosition + dataBehindSize), newECSOption.c_str(), newECSOption.size());
+ packet.resize(newPacketLen);
}
return true;
and false otherwise. */
bool parseEDNSOptions(const DNSQuestion& dq)
{
- assert(dq.dh != nullptr);
- assert(dq.consumed <= dq.len);
- assert(dq.len <= dq.size);
-
+ const auto dh = dq.getHeader();
if (dq.ednsOptions != nullptr) {
return true;
}
dq.ednsOptions = std::make_shared<std::map<uint16_t, EDNSOptionView> >();
- if (ntohs(dq.dh->arcount) == 0) {
+ if (ntohs(dh->arcount) == 0) {
/* nothing in additional so no EDNS */
return false;
}
- if (ntohs(dq.dh->ancount) != 0 || ntohs(dq.dh->nscount) != 0 || ntohs(dq.dh->arcount) > 1) {
- return slowParseEDNSOptions(reinterpret_cast<const char*>(dq.dh), dq.len, dq.ednsOptions);
+ if (ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || ntohs(dh->arcount) > 1) {
+ return slowParseEDNSOptions(dq.getData(), dq.ednsOptions);
}
- const char* packet = reinterpret_cast<const char*>(dq.dh);
-
size_t remaining = 0;
uint16_t optRDPosition;
- int res = getEDNSOptionsStart(packet, dq.consumed, dq.len, &optRDPosition, &remaining);
+ int res = getEDNSOptionsStart(dq.getData(), dq.qname->wirelength(), &optRDPosition, &remaining);
if (res == 0) {
- res = getEDNSOptions(packet + optRDPosition, remaining, *dq.ednsOptions);
+ res = getEDNSOptions(reinterpret_cast<const char*>(&dq.getData().at(optRDPosition)), remaining, *dq.ednsOptions);
return (res == 0);
}
return false;
}
-static bool addECSToExistingOPT(char* const packet, size_t const packetSize, uint16_t* const len, const string& newECSOption, unsigned char* optRDLen, bool& ecsAdded)
+static bool addECSToExistingOPT(std::vector<uint8_t>& packet, size_t maximumSize, const string& newECSOption, size_t optRDLenPosition, bool& ecsAdded)
{
/* we need to add one EDNS0 ECS option, fixing the size of EDNS0 RDLENGTH */
/* getEDNSOptionsStart has already checked that there is exactly one AR,
no NS and no AN */
+ uint16_t oldRDLen = (packet.at(optRDLenPosition) * 256) + packet.at(optRDLenPosition + 1);
+ if (packet.size() != (optRDLenPosition + sizeof(uint16_t) + oldRDLen)) {
+ /* we are supposed to be the last record, do we have some trailing data to remove? */
+ uint32_t realPacketLen = getDNSPacketLength(reinterpret_cast<const char*>(packet.data()), packet.size());
+ packet.resize(realPacketLen);
+ }
- /* check if the existing buffer is large enough */
- const size_t newECSOptionSize = newECSOption.size();
- if (packetSize - *len <= newECSOptionSize) {
+ if ((maximumSize - packet.size()) < newECSOption.size()) {
return false;
}
- uint16_t newRDLen = (optRDLen[0] * 256) + optRDLen[1];
- newRDLen += newECSOptionSize;
- optRDLen[0] = newRDLen / 256;
- optRDLen[1] = newRDLen % 256;
+ uint16_t newRDLen = oldRDLen + newECSOption.size();
+ packet.at(optRDLenPosition) = newRDLen / 256;
+ packet.at(optRDLenPosition + 1) = newRDLen % 256;
- memcpy(packet + *len, newECSOption.c_str(), newECSOptionSize);
- *len += newECSOptionSize;
+ packet.insert(packet.end(), newECSOption.begin(), newECSOption.end());
ecsAdded = true;
return true;
}
-static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t* const len, const string& newECSOption, bool& ednsAdded, bool& ecsAdded, bool preserveTrailingData)
+static bool addEDNSWithECS(std::vector<uint8_t>& packet, size_t maximumSize, const string& newECSOption, bool& ednsAdded, bool& ecsAdded)
{
/* we need to add a EDNS0 RR with one EDNS0 ECS option, fixing the AR count */
string EDNSRR;
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet);
generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, 0, false);
- /* does it fit in the existing buffer? */
- if (packetSize - *len <= EDNSRR.size()) {
+ if ((maximumSize - packet.size()) < EDNSRR.size()) {
return false;
}
- uint32_t realPacketLen = getDNSPacketLength(packet, *len);
- if (realPacketLen < *len && preserveTrailingData) {
- size_t toMove = *len - realPacketLen;
- memmove(packet + realPacketLen + EDNSRR.size(), packet + realPacketLen, toMove);
- *len += EDNSRR.size();
- }
- else {
- *len = realPacketLen + EDNSRR.size();
- }
+#warning FIXME: we can avoid a copy here by generating in place
+ packet.insert(packet.end(), EDNSRR.begin(), EDNSRR.end());
+ struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet.data());
uint16_t arcount = ntohs(dh->arcount);
arcount++;
dh->arcount = htons(arcount);
ednsAdded = true;
ecsAdded = true;
- memcpy(packet + realPacketLen, EDNSRR.c_str(), EDNSRR.size());
-
return true;
}
-bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const unsigned int consumed, uint16_t* const len, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption, bool preserveTrailingData)
+bool handleEDNSClientSubnet(std::vector<uint8_t>& packet, const size_t maximumSize, const size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption)
{
- assert(packet != nullptr);
- assert(len != nullptr);
- assert(consumed <= (size_t) *len);
+ assert(qnameWireLength <= packet.size());
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
+ const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
if (ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || (ntohs(dh->arcount) != 0 && ntohs(dh->arcount) != 1)) {
vector<uint8_t> newContent;
- newContent.reserve(packetSize);
+ newContent.reserve(packet.size());
- if (!slowRewriteQueryWithExistingEDNS(std::string(packet, *len), newContent, ednsAdded, ecsAdded, overrideExisting, newECSOption)) {
+ if (!slowRewriteQueryWithExistingEDNS(std::string(reinterpret_cast<const char*>(packet.data()), packet.size()), newContent, ednsAdded, ecsAdded, overrideExisting, newECSOption)) {
ednsAdded = false;
ecsAdded = false;
return false;
}
- if (newContent.size() > packetSize) {
+ if (newContent.size() > maximumSize) {
ednsAdded = false;
ecsAdded = false;
return false;
}
- memcpy(packet, &newContent.at(0), newContent.size());
- *len = newContent.size();
+ packet = std::move(newContent);
return true;
}
uint16_t optRDPosition = 0;
size_t remaining = 0;
- int res = getEDNSOptionsStart(packet, consumed, *len, &optRDPosition, &remaining);
+ int res = getEDNSOptionsStart(packet, qnameWireLength, &optRDPosition, &remaining);
if (res != 0) {
- return addEDNSWithECS(packet, packetSize, len, newECSOption, ednsAdded, ecsAdded, preserveTrailingData);
+ /* no EDNS but there might be another record in additional (TSIG?) */
+ size_t minimumPacketSize = sizeof(dnsheader) + qnameWireLength + sizeof(uint16_t) + sizeof(uint16_t);
+ if (packet.size() > minimumPacketSize) {
+ if (ntohs(dh->arcount) == 0) {
+ /* well now.. */
+ packet.resize(minimumPacketSize);
+ }
+ else {
+ uint32_t realPacketLen = getDNSPacketLength(reinterpret_cast<const char*>(packet.data()), packet.size());
+ packet.resize(realPacketLen);
+ }
+ }
+
+ return addEDNSWithECS(packet, maximumSize, newECSOption, ednsAdded, ecsAdded);
}
- unsigned char* optRDLen = reinterpret_cast<unsigned char*>(packet) + optRDPosition;
- char * ecsOptionStart = nullptr;
+ size_t ecsOptionStartPosition = 0;
size_t ecsOptionSize = 0;
- res = getEDNSOption(reinterpret_cast<char*>(optRDLen), remaining, EDNSOptionCode::ECS, &ecsOptionStart, &ecsOptionSize);
+ res = getEDNSOption(reinterpret_cast<const char*>(&packet.at(optRDPosition)), remaining, EDNSOptionCode::ECS, &ecsOptionStartPosition, &ecsOptionSize);
if (res == 0) {
/* there is already an ECS value */
return true;
}
- return replaceEDNSClientSubnetOption(packet, packetSize, len, ecsOptionStart, ecsOptionSize, optRDLen, newECSOption);
+ return replaceEDNSClientSubnetOption(packet, maximumSize, optRDPosition + ecsOptionStartPosition, ecsOptionSize, optRDPosition, newECSOption);
} else {
/* we have an EDNS OPT RR but no existing ECS option */
- return addECSToExistingOPT(packet, packetSize, len, newECSOption, optRDLen, ecsAdded);
+ return addECSToExistingOPT(packet, maximumSize, newECSOption, optRDPosition, ecsAdded);
}
return true;
}
-bool handleEDNSClientSubnet(DNSQuestion& dq, bool& ednsAdded, bool& ecsAdded, bool preserveTrailingData)
+bool handleEDNSClientSubnet(DNSQuestion& dq, bool& ednsAdded, bool& ecsAdded)
{
assert(dq.remote != nullptr);
string newECSOption;
generateECSOption(dq.ecsSet ? dq.ecs.getNetwork() : *dq.remote, newECSOption, dq.ecsSet ? dq.ecs.getBits() : dq.ecsPrefixLength);
- char* packet = reinterpret_cast<char*>(dq.dh);
- return handleEDNSClientSubnet(packet, dq.size, dq.consumed, &dq.len, ednsAdded, ecsAdded, dq.ecsOverride, newECSOption, preserveTrailingData);
+ return handleEDNSClientSubnet(dq.getMutableData(), dq.getMaximumSize(), dq.qname->wirelength(), ednsAdded, ecsAdded, dq.ecsOverride, newECSOption);
}
static int removeEDNSOptionFromOptions(unsigned char* optionsStart, const uint16_t optionsLen, const uint16_t optionCodeToRemove, uint16_t* newOptionsLen)
return 0;
}
-bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
+bool addEDNS(std::vector<uint8_t>& packet, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
{
std::string optRecord;
generateOptRR(std::string(), optRecord, payloadSize, ednsrcode, dnssecOK);
- if (optRecord.size() >= size || (size - optRecord.size()) < len) {
- return false;
- }
-
- char * optPtr = reinterpret_cast<char*>(dh) + len;
- memcpy(optPtr, optRecord.data(), optRecord.size());
- len += optRecord.size();
+ packet.insert(packet.end(), optRecord.begin(), optRecord.end());
+ auto dh = reinterpret_cast<dnsheader*>(packet.data());
dh->arcount = htons(ntohs(dh->arcount) + 1);
return true;
*/
bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum)
{
- if (ntohs(dq.dh->qdcount) != 1) {
+ auto& packet = dq.getMutableData();
+ auto dh = dq.getHeader();
+ if (ntohs(dh->qdcount) != 1) {
return false;
}
- assert(dq.consumed == dq.qname->wirelength());
- size_t queryPartSize = sizeof(dnsheader) + dq.consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
- if (dq.len < queryPartSize) {
+ size_t queryPartSize = sizeof(dnsheader) + dq.qname->wirelength() + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
+ if (packet.size() < queryPartSize) {
/* something is already wrong, don't build on flawed foundations */
return false;
}
- size_t available = dq.size - queryPartSize;
uint16_t qtype = htons(QType::SOA);
uint16_t qclass = htons(QClass::IN);
uint16_t rdLength = mname.wirelength() + rname.wirelength() + sizeof(serial) + sizeof(refresh) + sizeof(retry) + sizeof(expire) + sizeof(minimum);
size_t soaSize = zone.wirelength() + sizeof(qtype) + sizeof(qclass) + sizeof(ttl) + sizeof(rdLength) + rdLength;
-
- if (soaSize > available) {
- /* not enough space left to add the SOA, sorry! */
- return false;
- }
-
bool hadEDNS = false;
bool dnssecOK = false;
if (g_addEDNSToSelfGeneratedResponses) {
uint16_t payloadSize = 0;
uint16_t z = 0;
- hadEDNS = getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &payloadSize, &z);
+ hadEDNS = getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(packet.data()), packet.size(), &payloadSize, &z);
if (hadEDNS) {
dnssecOK = z & EDNS_HEADER_FLAG_DO;
}
}
/* chop off everything after the question */
- dq.len = queryPartSize;
+ packet.resize(queryPartSize);
+ dh = dq.getHeader();
if (nxd) {
- dq.dh->rcode = RCode::NXDomain;
+ dh->rcode = RCode::NXDomain;
}
else {
- dq.dh->rcode = RCode::NoError;
+ dh->rcode = RCode::NoError;
}
- dq.dh->qr = true;
- dq.dh->ancount = 0;
- dq.dh->nscount = 0;
- dq.dh->arcount = 0;
+ dh->qr = true;
+ dh->ancount = 0;
+ dh->nscount = 0;
+ dh->arcount = 0;
rdLength = htons(rdLength);
ttl = htonl(ttl);
throw std::runtime_error("Unexpected SOA response size: " + std::to_string(soa.size()) + " vs " + std::to_string(soaSize));
}
- memcpy(reinterpret_cast<char*>(dq.dh) + queryPartSize, soa.c_str(), soa.size());
-
- dq.len += soa.size();
-
- dq.dh->arcount = htons(1);
+ packet.insert(packet.end(), soa.begin(), soa.end());
+ dh = dq.getHeader();
+ dh->arcount = htons(1);
if (hadEDNS) {
/* now we need to add a new OPT record */
- return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
+ return addEDNS(packet, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
}
return true;
/* remaining is at least the size of the rdlen + the options if any + the following records if any */
size_t remaining = 0;
- int res = getEDNSOptionsStart(reinterpret_cast<char*>(dq.dh), dq.consumed, dq.len, &optRDPosition, &remaining);
+ auto& packet = dq.getMutableData();
+ int res = getEDNSOptionsStart(packet, dq.qname->wirelength(), &optRDPosition, &remaining);
if (res != 0) {
/* if the initial query did not have EDNS0, we are done */
}
const size_t existingOptLen = /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2 + remaining;
- if (existingOptLen >= dq.len) {
+ if (existingOptLen >= packet.size()) {
/* something is wrong, bail out */
return false;
}
- char* optRDLen = reinterpret_cast<char*>(dq.dh) + optRDPosition;
- char * optPtr = (optRDLen - (/* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2));
+ uint8_t* optRDLen = &packet.at(optRDPosition);
+ uint8_t* optPtr = (optRDLen - (/* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2));
- const uint8_t* zPtr = reinterpret_cast<const uint8_t*>(optPtr) + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE;
+ const uint8_t* zPtr = optPtr + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE;
uint16_t z = 0x100 * (*zPtr) + *(zPtr + 1);
bool dnssecOK = z & EDNS_HEADER_FLAG_DO;
/* remove the existing OPT record, and everything else that follows (any SIG or TSIG would be useless anyway) */
- dq.len -= existingOptLen;
- dq.dh->arcount = 0;
+ packet.resize(packet.size() - existingOptLen);
+ dq.getHeader()->arcount = 0;
if (g_addEDNSToSelfGeneratedResponses) {
/* now we need to add a new OPT record */
- return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
+ return addEDNS(packet, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
}
/* otherwise we are just fine */
// goal in life - if you send us a reasonably normal packet, we'll get Z for you, otherwise 0
int getEDNSZ(const DNSQuestion& dq)
-try
{
- if (ntohs(dq.dh->qdcount) != 1 || dq.dh->ancount != 0 || ntohs(dq.dh->arcount) != 1 || dq.dh->nscount != 0) {
- return 0;
- }
+ try
+ {
+ const auto& dh = dq.getHeader();
+ if (ntohs(dh->qdcount) != 1 || dh->ancount != 0 || ntohs(dh->arcount) != 1 || dh->nscount != 0) {
+ return 0;
+ }
- if (dq.len <= sizeof(dnsheader)) {
- return 0;
- }
+ if (dq.getData().size() <= sizeof(dnsheader)) {
+ return 0;
+ }
- size_t pos = sizeof(dnsheader) + dq.consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
+ size_t pos = sizeof(dnsheader) + dq.qname->wirelength() + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
- if (dq.len <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
- return 0;
- }
+ if (dq.getData().size() <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
+ return 0;
+ }
- const char* packet = reinterpret_cast<const char*>(dq.dh);
+ auto& packet = dq.getData();
- if (packet[pos] != 0) {
- /* not root, so not a valid OPT record */
- return 0;
- }
+ if (packet.at(pos) != 0) {
+ /* not root, so not a valid OPT record */
+ return 0;
+ }
- pos++;
+ pos++;
- uint16_t qtype = (reinterpret_cast<const unsigned char*>(packet)[pos])*256 + reinterpret_cast<const unsigned char*>(packet)[pos+1];
- pos += DNS_TYPE_SIZE;
- pos += DNS_CLASS_SIZE;
+ uint16_t qtype = packet.at(pos)*256 + packet.at(pos+1);
+ pos += DNS_TYPE_SIZE;
+ pos += DNS_CLASS_SIZE;
+
+ if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= packet.size()) {
+ return 0;
+ }
- if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= dq.len) {
+ const uint8_t* z = &packet.at(pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE);
+ return 0x100 * (*z) + *(z+1);
+ }
+ catch(...)
+ {
return 0;
}
-
- const uint8_t* z = reinterpret_cast<const uint8_t*>(packet) + pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE;
- return 0x100 * (*z) + *(z+1);
-}
-catch(...)
-{
- return 0;
}
bool queryHasEDNS(const DNSQuestion& dq)
uint16_t optRDPosition;
size_t ecsRemaining = 0;
- int res = getEDNSOptionsStart(reinterpret_cast<char*>(dq.dh), dq.consumed, dq.len, &optRDPosition, &ecsRemaining);
+ int res = getEDNSOptionsStart(dq.getData(), dq.qname->wirelength(), &optRDPosition, &ecsRemaining);
if (res == 0) {
return true;
}
uint16_t optStart;
size_t optLen = 0;
bool last = false;
- const char * packet = reinterpret_cast<const char*>(dq.dh);
- std::string packetStr(packet, dq.len);
+ const auto& packet = dq.getData();
+#warning FIXME: save an alloc+copy
+ std::string packetStr(reinterpret_cast<const char*>(packet.data()), packet.size());
int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last);
if (res != 0) {
// no EDNS OPT RR
return false;
}
- if (optStart < dq.len && packetStr.at(optStart) != 0) {
+ if (optStart < packet.size() && packetStr.at(optStart) != 0) {
// OPT RR Name != '.'
return false;
}
static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t) AKA RR TTL size");
// copy out 4-byte "ttl" (really the EDNS0 record), after root label (1) + type (2) + class (2).
- memcpy(&edns0, packet + optStart + 5, sizeof edns0);
+ memcpy(&edns0, &packet.at(optStart + 5), sizeof edns0);
return true;
}
void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength);
int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove);
int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uint16_t optionCodeToSkip, vector<uint8_t>& newContent);
-int getEDNSOptionsStart(const char* packet, const size_t offset, const size_t len, uint16_t* optRDPosition, size_t * remaining);
+int getEDNSOptionsStart(const std::vector<uint8_t>& packet, const size_t offset, uint16_t* optRDPosition, size_t * remaining);
bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart = nullptr, uint16_t* optContentLen = nullptr);
-bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode);
+bool addEDNS(std::vector<uint8_t>& packet, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode);
bool addEDNSToQueryTurnedResponse(DNSQuestion& dq);
bool setNegativeAndAdditionalSOA(DNSQuestion& dq, bool nxd, const DNSName& zone, uint32_t ttl, const DNSName& mname, const DNSName& rname, uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum);
-bool handleEDNSClientSubnet(DNSQuestion& dq, bool& ednsAdded, bool& ecsAdded, bool preserveTrailingData);
-bool handleEDNSClientSubnet(char* packet, size_t packetSize, unsigned int consumed, uint16_t* len, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption, bool preserveTrailingData);
+bool handleEDNSClientSubnet(DNSQuestion& dq, bool& ednsAdded, bool& ecsAdded);
+bool handleEDNSClientSubnet(std::vector<uint8_t>& packet, size_t maximumSize, size_t qnameWireLength, bool& ednsAdded, bool& ecsAdded, bool overrideExisting, const string& newECSOption);
bool parseEDNSOptions(const DNSQuestion& dq);
d_queries++;
if(d_addECS) {
- std::string query;
- uint16_t len = dq->len;
+ std::vector<uint8_t> query(dq->getData());
bool ednsAdded = false;
bool ecsAdded = false;
- query.reserve(dq->size);
- query.assign((char*) dq->dh, len);
std::string newECSOption;
generateECSOption(dq->ecsSet ? dq->ecs.getNetwork() : *dq->remote, newECSOption, dq->ecsSet ? dq->ecs.getBits() : dq->ecsPrefixLength);
- if (!handleEDNSClientSubnet(const_cast<char*>(query.c_str()), query.capacity(), dq->qname->wirelength(), &len, ednsAdded, ecsAdded, dq->ecsOverride, newECSOption, g_preserveTrailingData)) {
+ if (!handleEDNSClientSubnet(query, dq->getMaximumSize(), dq->qname->wirelength(), ednsAdded, ecsAdded, dq->ecsOverride, newECSOption)) {
return DNSAction::Action::None;
}
- res = send(d_fd, query.c_str(), len, 0);
+ res = send(d_fd, query.data(), query.size(), 0);
}
else {
- res = send(d_fd, (char*)dq->dh, dq->len, 0);
+ res = send(d_fd, dq->getData().data(), dq->getData().size(), 0);
}
- if (res <= 0)
+ if (res <= 0) {
d_senderrors++;
+ }
}
return DNSAction::Action::None;
}
RCodeAction(uint8_t rcode) : d_rcode(rcode) {}
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->dh->rcode = d_rcode;
- dq->dh->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
+ dq->getHeader()->rcode = d_rcode;
+ dq->getHeader()->qr = true; // for good measure
+ setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
return Action::HeaderModify;
}
std::string toString() const override
ERCodeAction(uint8_t rcode) : d_rcode(rcode) {}
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->dh->rcode = (d_rcode & 0xF);
+ dq->getHeader()->rcode = (d_rcode & 0xF);
dq->ednsRCode = ((d_rcode & 0xFFF0) >> 4);
- dq->dh->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
+ dq->getHeader()->qr = true; // for good measure
+ setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
return Action::HeaderModify;
}
std::string toString() const override
shuffle(addrs.begin(), addrs.end(), t_randomEngine);
}
- unsigned int consumed=0;
- DNSName ignore((char*)dq->dh, dq->len, sizeof(dnsheader), false, 0, 0, &consumed);
+ unsigned int qnameWireLength=0;
+ DNSName ignore((char*)dq->getData().data(), dq->getData().size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength);
- if (dq->size < (sizeof(dnsheader) + consumed + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) {
+ if (dq->getMaximumSize() < (sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen)) {
return Action::None;
}
dnssecOK = getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO;
}
- dq->len = sizeof(dnsheader) + consumed + 4; // there goes your EDNS
- char* dest = ((char*)dq->dh) + dq->len;
+ auto& data = dq->getMutableData();
+ data.resize(sizeof(dnsheader) + qnameWireLength + 4 + numberOfRecords*12 /* recordstart */ + totrdatalen); // there goes your EDNS
+ uint8_t* dest = &(data.at(sizeof(dnsheader) + qnameWireLength + 4));
- dq->dh->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
- dq->dh->ancount = 0;
- dq->dh->arcount = 0; // for now, forget about your EDNS, we're marching over it
+ dq->getHeader()->qr = true; // for good measure
+ setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
+ dq->getHeader()->ancount = 0;
+ dq->getHeader()->arcount = 0; // for now, forget about your EDNS, we're marching over it
uint32_t ttl = htonl(d_responseConfig.ttl);
unsigned char recordstart[] = {0xc0, 0x0c, // compressed name
memcpy(dest, recordstart, sizeof(recordstart));
dest += sizeof(recordstart);
memcpy(dest, wireData.c_str(), wireData.length());
- dq->len += wireData.length() + sizeof(recordstart);
- dq->dh->ancount++;
+ dq->getHeader()->ancount++;
}
else if (!d_rawResponse.empty()) {
uint16_t rdataLen = htons(d_rawResponse.size());
memcpy(dest, recordstart, sizeof(recordstart));
dest += sizeof(recordstart);
memcpy(dest, d_rawResponse.c_str(), d_rawResponse.size());
- dq->len += d_rawResponse.size() + sizeof(recordstart);
- dq->dh->ancount++;
+ dq->getHeader()->ancount++;
raw = true;
}
else {
addr.sin4.sin_family == AF_INET ? (void*)&addr.sin4.sin_addr.s_addr : (void*)&addr.sin6.sin6_addr.s6_addr,
addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
dest += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr));
- dq->len += (addr.sin4.sin_family == AF_INET ? sizeof(addr.sin4.sin_addr.s_addr) : sizeof(addr.sin6.sin6_addr.s6_addr)) + sizeof(recordstart);
- dq->dh->ancount++;
+ dq->getHeader()->ancount++;
}
}
- dq->dh->ancount = htons(dq->dh->ancount);
+ dq->getHeader()->ancount = htons(dq->getHeader()->ancount);
if (hadEDNS && raw == false) {
- addEDNS(dq->dh, dq->len, dq->size, dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
+ addEDNS(dq->getMutableData(), dnssecOK, g_PayloadSizeSelfGenAnswers, 0);
}
return Action::HeaderModify;
{}
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- if(dq->dh->arcount)
+ if(dq->getHeader()->arcount)
return Action::None;
std::string mac = getMACAddress(*dq->remote);
std::string res;
generateOptRR(optRData, res, g_EdnsUDPPayloadSize, 0, false);
- if ((dq->size - dq->len) < res.length())
+ if (!dq->hasRoomFor(res.length())) {
return Action::None;
+ }
- dq->dh->arcount = htons(1);
- char* dest = ((char*)dq->dh) + dq->len;
- memcpy(dest, res.c_str(), res.length());
- dq->len += res.length();
+ dq->getHeader()->arcount = htons(1);
+ auto& data = dq->getMutableData();
+ data.insert(data.end(), res.begin(), res.end());
return Action::None;
}
public:
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->dh->rd = false;
+ dq->getHeader()->rd = false;
return Action::None;
}
std::string toString() const override
if (!d_fp) {
if (!d_verboseOnly || g_verbose) {
if (d_includeTimestamp) {
- infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
+ infolog("[%u.%u] Packet from %s for %s %s with id %d", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->getHeader()->id);
}
else {
- infolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->dh->id);
+ infolog("Packet from %s for %s %s with id %d", dq->remote->toStringWithPort(), dq->qname->toString(), QType(dq->qtype).getName(), dq->getHeader()->id);
}
}
}
fwrite(&tv_sec, sizeof(tv_sec), 1, d_fp.get());
fwrite(&tv_nsec, sizeof(tv_nsec), 1, d_fp.get());
}
- uint16_t id = dq->dh->id;
+ uint16_t id = dq->getHeader()->id;
fwrite(&id, sizeof(id), 1, d_fp.get());
fwrite(out.c_str(), 1, out.size(), d_fp.get());
fwrite(&dq->qtype, sizeof(dq->qtype), 1, d_fp.get());
}
else {
if (d_includeTimestamp) {
- fprintf(d_fp.get(), "[%llu.%lu] Packet from %s for %s %s with id %d\n", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->dh->id);
+ fprintf(d_fp.get(), "[%llu.%lu] Packet from %s for %s %s with id %d\n", static_cast<unsigned long long>(dq->queryTime->tv_sec), static_cast<unsigned long>(dq->queryTime->tv_nsec), dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->getHeader()->id);
}
else {
- fprintf(d_fp.get(), "Packet from %s for %s %s with id %d\n", dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->dh->id);
+ fprintf(d_fp.get(), "Packet from %s for %s %s with id %d\n", dq->remote->toStringWithPort().c_str(), dq->qname->toString().c_str(), QType(dq->qtype).getName().c_str(), dq->getHeader()->id);
}
}
}
if (!d_fp) {
if (!d_verboseOnly || g_verbose) {
if (d_includeTimestamp) {
- infolog("[%u.%u] Answer to %s for %s %s (%s) with id %d", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id);
+ infolog("[%u.%u] Answer to %s for %s %s (%s) with id %d", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->getHeader()->rcode), dr->getHeader()->id);
}
else {
- infolog("Answer to %s for %s %s (%s) with id %d", dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->dh->rcode), dr->dh->id);
+ infolog("Answer to %s for %s %s (%s) with id %d", dr->remote->toStringWithPort(), dr->qname->toString(), QType(dr->qtype).getName(), RCode::to_s(dr->getHeader()->rcode), dr->getHeader()->id);
}
}
}
else {
if (d_includeTimestamp) {
- fprintf(d_fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %d\n", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id);
+ fprintf(d_fp.get(), "[%llu.%lu] Answer to %s for %s %s (%s) with id %d\n", static_cast<unsigned long long>(dr->queryTime->tv_sec), static_cast<unsigned long>(dr->queryTime->tv_nsec), dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->getHeader()->rcode).c_str(), dr->getHeader()->id);
}
else {
- fprintf(d_fp.get(), "Answer to %s for %s %s (%s) with id %d\n", dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->dh->rcode).c_str(), dr->dh->id);
+ fprintf(d_fp.get(), "Answer to %s for %s %s (%s) with id %d\n", dr->remote->toStringWithPort().c_str(), dr->qname->toString().c_str(), QType(dr->qtype).getName().c_str(), RCode::to_s(dr->getHeader()->rcode).c_str(), dr->getHeader()->id);
}
}
return Action::None;
public:
DNSAction::Action operator()(DNSQuestion* dq, std::string* ruleresult) const override
{
- dq->dh->cd = true;
+ dq->getHeader()->cd = true;
return Action::None;
}
std::string toString() const override
static thread_local std::string data;
data.clear();
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(dq->dh);
- DnstapMessage message(data, !dh->qr ? DnstapMessage::MessageType::client_query : DnstapMessage::MessageType::client_response, d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->dh), dq->len, dq->queryTime, nullptr);
+ DnstapMessage message(data, !dq->getHeader()->qr ? DnstapMessage::MessageType::client_query : DnstapMessage::MessageType::client_response, d_identity, dq->remote, dq->local, dq->tcp, reinterpret_cast<const char*>(dq->getData().data()), dq->getData().size(), dq->queryTime, nullptr);
{
if (d_alterFunc) {
std::lock_guard<std::mutex> lock(g_luamutex);
gettime(&now, true);
data.clear();
- DnstapMessage message(data, DnstapMessage::MessageType::client_response, d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->dh), dr->len, dr->queryTime, &now);
+ DnstapMessage message(data, DnstapMessage::MessageType::client_response, d_identity, dr->remote, dr->local, dr->tcp, reinterpret_cast<const char*>(dr->getData().data()), dr->getData().size(), dr->queryTime, &now);
{
if (d_alterFunc) {
std::lock_guard<std::mutex> lock(g_luamutex);
class HTTPStatusAction: public DNSAction
{
public:
- HTTPStatusAction(int code, const std::string& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
+ HTTPStatusAction(int code, const std::vector<uint8_t>& body, const std::string& contentType): d_body(body), d_contentType(contentType), d_code(code)
{
}
return Action::None;
}
- dq->du->setHTTPResponse(d_code, d_body, d_contentType);
- dq->dh->qr = true; // for good measure
- setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
+ dq->du->setHTTPResponse(d_code, std::vector<uint8_t>(d_body), d_contentType);
+ dq->getHeader()->qr = true; // for good measure
+ setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
return Action::HeaderModify;
}
ResponseConfig d_responseConfig;
private:
- std::string d_body;
+ std::vector<uint8_t> d_body;
std::string d_contentType;
int d_code;
};
return Action::None;
}
- setResponseHeadersFromConfig(*dq->dh, d_responseConfig);
+ setResponseHeadersFromConfig(*dq->getHeader(), d_responseConfig);
return Action::Allow;
}
#ifdef HAVE_DNS_OVER_HTTPS
luaCtx.writeFunction("HTTPStatusAction", [](uint16_t status, std::string body, boost::optional<std::string> contentType, boost::optional<responseParams_t> vars) {
- auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, body, contentType ? *contentType : ""));
+ auto ret = std::shared_ptr<DNSAction>(new HTTPStatusAction(status, std::vector<uint8_t>(body.begin(), body.end()), contentType ? *contentType : ""));
auto hsa = std::dynamic_pointer_cast<HTTPStatusAction>(ret);
parseResponseConfig(vars, hsa->d_responseConfig);
return ret;
luaCtx.registerMember<const DNSName (DNSQuestion::*)>("qname", [](const DNSQuestion& dq) -> const DNSName { return *dq.qname; }, [](DNSQuestion& dq, const DNSName newName) { (void) newName; });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qtype", [](const DNSQuestion& dq) -> uint16_t { return dq.qtype; }, [](DNSQuestion& dq, uint16_t newType) { (void) newType; });
luaCtx.registerMember<uint16_t (DNSQuestion::*)>("qclass", [](const DNSQuestion& dq) -> uint16_t { return dq.qclass; }, [](DNSQuestion& dq, uint16_t newClass) { (void) newClass; });
- luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.dh->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.dh->rcode = newRCode; });
+ luaCtx.registerMember<int (DNSQuestion::*)>("rcode", [](const DNSQuestion& dq) -> int { return dq.getHeader()->rcode; }, [](DNSQuestion& dq, int newRCode) { dq.getHeader()->rcode = newRCode; });
luaCtx.registerMember<const ComboAddress (DNSQuestion::*)>("remoteaddr", [](const DNSQuestion& dq) -> const ComboAddress { return *dq.remote; }, [](DNSQuestion& dq, const ComboAddress newRemote) { (void) newRemote; });
/* DNSDist DNSQuestion */
- luaCtx.registerMember("dh", &DNSQuestion::dh);
- luaCtx.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.len; }, [](DNSQuestion& dq, uint16_t newlen) { dq.len = newlen; });
- luaCtx.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; });
- luaCtx.registerMember<size_t (DNSQuestion::*)>("size", [](const DNSQuestion& dq) -> size_t { return dq.size; }, [](DNSQuestion& dq, size_t newSize) { (void) newSize; });
+ luaCtx.registerMember<dnsheader* (DNSQuestion::*)>("dh", [](const DNSQuestion& dq) -> dnsheader* { return const_cast<DNSQuestion&>(dq).getHeader(); }, [](DNSQuestion& dq, const dnsheader* dh) { *(dq.getHeader()) = *dh; });
+ luaCtx.registerMember<uint16_t (DNSQuestion::*)>("len", [](const DNSQuestion& dq) -> uint16_t { return dq.getData().size(); }, [](DNSQuestion& dq, uint16_t newlen) { dq.getMutableData().resize(newlen); });
+ luaCtx.registerMember<uint8_t (DNSQuestion::*)>("opcode", [](const DNSQuestion& dq) -> uint8_t { return dq.getHeader()->opcode; }, [](DNSQuestion& dq, uint8_t newOpcode) { (void) newOpcode; });
+ #warning FIXME we need to provide Lua with a way to update the size
+ //luaCtx.registerMember<size_t (DNSQuestion::*)>("size", [](const DNSQuestion& dq) -> size_t { return dq.getData().size(); }, [](DNSQuestion& dq, size_t newSize) { (void) newSize; });
luaCtx.registerMember<bool (DNSQuestion::*)>("tcp", [](const DNSQuestion& dq) -> bool { return dq.tcp; }, [](DNSQuestion& dq, bool newTcp) { (void) newTcp; });
luaCtx.registerMember<bool (DNSQuestion::*)>("skipCache", [](const DNSQuestion& dq) -> bool { return dq.skipCache; }, [](DNSQuestion& dq, bool newSkipCache) { dq.skipCache = newSkipCache; });
luaCtx.registerMember<bool (DNSQuestion::*)>("useECS", [](const DNSQuestion& dq) -> bool { return dq.useECS; }, [](DNSQuestion& dq, bool useECS) { dq.useECS = useECS; });
luaCtx.registerMember<const DNSName (DNSResponse::*)>("qname", [](const DNSResponse& dq) -> const DNSName { return *dq.qname; }, [](DNSResponse& dq, const DNSName newName) { (void) newName; });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("qtype", [](const DNSResponse& dq) -> uint16_t { return dq.qtype; }, [](DNSResponse& dq, uint16_t newType) { (void) newType; });
luaCtx.registerMember<uint16_t (DNSResponse::*)>("qclass", [](const DNSResponse& dq) -> uint16_t { return dq.qclass; }, [](DNSResponse& dq, uint16_t newClass) { (void) newClass; });
- luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.dh->rcode; }, [](DNSResponse& dq, int newRCode) { dq.dh->rcode = newRCode; });
+ luaCtx.registerMember<int (DNSResponse::*)>("rcode", [](const DNSResponse& dq) -> int { return dq.getHeader()->rcode; }, [](DNSResponse& dq, int newRCode) { dq.getHeader()->rcode = newRCode; });
luaCtx.registerMember<const ComboAddress (DNSResponse::*)>("remoteaddr", [](const DNSResponse& dq) -> const ComboAddress { return *dq.remote; }, [](DNSResponse& dq, const ComboAddress newRemote) { (void) newRemote; });
- luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return dr.dh; }, [](DNSResponse& dr, dnsheader * newdh) { dr.dh = newdh; });
- luaCtx.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.len; }, [](DNSResponse& dq, uint16_t newlen) { dq.len = newlen; });
- luaCtx.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.dh->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; });
- luaCtx.registerMember<size_t (DNSResponse::*)>("size", [](const DNSResponse& dq) -> size_t { return dq.size; }, [](DNSResponse& dq, size_t newSize) { (void) newSize; });
+ luaCtx.registerMember<dnsheader* (DNSResponse::*)>("dh", [](const DNSResponse& dr) -> dnsheader* { return const_cast<DNSResponse&>(dr).getHeader(); }, [](DNSResponse& dr, const dnsheader* dh) { *(dr.getHeader()) = *dh; });
+ luaCtx.registerMember<uint16_t (DNSResponse::*)>("len", [](const DNSResponse& dq) -> uint16_t { return dq.getData().size(); }, [](DNSResponse& dq, uint16_t newlen) { dq.getMutableData().resize(newlen); });
+ luaCtx.registerMember<uint8_t (DNSResponse::*)>("opcode", [](const DNSResponse& dq) -> uint8_t { return dq.getHeader()->opcode; }, [](DNSResponse& dq, uint8_t newOpcode) { (void) newOpcode; });
+ #warning FIXME we need to provide Lua with a way to update the size
+ //luaCtx.registerMember<size_t (DNSResponse::*)>("size", [](const DNSResponse& dq) -> size_t { return dq.size; }, [](DNSResponse& dq, size_t newSize) { (void) newSize; });
luaCtx.registerMember<bool (DNSResponse::*)>("tcp", [](const DNSResponse& dq) -> bool { return dq.tcp; }, [](DNSResponse& dq, bool newTcp) { (void) newTcp; });
luaCtx.registerMember<bool (DNSResponse::*)>("skipCache", [](const DNSResponse& dq) -> bool { return dq.skipCache; }, [](DNSResponse& dq, bool newSkipCache) { dq.skipCache = newSkipCache; });
- luaCtx.registerFunction<void(DNSResponse::*)(std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc)>("editTTLs", [](const DNSResponse& dr, std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc) {
- editDNSPacketTTL((char*) dr.dh, dr.len, editFunc);
+ luaCtx.registerFunction<void(DNSResponse::*)(std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc)>("editTTLs", [](DNSResponse& dr, std::function<uint32_t(uint8_t section, uint16_t qclass, uint16_t qtype, uint32_t ttl)> editFunc) {
+ editDNSPacketTTL(reinterpret_cast<char *>(dr.getMutableData().data()), dr.getData().size(), editFunc);
});
luaCtx.registerFunction<std::string(DNSResponse::*)(void)const>("getTrailingData", [](const DNSResponse& dq) {
return dq.getTrailingData();
if (dq.du == nullptr) {
return;
}
- dq.du->setHTTPResponse(statusCode, body, contentType ? *contentType : "");
+ std::vector<uint8_t> vect(body.begin(), body.end());
+ dq.du->setHTTPResponse(statusCode, std::move(vect), contentType ? *contentType : "");
});
#endif /* HAVE_DNS_OVER_HTTPS */
headers->push_back({ boost::to_lower_copy(header.first), header.second });
}
}
- return std::make_shared<DOHResponseMapEntry>(regex, status, content, headers);
+ return std::make_shared<DOHResponseMapEntry>(regex, status, std::vector<uint8_t>(content.begin(), content.end()), headers);
});
}
StopWatch sw;
sw.start();
for(int n=0; n < times; ++n) {
- const item& i = items[n % items.size()];
- DNSQuestion dq(&i.qname, i.qtype, i.qclass, 0, &i.rem, &i.rem, (struct dnsheader*)&i.packet[0], i.packet.size(), i.packet.size(), false, &sw.d_start);
- if(rule->matches(&dq))
+ item& i = items[n % items.size()];
+ DNSQuestion dq(&i.qname, i.qtype, i.qclass, &i.rem, &i.rem, i.packet, false, &sw.d_start);
+ if (rule->matches(&dq)) {
matches++;
+ }
}
double udiff=sw.udiff();
g_outputBuffer=(boost::format("Had %d matches out of %d, %.1f qps, in %.1f usec\n") % matches % times % (1000000*(1.0*times/udiff)) % udiff).str();
luaCtx.writeFunction("setECSOverride", [](bool override) { g_ECSOverride=override; });
- luaCtx.writeFunction("setPreserveTrailingData", [](bool preserve) { g_preserveTrailingData = preserve; });
-
luaCtx.writeFunction("showDynBlocks", []() {
setLuaNoSideEffect();
auto slow = g_dynblockNMG.getCopy();
m.setTime(ts.tv_sec, ts.tv_nsec / 1000);
}
- m.setRequest(d_dq.uniqueId ? *d_dq.uniqueId : getUniqueID(), d_requestor ? *d_requestor : *d_dq.remote, d_responder ? *d_responder : *d_dq.local, d_question ? d_question->d_name : *d_dq.qname, d_question ? d_question->d_type : d_dq.qtype, d_question ? d_question->d_class : d_dq.qclass, d_dq.dh->id, d_dq.tcp, d_bytes ? *d_bytes : d_dq.len);
+ m.setRequest(d_dq.uniqueId ? *d_dq.uniqueId : getUniqueID(), d_requestor ? *d_requestor : *d_dq.remote, d_responder ? *d_responder : *d_dq.local, d_question ? d_question->d_name : *d_dq.qname, d_question ? d_question->d_type : d_dq.qtype, d_question ? d_question->d_class : d_dq.qclass, d_dq.getHeader()->id, d_dq.tcp, d_bytes ? *d_bytes : d_dq.getData().size());
if (d_serverIdentity) {
m.setServerIdentity(*d_serverIdentity);
}
if (d_dr != nullptr) {
- m.setResponseCode(d_rcode ? *d_rcode : d_dr->dh->rcode);
- m.addRRsFromPacket(reinterpret_cast<const char*>(d_dr->dh), d_dr->len, d_includeCNAME);
+ m.setResponseCode(d_rcode ? *d_rcode : d_dr->getHeader()->rcode);
+ m.addRRsFromPacket(reinterpret_cast<const char*>(d_dr->getData().data()), d_dr->getData().size(), d_includeCNAME);
}
else {
if (d_rcode) {
std::string qname = dq.qname->toStringNoDot();
const uint32_t socketFamily = dq.remote->isIPv4() ? 1 : 2;
const uint32_t socketProtocol = dq.tcp ? 2 : 1;
- const uint32_t queryType = dq.dh->qr ? 2 : 1;
- const uint32_t querySize = (uint32_t) dq.len;
- const uint32_t queryID = (uint32_t) ntohs(dq.dh->id);
+ const uint32_t queryType = dq.getHeader()->qr ? 2 : 1;
+ const uint32_t querySize = (uint32_t) dq.getData().size();
+ const uint32_t queryID = (uint32_t) ntohs(dq.getHeader()->id);
const uint32_t qType = (uint32_t) dq.qtype;
const uint32_t qClass = (uint32_t) dq.qclass;
return;
}
- uint16_t responseSize = response.d_buffer.size();
- response.d_buffer.resize(responseSize + static_cast<size_t>(512));
- size_t responseCapacity = response.d_buffer.size();
- auto responseAsCharArray = reinterpret_cast<char*>(&response.d_buffer.at(0));
-
auto& ids = response.d_idstate;
- unsigned int consumed;
- if (!responseContentMatches(responseAsCharArray, responseSize, ids.qname, ids.qtype, ids.qclass, response.d_connection->getRemote(), consumed)) {
+ unsigned int qnameWireLength;
+ if (!responseContentMatches(response.d_buffer, ids.qname, ids.qtype, ids.qclass, response.d_connection->getRemote(), qnameWireLength)) {
return;
}
- auto dh = reinterpret_cast<struct dnsheader*>(responseAsCharArray);
- uint16_t addRoom = 0;
- DNSResponse dr = makeDNSResponseFromIDState(ids, dh, responseCapacity, responseSize, true);
- if (dr.dnsCryptQuery) {
- addRoom = DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE;
- }
+ DNSResponse dr = makeDNSResponseFromIDState(ids, response.d_buffer, true);
- memcpy(&response.d_cleartextDH, dr.dh, sizeof(response.d_cleartextDH));
+ memcpy(&response.d_cleartextDH, dr.getHeader(), sizeof(response.d_cleartextDH));
- std::vector<uint8_t> rewrittenResponse;
- if (!processResponse(&responseAsCharArray, &responseSize, &responseCapacity, state->d_threadData.localRespRulactions, dr, addRoom, rewrittenResponse, false)) {
+ if (!processResponse(response.d_buffer, state->d_threadData.localRespRulactions, dr, false)) {
return;
}
- if (!rewrittenResponse.empty()) {
- /* responseSize has been updated as well but we don't really care since it will match
- the capacity of rewrittenResponse anyway */
- response.d_buffer = std::move(rewrittenResponse);
- } else {
- /* the size might have been updated (shrinked) if we removed the whole OPT RR, for example) */
- response.d_buffer.resize(responseSize);
- }
-
if (state->d_isXFR && !state->d_xfrStarted) {
/* don't bother parsing the content of the response for now */
state->d_xfrStarted = true;
struct timespec queryRealTime;
gettime(&queryRealTime, true);
- auto query = reinterpret_cast<char*>(&state->d_buffer.at(0));
std::shared_ptr<DNSCryptQuery> dnsCryptQuery{nullptr};
- auto dnsCryptResponse = checkDNSCryptQuery(*state->d_ci.cs, query, state->d_querySize, dnsCryptQuery, queryRealTime.tv_sec, true);
+ auto dnsCryptResponse = checkDNSCryptQuery(*state->d_ci.cs, state->d_buffer, dnsCryptQuery, queryRealTime.tv_sec, true);
if (dnsCryptResponse) {
TCPResponse response;
- response.d_buffer = std::move(*dnsCryptResponse);
state->d_state = IncomingTCPConnectionState::State::idle;
++state->d_currentQueriesCount;
return state->sendResponse(state, now, std::move(response));
}
- const auto& dh = reinterpret_cast<dnsheader*>(query);
+ const auto* dh = reinterpret_cast<dnsheader*>(state->d_buffer.data());
if (!checkQueryHeaders(dh)) {
return IOState::NeedRead;
}
uint16_t qtype, qclass;
- unsigned int consumed = 0;
- DNSName qname(query, state->d_querySize, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, &state->d_origDest, &state->d_ci.remote, reinterpret_cast<dnsheader*>(query), state->d_buffer.size(), state->d_querySize, true, &queryRealTime);
+ unsigned int qnameWireLength = 0;
+ DNSName qname(reinterpret_cast<const char*>(state->d_buffer.data()), state->d_buffer.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength);
+ DNSQuestion dq(&qname, qtype, qclass, &state->d_origDest, &state->d_ci.remote, state->d_buffer, true, &queryRealTime);
dq.dnsCryptQuery = std::move(dnsCryptQuery);
dq.sni = state->d_handler.getServerNameIndication();
return IOState::Done;
}
+ // the buffer might have been invalidated by now
+ dh = dq.getHeader();
if (result == ProcessQueryResult::SendAnswer) {
- state->d_buffer.resize(dq.len);
TCPResponse response;
response.d_selfGenerated = true;
response.d_buffer = std::move(state->d_buffer);
setIDStateFromDNSQuestion(ids, dq, std::move(qname));
ids.origID = ntohs(dh->id);
- const uint8_t sizeBytes[] = { static_cast<uint8_t>(dq.len / 256), static_cast<uint8_t>(dq.len % 256) };
+ uint16_t queryLen = state->d_buffer.size();
+ const uint8_t sizeBytes[] = { static_cast<uint8_t>(queryLen / 256), static_cast<uint8_t>(queryLen % 256) };
/* prepend the size. Yes, this is not the most efficient way but it prevents mistakes
that could occur if we had to deal with the size during the processing,
especially alignment issues */
- /* first we need to resize to the size that is actually used, since we allocated more to be able to insert
- EDNS or Proxy Protocol values */
- dq.size = state->d_buffer.size();
- state->d_buffer.resize(dq.len);
state->d_buffer.insert(state->d_buffer.begin(), sizeBytes, sizeBytes + 2);
- dq.len = dq.len + 2;
- dq.dh = reinterpret_cast<dnsheader*>(&state->d_buffer.at(0));
- state->d_buffer.resize(dq.len);
bool proxyProtocolPayloadAdded = false;
std::string proxyProtocolPayload;
iostate = state->d_handler.tryRead(state->d_buffer, state->d_currentPos, state->d_querySize);
if (iostate == IOState::Done) {
DEBUGLOG("query received");
+ state->d_buffer.resize(state->d_querySize);
iostate = handleQuery(state, now);
// if the query has been passed to a backend, or dropped, we can start
#include "dnsparser.hh"
#include "xpf.hh"
-bool addXPF(DNSQuestion& dq, uint16_t optionCode, bool preserveTrailingData)
+bool addXPF(DNSQuestion& dq, uint16_t optionCode)
{
std::string payload = generateXPFPayload(dq.tcp, *dq.remote, *dq.local);
uint8_t root = '\0';
drh.d_clen = htons(payload.size());
size_t recordHeaderLen = sizeof(root) + sizeof(drh);
- size_t available = dq.size - dq.len;
-
- if ((payload.size() + recordHeaderLen) > available) {
+ if (!dq.hasRoomFor(payload.size() + recordHeaderLen)) {
return false;
}
size_t xpfSize = sizeof(root) + sizeof(drh) + payload.size();
- uint32_t realPacketLen = getDNSPacketLength(reinterpret_cast<const char*>(dq.dh), dq.len);
- if (realPacketLen < dq.len && preserveTrailingData) {
- size_t toMove = dq.len - realPacketLen;
- memmove(reinterpret_cast<char*>(dq.dh) + realPacketLen + xpfSize, reinterpret_cast<const char*>(dq.dh) + realPacketLen, toMove);
- dq.len += xpfSize;
- }
- else {
- dq.len = realPacketLen + xpfSize;
- }
+ auto& data = dq.getMutableData();
+ uint32_t realPacketLen = getDNSPacketLength(reinterpret_cast<const char*>(data.data()), data.size());
+ data.resize(realPacketLen + xpfSize);
size_t pos = realPacketLen;
- memcpy(reinterpret_cast<char*>(dq.dh) + pos, &root, sizeof(root));
+ memcpy(reinterpret_cast<char*>(&data.at(pos)), &root, sizeof(root));
pos += sizeof(root);
- memcpy(reinterpret_cast<char*>(dq.dh) + pos, &drh, sizeof(drh));
+ memcpy(reinterpret_cast<char*>(&data.at(pos)), &drh, sizeof(drh));
pos += sizeof(drh);
- memcpy(reinterpret_cast<char*>(dq.dh) + pos, payload.data(), payload.size());
+ memcpy(reinterpret_cast<char*>(&data.at(pos)), payload.data(), payload.size());
pos += payload.size();
- dq.dh->arcount = htons(ntohs(dq.dh->arcount) + 1);
+ dq.getHeader()->arcount = htons(ntohs(dq.getHeader()->arcount) + 1);
return true;
}
#include "dnsdist.hh"
-bool addXPF(DNSQuestion& dq, uint16_t optionCode, bool preserveTrailingData);
+bool addXPF(DNSQuestion& dq, uint16_t optionCode);
bool g_servFailOnNoPolicy{false};
bool g_truncateTC{false};
bool g_fixupCase{false};
-bool g_preserveTrailingData{false};
std::set<std::string> g_capabilitiesToRetain;
-static void truncateTC(char* packet, uint16_t* len, size_t responseSize, unsigned int consumed)
-try
+static size_t const s_initialUDPPacketBufferSize = s_maxPacketCacheEntrySize + DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE;
+static_assert(s_initialUDPPacketBufferSize <= UINT16_MAX, "Packet size should fit in a uint16_t");
+
+static void truncateTC(std::vector<uint8_t>& packet, unsigned int qnameWireLength)
{
- bool hadEDNS = false;
- uint16_t payloadSize = 0;
- uint16_t z = 0;
+ try
+ {
+ bool hadEDNS = false;
+ uint16_t payloadSize = 0;
+ uint16_t z = 0;
- if (g_addEDNSToSelfGeneratedResponses) {
- hadEDNS = getEDNSUDPPayloadSizeAndZ(packet, *len, &payloadSize, &z);
- }
+ if (g_addEDNSToSelfGeneratedResponses) {
+ hadEDNS = getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(packet.data()), packet.size(), &payloadSize, &z);
+ }
- *len=static_cast<uint16_t>(sizeof(dnsheader)+consumed+DNS_TYPE_SIZE+DNS_CLASS_SIZE);
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet);
- dh->ancount = dh->arcount = dh->nscount = 0;
+ packet.resize(static_cast<uint16_t>(sizeof(dnsheader)+qnameWireLength+DNS_TYPE_SIZE+DNS_CLASS_SIZE));
+ struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet.data());
+ dh->ancount = dh->arcount = dh->nscount = 0;
- if (hadEDNS) {
- addEDNS(dh, *len, responseSize, z & EDNS_HEADER_FLAG_DO, payloadSize, 0);
+ if (hadEDNS) {
+ addEDNS(packet, z & EDNS_HEADER_FLAG_DO, payloadSize, 0);
+ }
+ }
+ catch(...)
+ {
+ ++g_stats.truncFail;
}
-}
-catch(...)
-{
- g_stats.truncFail++;
}
struct DelayedPacket
{
int fd;
- string packet;
+ std::vector<uint8_t> packet;
ComboAddress destination;
ComboAddress origDest;
void operator()()
{
ssize_t res;
if(origDest.sin4.sin_family == 0) {
- res = sendto(fd, packet.c_str(), packet.size(), 0, (struct sockaddr*)&destination, destination.getSocklen());
+ res = sendto(fd, packet.data(), packet.size(), 0, (struct sockaddr*)&destination, destination.getSocklen());
}
else {
- res = sendfromto(fd, packet.c_str(), packet.size(), 0, origDest, destination);
+ res = sendfromto(fd, packet.data(), packet.size(), 0, origDest, destination);
}
if (res == -1) {
int err = errno;
std::string DNSQuestion::getTrailingData() const
{
- const char* message = reinterpret_cast<const char*>(this->dh);
- const uint16_t messageLen = getDNSPacketLength(message, this->len);
- return std::string(message + messageLen, this->len - messageLen);
+ const char* message = reinterpret_cast<const char*>(this->getHeader());
+ const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
+ return std::string(message + messageLen, this->getData().size() - messageLen);
}
bool DNSQuestion::setTrailingData(const std::string& tail)
{
- char* message = reinterpret_cast<char*>(this->dh);
- const uint16_t messageLen = getDNSPacketLength(message, this->len);
- const uint16_t tailLen = tail.size();
- if (tailLen > (this->size - messageLen)) {
- vinfolog("Trailing data update failed, the new trailing data size was %d, the existing message length was %d, packet size was %d and buffer size %d", tail.size(), messageLen, this->len, this->size);
- return false;
- }
-
- /* Update length and copy data from the Lua string. */
- this->len = messageLen + tailLen;
- if (tailLen > 0) {
- tail.copy(message + messageLen, tailLen);
+ const char* message = reinterpret_cast<const char*>(this->data.data());
+ const uint16_t messageLen = getDNSPacketLength(message, this->data.size());
+ this->data.resize(messageLen);
+ if (tail.size() > 0) {
+ this->data.insert(this->data.end(), tail.begin(), tail.end());
}
return true;
}
doAvg(g_stats.latencyAvg1000000, udiff, 1000000);
}
-bool responseContentMatches(const char* response, const uint16_t responseLen, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& consumed)
+bool responseContentMatches(const std::vector<uint8_t>& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength)
{
- if (responseLen < sizeof(dnsheader)) {
+ if (response.size() < sizeof(dnsheader)) {
return false;
}
- const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(response);
+ const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(response.data());
if (dh->qr == 0) {
++g_stats.nonCompliantResponses;
return false;
uint16_t rqtype, rqclass;
DNSName rqname;
try {
- rqname=DNSName(response, responseLen, sizeof(dnsheader), false, &rqtype, &rqclass, &consumed);
+ rqname = DNSName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, &rqtype, &rqclass, &qnameWireLength);
}
- catch(const std::exception& e) {
- if(responseLen > 0 && static_cast<size_t>(responseLen) > sizeof(dnsheader)) {
+ catch (const std::exception& e) {
+ if(response.size() > 0 && static_cast<size_t>(response.size()) > sizeof(dnsheader)) {
infolog("Backend %s sent us a response with id %d that did not parse: %s", remote.toStringWithPort(), ntohs(dh->id), e.what());
}
++g_stats.nonCompliantResponses;
static const uint16_t rdMask = 1 << FLAGS_RD_OFFSET;
static const uint16_t cdMask = 1 << FLAGS_CD_OFFSET;
static const uint16_t restoreFlagsMask = UINT16_MAX & ~(rdMask | cdMask);
- uint16_t * flags = getFlagsFromDNSHeader(dh);
+ uint16_t* flags = getFlagsFromDNSHeader(dh);
/* clear the flags we are about to restore */
*flags &= restoreFlagsMask;
/* only keep the flags we want to restore */
static bool fixUpQueryTurnedResponse(DNSQuestion& dq, const uint16_t origFlags)
{
- restoreFlags(dq.dh, origFlags);
+ restoreFlags(dq.getHeader(), origFlags);
return addEDNSToQueryTurnedResponse(dq);
}
-static bool fixUpResponse(char** response, uint16_t* responseLen, size_t* responseSize, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, std::vector<uint8_t>& rewrittenResponse, uint16_t addRoom, bool* zeroScope)
+static bool fixUpResponse(std::vector<uint8_t>& response, const DNSName& qname, uint16_t origFlags, bool ednsAdded, bool ecsAdded, bool* zeroScope)
{
- if (*responseLen < sizeof(dnsheader)) {
+ if (response.size() < sizeof(dnsheader)) {
return false;
}
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(*response);
+ struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
restoreFlags(dh, origFlags);
- if (*responseLen == sizeof(dnsheader)) {
+ if (response.size() == sizeof(dnsheader)) {
return true;
}
if (g_fixupCase) {
const auto& realname = qname.getStorage();
- if (*responseLen >= (sizeof(dnsheader) + realname.length())) {
- memcpy(*response + sizeof(dnsheader), realname.c_str(), realname.length());
+ if (response.size() >= (sizeof(dnsheader) + realname.length())) {
+ memcpy(&response.at(sizeof(dnsheader)), realname.c_str(), realname.length());
}
}
size_t optLen = 0;
bool last = false;
- const std::string responseStr(*response, *responseLen);
+#warning FIXME: save an alloc+copy
+ const std::string responseStr(reinterpret_cast<const char*>(response.data()), response.size());
int res = locateEDNSOptRR(responseStr, &optStart, &optLen, &last);
if (res == 0) {
therefore we need to remove it entirely */
if (last) {
/* simply remove the last AR */
- *responseLen -= optLen;
+ response.resize(response.size() - optLen);
+ dh = reinterpret_cast<struct dnsheader*>(response.data());
uint16_t arcount = ntohs(dh->arcount);
arcount--;
dh->arcount = htons(arcount);
}
else {
/* Removing an intermediary RR could lead to compression error */
+ std::vector<uint8_t> rewrittenResponse;
if (rewriteResponseWithoutEDNS(responseStr, rewrittenResponse) == 0) {
- *responseLen = rewrittenResponse.size();
- if (addRoom && (UINT16_MAX - *responseLen) > addRoom) {
- rewrittenResponse.reserve(*responseLen + addRoom);
- }
- *responseSize = rewrittenResponse.capacity();
- *response = reinterpret_cast<char*>(rewrittenResponse.data());
+ response = std::move(rewrittenResponse);
}
else {
warnlog("Error rewriting content");
/* nothing after the OPT RR, we can simply remove the
ECS option */
size_t existingOptLen = optLen;
- removeEDNSOptionFromOPT(*response + optStart, &optLen, EDNSOptionCode::ECS);
- *responseLen -= (existingOptLen - optLen);
+ removeEDNSOptionFromOPT(reinterpret_cast<char*>(&response.at(optStart)), &optLen, EDNSOptionCode::ECS);
+ response.resize(response.size() - (existingOptLen - optLen));
}
else {
+ std::vector<uint8_t> rewrittenResponse;
/* Removing an intermediary RR could lead to compression error */
if (rewriteResponseWithoutEDNSOption(responseStr, EDNSOptionCode::ECS, rewrittenResponse) == 0) {
- *responseLen = rewrittenResponse.size();
- if (addRoom && (UINT16_MAX - *responseLen) > addRoom) {
- rewrittenResponse.reserve(*responseLen + addRoom);
- }
- *responseSize = rewrittenResponse.capacity();
- *response = reinterpret_cast<char*>(rewrittenResponse.data());
+ response = std::move(rewrittenResponse);
}
else {
warnlog("Error rewriting content");
}
#ifdef HAVE_DNSCRYPT
-static bool encryptResponse(char* response, uint16_t* responseLen, size_t responseSize, bool tcp, std::shared_ptr<DNSCryptQuery> dnsCryptQuery, dnsheader** dh, dnsheader* dhCopy)
+static bool encryptResponse(std::vector<uint8_t>& response, bool tcp, std::shared_ptr<DNSCryptQuery> dnsCryptQuery)
{
if (dnsCryptQuery) {
- uint16_t encryptedResponseLen = 0;
-
- /* save the original header before encrypting it in place */
- if (dh != nullptr && *dh != nullptr && dhCopy != nullptr) {
- memcpy(dhCopy, *dh, sizeof(dnsheader));
- *dh = dhCopy;
- }
-
- int res = dnsCryptQuery->encryptResponse(response, *responseLen, responseSize, tcp, &encryptedResponseLen);
- if (res == 0) {
- *responseLen = encryptedResponseLen;
- } else {
+ #warning FIXME should not be harcoded
+ int res = dnsCryptQuery->encryptResponse(response, tcp ? std::numeric_limits<uint16_t>::max() : 4096, tcp);
+ if (res != 0) {
/* dropping response */
vinfolog("Error encrypting the response, dropping.");
return false;
return true;
break;
case DNSResponseAction::Action::ServFail:
- dr.dh->rcode = RCode::ServFail;
+ dr.getHeader()->rcode = RCode::ServFail;
return true;
break;
/* non-terminal actions follow */
return true;
}
-bool processResponse(char** response, uint16_t* responseLen, size_t* responseSize, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, size_t addRoom, std::vector<uint8_t>& rewrittenResponse, bool muted)
+bool processResponse(std::vector<uint8_t>& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted)
{
if (!applyRulesToResponse(localRespRulactions, dr)) {
return false;
}
bool zeroScope = false;
- if (!fixUpResponse(response, responseLen, responseSize, *dr.qname, dr.origFlags, dr.ednsAdded, dr.ecsAdded, rewrittenResponse, addRoom, dr.useZeroScope ? &zeroScope : nullptr)) {
+ if (!fixUpResponse(response, *dr.qname, dr.origFlags, dr.ednsAdded, dr.ecsAdded, dr.useZeroScope ? &zeroScope : nullptr)) {
return false;
}
- if (dr.packetCache && !dr.skipCache && *responseLen <= s_maxPacketCacheEntrySize) {
+ if (dr.packetCache && !dr.skipCache && response.size() <= s_maxPacketCacheEntrySize) {
if (!dr.useZeroScope) {
/* if the query was not suitable for zero-scope, for
example because it had an existing ECS entry so the hash is
zeroScope = false;
}
// if zeroScope, pass the pre-ECS hash-key and do not pass the subnet to the cache
- dr.packetCache->insert(zeroScope ? dr.cacheKeyNoECS : dr.cacheKey, zeroScope ? boost::none : dr.subnet, dr.origFlags, dr.dnssecOK, *dr.qname, dr.qtype, dr.qclass, *response, *responseLen, dr.tcp, dr.dh->rcode, dr.tempFailureTTL);
+ dr.packetCache->insert(zeroScope ? dr.cacheKeyNoECS : dr.cacheKey, zeroScope ? boost::none : dr.subnet, dr.origFlags, dr.dnssecOK, *dr.qname, dr.qtype, dr.qclass, response, dr.tcp, dr.getHeader()->rcode, dr.tempFailureTTL);
}
#ifdef HAVE_DNSCRYPT
if (!muted) {
- if (!encryptResponse(*response, responseLen, *responseSize, dr.tcp, dr.dnsCryptQuery, nullptr, nullptr)) {
+ if (!encryptResponse(response, dr.tcp, dr.dnsCryptQuery)) {
return false;
}
}
return true;
}
-static bool sendUDPResponse(int origFD, const char* response, const uint16_t responseLen, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
+static bool sendUDPResponse(int origFD, const std::vector<uint8_t>& response, const int delayMsec, const ComboAddress& origDest, const ComboAddress& origRemote)
{
if(delayMsec && g_delay) {
- DelayedPacket dp{origFD, string(response,responseLen), origRemote, origDest};
+ DelayedPacket dp{origFD, response, origRemote, origDest};
g_delay->submit(dp, delayMsec);
}
else {
ssize_t res;
if(origDest.sin4.sin_family == 0) {
- res = sendto(origFD, response, responseLen, 0, reinterpret_cast<const struct sockaddr*>(&origRemote), origRemote.getSocklen());
+ res = sendto(origFD, response.data(), response.size(), 0, reinterpret_cast<const struct sockaddr*>(&origRemote), origRemote.getSocklen());
}
else {
- res = sendfromto(origFD, response, responseLen, 0, origDest, origRemote);
+ res = sendfromto(origFD, response.data(), response.size(), 0, origDest, origRemote);
}
if (res == -1) {
int err = errno;
// listens on a dedicated socket, lobs answers from downstream servers to original requestors
void responderThread(std::shared_ptr<DownstreamState> dss)
-try {
+{
+ try {
setThreadName("dnsdist/respond");
auto localRespRulactions = g_resprulactions.getLocal();
- char packet[s_maxPacketCacheEntrySize + DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE];
- static_assert(sizeof(packet) <= UINT16_MAX, "Packet size should fit in a uint16_t");
+ std::vector<uint8_t> response(s_initialUDPPacketBufferSize);
+
/* when the answer is encrypted in place, we need to get a copy
of the original header before encryption to fill the ring buffer */
dnsheader cleartextDH;
- vector<uint8_t> rewrittenResponse;
-
uint16_t queryId = 0;
std::vector<int> sockets;
sockets.reserve(dss->sockets.size());
for(;;) {
- dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet);
try {
pickBackendSocketsReadyForReceiving(dss, sockets);
if (dss->isStopped()) {
}
for (const auto& fd : sockets) {
- ssize_t got = recv(fd, packet, sizeof(packet), 0);
- char * response = packet;
- size_t responseSize = sizeof(packet);
+ response.resize(s_initialUDPPacketBufferSize);
+ ssize_t got = recv(fd, response.data(), response.size(), 0);
if (got == 0 && dss->isStopped()) {
break;
continue;
}
- uint16_t responseLen = static_cast<uint16_t>(got);
+ response.resize(static_cast<size_t>(got));
+ dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
queryId = dh->id;
- if(queryId >= dss->idStates.size()) {
+ if (queryId >= dss->idStates.size()) {
continue;
}
IDState* ids = &dss->idStates[queryId];
int64_t usageIndicator = ids->usageIndicator;
- if(!IDState::isInUse(usageIndicator)) {
+ if (!IDState::isInUse(usageIndicator)) {
/* the corresponding state is marked as not in use, meaning that:
- it was already cleaned up by another thread and the state is gone ;
- we already got a response for this query and this one is a duplicate.
ids->age = 0;
int origFD = ids->origFD;
- unsigned int consumed = 0;
- if (!responseContentMatches(response, responseLen, ids->qname, ids->qtype, ids->qclass, dss->remote, consumed)) {
+ unsigned int qnameWireLength = 0;
+ if (!responseContentMatches(response, ids->qname, ids->qtype, ids->qclass, dss->remote, qnameWireLength)) {
continue;
}
continue;
}
- if(dh->tc && g_truncateTC) {
- truncateTC(response, &responseLen, responseSize, consumed);
+ if (dh->tc && g_truncateTC) {
+ truncateTC(response, qnameWireLength);
}
dh->id = ids->origID;
- uint16_t addRoom = 0;
- DNSResponse dr = makeDNSResponseFromIDState(*ids, dh, sizeof(packet), responseLen, false);
- if (dr.dnsCryptQuery) {
- addRoom = DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE;
- }
+ DNSResponse dr = makeDNSResponseFromIDState(*ids, response, false);
+ memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH));
- memcpy(&cleartextDH, dr.dh, sizeof(cleartextDH));
- if (!processResponse(&response, &responseLen, &responseSize, localRespRulactions, dr, addRoom, rewrittenResponse, ids->cs && ids->cs->muted)) {
+ if (!processResponse(response, localRespRulactions, dr, ids->cs && ids->cs->muted)) {
continue;
}
if (du) {
#ifdef HAVE_DNS_OVER_HTTPS
// DoH query
- du->response = std::string(response, responseLen);
+ du->response = std::move(response);
static_assert(sizeof(du) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to be interleaved and to either fully succeed or fail");
ssize_t sent = write(du->rsock, &du, sizeof(du));
if (sent != sizeof(du)) {
empty.sin4.sin_family = 0;
/* if ids->destHarvested is false, origDest holds the listening address.
We don't want to use that as a source since it could be 0.0.0.0 for example. */
- sendUDPResponse(origFD, response, responseLen, dr.delayMsec, ids->destHarvested ? ids->origDest : empty, ids->origRemote);
+ sendUDPResponse(origFD, response, dr.delayMsec, ids->destHarvested ? ids->origDest : empty, ids->origRemote);
}
}
dss->latencyUsec = (127.0 * dss->latencyUsec / 128.0) + udiff/128.0;
doLatencyStats(udiff);
-
- rewrittenResponse.clear();
}
}
- catch(const std::exception& e){
+ catch (const std::exception& e){
vinfolog("Got an error in UDP responder thread while parsing a response from %s, id %d: %s", dss->remote.toStringWithPort(), queryId, e.what());
}
}
}
-catch(const std::exception& e)
+catch (const std::exception& e)
{
errlog("UDP responder thread died because of exception: %s", e.what());
}
-catch(const PDNSException& e)
+catch (const PDNSException& e)
{
errlog("UDP responder thread died because of PowerDNS exception: %s", e.reason);
}
-catch(...)
+catch (...)
{
errlog("UDP responder thread died because of an exception: %s", "unknown");
}
+}
std::mutex g_luamutex;
LuaContext g_lua;
return true;
break;
case DNSAction::Action::Nxdomain:
- dq.dh->rcode = RCode::NXDomain;
- dq.dh->qr=true;
+ dq.getHeader()->rcode = RCode::NXDomain;
+ dq.getHeader()->qr=true;
++g_stats.ruleNXDomain;
return true;
break;
case DNSAction::Action::Refused:
- dq.dh->rcode = RCode::Refused;
- dq.dh->qr=true;
+ dq.getHeader()->rcode = RCode::Refused;
+ dq.getHeader()->qr=true;
++g_stats.ruleRefused;
return true;
break;
case DNSAction::Action::ServFail:
- dq.dh->rcode = RCode::ServFail;
- dq.dh->qr=true;
+ dq.getHeader()->rcode = RCode::ServFail;
+ dq.getHeader()->qr=true;
++g_stats.ruleServFail;
return true;
break;
return true;
break;
case DNSAction::Action::Truncate:
- dq.dh->tc = true;
- dq.dh->qr = true;
- dq.dh->ra = dq.dh->rd;
- dq.dh->aa = false;
- dq.dh->ad = false;
+ dq.getHeader()->tc = true;
+ dq.getHeader()->qr = true;
+ dq.getHeader()->ra = dq.getHeader()->rd;
+ dq.getHeader()->aa = false;
+ dq.getHeader()->ad = false;
return true;
break;
case DNSAction::Action::HeaderModify:
return true;
break;
case DNSAction::Action::NoRecurse:
- dq.dh->rd = false;
+ dq.getHeader()->rd = false;
return true;
break;
/* non-terminal actions follow */
static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dq, const struct timespec& now)
{
- g_rings.insertQuery(now, *dq.remote, *dq.qname, dq.qtype, dq.len, *dq.dh);
+ g_rings.insertQuery(now, *dq.remote, *dq.qname, dq.qtype, dq.getData().size(), *dq.getHeader());
if(g_qcount.enabled) {
string qname = (*dq.qname).toLogString();
vinfolog("Query from %s turned into NXDomain because of dynamic block", dq.remote->toStringWithPort());
updateBlockStats();
- dq.dh->rcode = RCode::NXDomain;
- dq.dh->qr=true;
+ dq.getHeader()->rcode = RCode::NXDomain;
+ dq.getHeader()->qr=true;
return true;
case DNSAction::Action::Refused:
vinfolog("Query from %s refused because of dynamic block", dq.remote->toStringWithPort());
updateBlockStats();
- dq.dh->rcode = RCode::Refused;
- dq.dh->qr = true;
+ dq.getHeader()->rcode = RCode::Refused;
+ dq.getHeader()->qr = true;
return true;
case DNSAction::Action::Truncate:
if(!dq.tcp) {
updateBlockStats();
vinfolog("Query from %s truncated because of dynamic block", dq.remote->toStringWithPort());
- dq.dh->tc = true;
- dq.dh->qr = true;
- dq.dh->ra = dq.dh->rd;
- dq.dh->aa = false;
- dq.dh->ad = false;
+ dq.getHeader()->tc = true;
+ dq.getHeader()->qr = true;
+ dq.getHeader()->ra = dq.getHeader()->rd;
+ dq.getHeader()->aa = false;
+ dq.getHeader()->ad = false;
return true;
}
else {
case DNSAction::Action::NoRecurse:
updateBlockStats();
vinfolog("Query from %s setting rd=0 because of dynamic block", dq.remote->toStringWithPort());
- dq.dh->rd = false;
+ dq.getHeader()->rd = false;
return true;
default:
updateBlockStats();
vinfolog("Query from %s for %s turned into NXDomain because of dynamic block", dq.remote->toStringWithPort(), dq.qname->toLogString());
updateBlockStats();
- dq.dh->rcode = RCode::NXDomain;
- dq.dh->qr=true;
+ dq.getHeader()->rcode = RCode::NXDomain;
+ dq.getHeader()->qr=true;
return true;
case DNSAction::Action::Refused:
vinfolog("Query from %s for %s refused because of dynamic block", dq.remote->toStringWithPort(), dq.qname->toLogString());
updateBlockStats();
- dq.dh->rcode = RCode::Refused;
- dq.dh->qr=true;
+ dq.getHeader()->rcode = RCode::Refused;
+ dq.getHeader()->qr=true;
return true;
case DNSAction::Action::Truncate:
if(!dq.tcp) {
updateBlockStats();
vinfolog("Query from %s for %s truncated because of dynamic block", dq.remote->toStringWithPort(), dq.qname->toLogString());
- dq.dh->tc = true;
- dq.dh->qr = true;
- dq.dh->ra = dq.dh->rd;
- dq.dh->aa = false;
- dq.dh->ad = false;
+ dq.getHeader()->tc = true;
+ dq.getHeader()->qr = true;
+ dq.getHeader()->ra = dq.getHeader()->rd;
+ dq.getHeader()->aa = false;
+ dq.getHeader()->ad = false;
return true;
}
else {
case DNSAction::Action::NoRecurse:
updateBlockStats();
vinfolog("Query from %s setting rd=0 because of dynamic block", dq.remote->toStringWithPort());
- dq.dh->rd = false;
+ dq.getHeader()->rd = false;
return true;
default:
updateBlockStats();
return true;
}
-ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const char* request, const size_t requestLen, bool healthCheck)
+ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const std::vector<uint8_t>& request, bool healthCheck)
{
ssize_t result;
if (ss->sourceItf == 0) {
- result = send(sd, request, requestLen, 0);
+ result = send(sd, request.data(), request.size(), 0);
}
else {
struct msghdr msgh;
struct iovec iov;
cmsgbuf_aligned cbuf;
ComboAddress remote(ss->remote);
- fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), const_cast<char*>(request), requestLen, &remote);
+ fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), const_cast<char*>(reinterpret_cast<const char *>(request.data())), request.size(), &remote);
addCMsgSrcAddr(&msgh, &cbuf, &ss->sourceAddr, ss->sourceItf);
result = sendmsg(sd, &msgh, 0);
}
return true;
}
-boost::optional<std::vector<uint8_t>> checkDNSCryptQuery(const ClientState& cs, const char* query, uint16_t& len, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
+bool checkDNSCryptQuery(const ClientState& cs, std::vector<uint8_t>& query, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp)
{
if (cs.dnscryptCtx) {
#ifdef HAVE_DNSCRYPT
vector<uint8_t> response;
- uint16_t decryptedQueryLen = 0;
-
dnsCryptQuery = std::make_shared<DNSCryptQuery>(cs.dnscryptCtx);
- bool decrypted = handleDNSCryptQuery(const_cast<char*>(query), len, dnsCryptQuery, &decryptedQueryLen, tcp, now, response);
+ bool decrypted = handleDNSCryptQuery(query, dnsCryptQuery, tcp, now, response);
if (!decrypted) {
if (response.size() > 0) {
- return response;
+ query = std::move(response);
+ return true;
}
throw std::runtime_error("Unable to decrypt DNSCrypt query, dropping.");
}
-
- len = decryptedQueryLen;
#endif /* HAVE_DNSCRYPT */
}
- return boost::none;
+ return false;
}
bool checkQueryHeaders(const struct dnsheader* dh)
}
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
-static void queueResponse(const ClientState& cs, const char* response, uint16_t responseLen, const ComboAddress& dest, const ComboAddress& remote, struct mmsghdr& outMsg, struct iovec* iov, cmsgbuf_aligned* cbuf)
+static void queueResponse(const ClientState& cs, const std::vector<uint8_t>& response, const ComboAddress& dest, const ComboAddress& remote, struct mmsghdr& outMsg, struct iovec* iov, cmsgbuf_aligned* cbuf)
{
outMsg.msg_len = 0;
- fillMSGHdr(&outMsg.msg_hdr, iov, nullptr, 0, const_cast<char*>(response), responseLen, const_cast<ComboAddress*>(&remote));
+ fillMSGHdr(&outMsg.msg_hdr, iov, nullptr, 0, const_cast<char*>(reinterpret_cast<const char *>(&response.at(0))), response.size(), const_cast<ComboAddress*>(&remote));
if (dest.sin4.sin_family == 0) {
outMsg.msg_hdr.msg_control = nullptr;
/* self-generated responses or cache hits */
static bool prepareOutgoingResponse(LocalHolders& holders, ClientState& cs, DNSQuestion& dq, bool cacheHit)
{
- DNSResponse dr(dq.qname, dq.qtype, dq.qclass, dq.consumed, dq.local, dq.remote, reinterpret_cast<dnsheader*>(dq.dh), dq.size, dq.len, dq.tcp, dq.queryTime);
+ DNSResponse dr(dq.qname, dq.qtype, dq.qclass, dq.local, dq.remote, dq.getMutableData(), dq.tcp, dq.queryTime);
dr.uniqueId = dq.uniqueId;
dr.qTag = dq.qTag;
#ifdef HAVE_DNSCRYPT
if (!cs.muted) {
- if (!encryptResponse(reinterpret_cast<char*>(dq.dh), &dq.len, dq.size, dq.tcp, dq.dnsCryptQuery, nullptr, nullptr)) {
+ if (!encryptResponse(dq.getMutableData(), dq.tcp, dq.dnsCryptQuery)) {
return false;
}
}
++g_stats.cacheHits;
}
- switch (dr.dh->rcode) {
+ switch (dr.getHeader()->rcode) {
case RCode::NXDomain:
++g_stats.frontendNXDomain;
break;
ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend)
{
- const uint16_t queryId = ntohs(dq.dh->id);
+ const uint16_t queryId = ntohs(dq.getHeader()->id);
try {
/* we need an accurate ("real") value for the response and
return ProcessQueryResult::Drop;
}
- if(dq.dh->qr) { // something turned it into a response
+ if (dq.getHeader()->qr) { // something turned it into a response
fixUpQueryTurnedResponse(dq, dq.origFlags);
if (!prepareOutgoingResponse(holders, cs, dq, false)) {
const auto servers = serverPool->getServers();
selectedBackend = policy.getSelectedBackend(*servers, dq);
- uint16_t cachedResponseSize = dq.size;
uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL;
if (dq.packetCache && !dq.skipCache) {
// we need ECS parsing (parseECS) to be true so we can be sure that the initial incoming query did not have an existing
// ECS option, which would make it unsuitable for the zero-scope feature.
if (dq.packetCache && !dq.skipCache && (!selectedBackend || !selectedBackend->disableZeroScope) && dq.packetCache->isECSParsingEnabled()) {
- if (dq.packetCache->get(dq, dq.consumed, dq.dh->id, reinterpret_cast<char*>(dq.dh), &cachedResponseSize, &dq.cacheKeyNoECS, dq.subnet, dq.dnssecOK, allowExpired)) {
- dq.len = cachedResponseSize;
+ if (dq.packetCache->get(dq, dq.getHeader()->id, &dq.cacheKeyNoECS, dq.subnet, dq.dnssecOK, allowExpired)) {
if (!prepareOutgoingResponse(holders, cs, dq, true)) {
return ProcessQueryResult::Drop;
}
}
- if (!handleEDNSClientSubnet(dq, dq.ednsAdded, dq.ecsAdded, g_preserveTrailingData)) {
+ if (!handleEDNSClientSubnet(dq, dq.ednsAdded, dq.ecsAdded)) {
vinfolog("Dropping query from %s because we couldn't insert the ECS value", dq.remote->toStringWithPort());
return ProcessQueryResult::Drop;
}
}
if (dq.packetCache && !dq.skipCache) {
- if (dq.packetCache->get(dq, dq.consumed, dq.dh->id, reinterpret_cast<char*>(dq.dh), &cachedResponseSize, &dq.cacheKey, dq.subnet, dq.dnssecOK, allowExpired)) {
- dq.len = cachedResponseSize;
+ if (dq.packetCache->get(dq, dq.getHeader()->id, &dq.cacheKey, dq.subnet, dq.dnssecOK, allowExpired)) {
if (!prepareOutgoingResponse(holders, cs, dq, true)) {
return ProcessQueryResult::Drop;
++g_stats.cacheMisses;
}
- if(!selectedBackend) {
+ if (!selectedBackend) {
++g_stats.noPolicy;
vinfolog("%s query for %s|%s from %s, no policy applied", g_servFailOnNoPolicy ? "ServFailed" : "Dropped", dq.qname->toLogString(), QType(dq.qtype).getName(), dq.remote->toStringWithPort());
if (g_servFailOnNoPolicy) {
- restoreFlags(dq.dh, dq.origFlags);
+ restoreFlags(dq.getHeader(), dq.origFlags);
- dq.dh->rcode = RCode::ServFail;
- dq.dh->qr = true;
+ dq.getHeader()->rcode = RCode::ServFail;
+ dq.getHeader()->qr = true;
if (!prepareOutgoingResponse(holders, cs, dq, false)) {
return ProcessQueryResult::Drop;
}
if (dq.addXPF && selectedBackend->xpfRRCode != 0) {
- addXPF(dq, selectedBackend->xpfRRCode, g_preserveTrailingData);
+ addXPF(dq, selectedBackend->xpfRRCode);
}
selectedBackend->queries++;
return ProcessQueryResult::PassToBackend;
}
- catch(const std::exception& e){
+ catch (const std::exception& e){
vinfolog("Got an error while parsing a %s query from %s, id %d: %s", (dq.tcp ? "TCP" : "UDP"), dq.remote->toStringWithPort(), queryId, e.what());
}
return ProcessQueryResult::Drop;
}
-static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, char* query, uint16_t len, size_t queryBufferSize, struct mmsghdr* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
+static void processUDPQuery(ClientState& cs, LocalHolders& holders, const struct msghdr* msgh, const ComboAddress& remote, ComboAddress& dest, std::vector<uint8_t>& query, struct mmsghdr* responsesVect, unsigned int* queuedResponses, struct iovec* respIOV, cmsgbuf_aligned* respCBuf)
{
assert(responsesVect == nullptr || (queuedResponses != nullptr && respIOV != nullptr && respCBuf != nullptr));
uint16_t queryId = 0;
gettime(&queryRealTime, true);
std::shared_ptr<DNSCryptQuery> dnsCryptQuery = nullptr;
- auto dnsCryptResponse = checkDNSCryptQuery(cs, query, len, dnsCryptQuery, queryRealTime.tv_sec, false);
+ auto dnsCryptResponse = checkDNSCryptQuery(cs, query, dnsCryptQuery, queryRealTime.tv_sec, false);
if (dnsCryptResponse) {
- sendUDPResponse(cs.udpFD, reinterpret_cast<char*>(dnsCryptResponse->data()), static_cast<uint16_t>(dnsCryptResponse->size()), 0, dest, remote);
+ sendUDPResponse(cs.udpFD, query, 0, dest, remote);
return;
}
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(query);
+ struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(query.data());
queryId = ntohs(dh->id);
if (!checkQueryHeaders(dh)) {
}
uint16_t qtype, qclass;
- unsigned int consumed = 0;
- DNSName qname(query, len, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, dest.sin4.sin_family != 0 ? &dest : &cs.local, &remote, dh, queryBufferSize, len, false, &queryRealTime);
+ unsigned int qnameWireLength = 0;
+ DNSName qname(reinterpret_cast<const char*>(query.data()), query.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength);
+ DNSQuestion dq(&qname, qtype, qclass, dest.sin4.sin_family != 0 ? &dest : &cs.local, &remote, query, false, &queryRealTime);
dq.dnsCryptQuery = std::move(dnsCryptQuery);
std::shared_ptr<DownstreamState> ss{nullptr};
auto result = processQuery(dq, cs, holders, ss);
return;
}
+ // the buffer might have been invalidated by now (resized)
+ dh = dq.getHeader();
if (result == ProcessQueryResult::SendAnswer) {
#if defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE)
if (dq.delayMsec == 0 && responsesVect != nullptr) {
- queueResponse(cs, reinterpret_cast<char*>(dq.dh), dq.len, *dq.local, *dq.remote, responsesVect[*queuedResponses], respIOV, respCBuf);
+ queueResponse(cs, query, *dq.local, *dq.remote, responsesVect[*queuedResponses], respIOV, respCBuf);
(*queuedResponses)++;
return;
}
#endif /* defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE) */
/* we use dest, always, because we don't want to use the listening address to send a response since it could be 0.0.0.0 */
- sendUDPResponse(cs.udpFD, reinterpret_cast<char*>(dq.dh), dq.len, dq.delayMsec, dest, *dq.remote);
+ sendUDPResponse(cs.udpFD, query, dq.delayMsec, dest, *dq.remote);
return;
}
ids->destHarvested = false;
}
+ dh = dq.getHeader();
dh->id = idOffset;
if (ss->useProxyProtocol) {
}
int fd = pickBackendSocketForSending(ss);
- ssize_t ret = udpClientSendRequestToBackend(ss, fd, query, dq.len);
+ ssize_t ret = udpClientSendRequestToBackend(ss, fd, query);
if(ret < 0) {
++ss->sendErrors;
{
struct MMReceiver
{
- char packet[s_maxPacketCacheEntrySize];
+ std::vector<uint8_t> packet;
ComboAddress remote;
ComboAddress dest;
struct iovec iov;
- we use it for self-generated responses (from rule or cache)
but we only accept incoming payloads up to that size
*/
- static_assert(s_udpIncomingBufferSize <= sizeof(MMReceiver::packet), "the incoming buffer size should not be larger than sizeof(MMReceiver::packet)");
+ static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "the incoming buffer size should not be larger than s_initialUDPPacketBufferSize");
auto recvData = std::unique_ptr<MMReceiver[]>(new MMReceiver[vectSize]);
auto msgVec = std::unique_ptr<struct mmsghdr[]>(new struct mmsghdr[vectSize]);
/* initialize the structures needed to receive our messages */
for (size_t idx = 0; idx < vectSize; idx++) {
recvData[idx].remote.sin4.sin_family = cs->local.sin4.sin_family;
- fillMSGHdr(&msgVec[idx].msg_hdr, &recvData[idx].iov, &recvData[idx].cbuf, sizeof(recvData[idx].cbuf), recvData[idx].packet, cs->dnscryptCtx ? sizeof(recvData[idx].packet) : s_udpIncomingBufferSize, &recvData[idx].remote);
+ recvData[idx].packet.resize(s_initialUDPPacketBufferSize);
+ fillMSGHdr(&msgVec[idx].msg_hdr, &recvData[idx].iov, &recvData[idx].cbuf, sizeof(recvData[idx].cbuf), reinterpret_cast<char*>(&recvData[idx].packet.at(0)), cs->dnscryptCtx ? recvData[idx].packet.size() : s_udpIncomingBufferSize, &recvData[idx].remote);
}
/* go now */
/* reset the IO vector, since it's also used to send the vector of responses
to avoid having to copy the data around */
for (size_t idx = 0; idx < vectSize; idx++) {
- recvData[idx].iov.iov_base = recvData[idx].packet;
- recvData[idx].iov.iov_len = sizeof(recvData[idx].packet);
+ recvData[idx].packet.resize(s_initialUDPPacketBufferSize);
+ recvData[idx].iov.iov_base = &recvData[idx].packet.at(0);
+ recvData[idx].iov.iov_len = recvData[idx].packet.size();
}
/* block until we have at least one message ready, but return
continue;
}
- processUDPQuery(*cs, holders, msgh, remote, recvData[msgIdx].dest, recvData[msgIdx].packet, static_cast<uint16_t>(got), sizeof(recvData[msgIdx].packet), outMsgVec.get(), &msgsToSend, &recvData[msgIdx].iov, &recvData[msgIdx].cbuf);
-
+ recvData[msgIdx].packet.resize(got);
+ processUDPQuery(*cs, holders, msgh, remote, recvData[msgIdx].dest, recvData[msgIdx].packet, outMsgVec.get(), &msgsToSend, &recvData[msgIdx].iov, &recvData[msgIdx].cbuf);
}
/* immediate (not delayed or sent to a backend) responses (mostly from a rule, dynamic block
else
#endif /* defined(HAVE_RECVMMSG) && defined(HAVE_SENDMMSG) && defined(MSG_WAITFORONE) */
{
- char packet[s_maxPacketCacheEntrySize];
+ std::vector<uint8_t> packet(s_initialUDPPacketBufferSize);
/* the actual buffer is larger because:
- we may have to add EDNS and/or ECS
- we use it for self-generated responses (from rule or cache)
but we only accept incoming payloads up to that size
*/
- static_assert(s_udpIncomingBufferSize <= sizeof(packet), "the incoming buffer size should not be larger than sizeof(MMReceiver::packet)");
+ static_assert(s_udpIncomingBufferSize <= s_initialUDPPacketBufferSize, "the incoming buffer size should not be larger than sizeof(MMReceiver::packet)");
struct msghdr msgh;
struct iovec iov;
/* used by HarvestDestinationAddress */
ComboAddress remote;
ComboAddress dest;
remote.sin4.sin_family = cs->local.sin4.sin_family;
- fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), packet, cs->dnscryptCtx ? sizeof(packet) : s_udpIncomingBufferSize, &remote);
+ fillMSGHdr(&msgh, &iov, &cbuf, sizeof(cbuf), reinterpret_cast<char*>(&packet.at(0)), cs->dnscryptCtx ? packet.size() : s_udpIncomingBufferSize, &remote);
for(;;) {
+ packet.resize(s_initialUDPPacketBufferSize);
+ iov.iov_base = &packet.at(0);
+ iov.iov_len = packet.size();
+
ssize_t got = recvmsg(cs->udpFD, &msgh, 0);
if (got < 0 || static_cast<size_t>(got) < sizeof(struct dnsheader)) {
continue;
}
- processUDPQuery(*cs, holders, &msgh, remote, dest, packet, static_cast<uint16_t>(got), sizeof(packet), nullptr, nullptr, nullptr, nullptr);
+ packet.resize(static_cast<size_t>(got));
+ processUDPQuery(*cs, holders, &msgh, remote, dest, packet, nullptr, nullptr, nullptr, nullptr);
}
}
}
struct DNSQuestion
{
- DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, unsigned int consumed_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t queryLen, bool isTcp, const struct timespec* queryTime_):
- qname(name), local(lc), remote(rem), dh(header), queryTime(queryTime_), size(bufferSize), consumed(consumed_), tempFailureTTL(boost::none), qtype(type), qclass(class_), len(queryLen), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) {
- const uint16_t* flags = getFlagsFromDNSHeader(dh);
+ DNSQuestion(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, std::vector<uint8_t>& data_, bool isTcp, const struct timespec* queryTime_):
+ data(data_), qname(name), local(lc), remote(rem), queryTime(queryTime_), tempFailureTTL(boost::none), qtype(type), qclass(class_), ecsPrefixLength(rem->sin4.sin_family == AF_INET ? g_ECSSourcePrefixV4 : g_ECSSourcePrefixV6), tcp(isTcp), ecsOverride(g_ECSOverride) {
+ const uint16_t* flags = getFlagsFromDNSHeader(getHeader());
origFlags = *flags;
}
DNSQuestion(const DNSQuestion&) = delete;
std::string getTrailingData() const;
bool setTrailingData(const std::string&);
+ const std::vector<uint8_t>& getData() const
+ {
+ return data;
+ }
+ std::vector<uint8_t>& getMutableData()
+ {
+ return data;
+ }
+
+ dnsheader* getHeader()
+ {
+ if (data.size() < sizeof(dnsheader)) {
+ throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
+ }
+ return reinterpret_cast<dnsheader*>(&data.at(0));
+ }
+
+ const dnsheader* getHeader() const
+ {
+ if (data.size() < sizeof(dnsheader)) {
+ throw std::runtime_error("Trying to access the dnsheader of a too small (" + std::to_string(data.size()) + ") DNSQuestion buffer");
+ }
+ return reinterpret_cast<const dnsheader*>(&data.at(0));
+ }
+ bool hasRoomFor(size_t more) const
+ {
+ return data.size() <= getMaximumSize() && (getMaximumSize() - data.size()) >= more;
+ }
+
+ size_t getMaximumSize() const
+ {
+ if (tcp) {
+ return std::numeric_limits<uint16_t>::max();
+ }
+ return 4096;
+ }
+
+protected:
+ std::vector<uint8_t>& data;
+
+public:
boost::optional<boost::uuids::uuid> uniqueId;
Netmask ecs;
boost::optional<Netmask> subnet;
mutable std::shared_ptr<std::map<uint16_t, EDNSOptionView> > ednsOptions;
std::shared_ptr<DNSCryptQuery> dnsCryptQuery{nullptr};
std::shared_ptr<DNSDistPacketCache> packetCache{nullptr};
- struct dnsheader* dh{nullptr};
const struct timespec* queryTime{nullptr};
struct DOHUnit* du{nullptr};
- size_t size;
- unsigned int consumed{0};
int delayMsec{0};
boost::optional<uint32_t> tempFailureTTL;
uint32_t cacheKeyNoECS;
uint32_t cacheKey;
const uint16_t qtype;
const uint16_t qclass;
- uint16_t len;
uint16_t ecsPrefixLength;
uint16_t origFlags;
uint8_t ednsRCode{0};
struct DNSResponse : DNSQuestion
{
- DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, unsigned int consumed_, const ComboAddress* lc, const ComboAddress* rem, struct dnsheader* header, size_t bufferSize, uint16_t responseLen, bool isTcp, const struct timespec* queryTime_):
- DNSQuestion(name, type, class_, consumed_, lc, rem, header, bufferSize, responseLen, isTcp, queryTime_) { }
+ DNSResponse(const DNSName* name, uint16_t type, uint16_t class_, const ComboAddress* lc, const ComboAddress* rem, std::vector<uint8_t>& data_, bool isTcp, const struct timespec* queryTime_):
+ DNSQuestion(name, type, class_, lc, rem, data_, isTcp, queryTime_) { }
DNSResponse(const DNSResponse&) = delete;
DNSResponse& operator=(const DNSResponse&) = delete;
DNSResponse(DNSResponse&&) = default;
extern bool g_useTCPSinglePipe;
extern uint16_t g_downstreamTCPCleanupInterval;
extern size_t g_udpVectorSize;
-extern bool g_preserveTrailingData;
extern bool g_allowEmptyResponse;
extern shared_ptr<BPFFilter> g_defaultBPFFilter;
bool getLuaNoSideEffect(); // set if there were only explicit declarations of _no_ side effect
void resetLuaSideEffect(); // reset to indeterminate state
-bool responseContentMatches(const char* response, const uint16_t responseLen, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& consumed);
-bool processResponse(char** response, uint16_t* responseLen, size_t* responseSize, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, size_t addRoom, std::vector<uint8_t>& rewrittenResponse, bool muted);
+bool responseContentMatches(const std::vector<uint8_t>& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& remote, unsigned int& qnameWireLength);
+bool processResponse(std::vector<uint8_t>& response, LocalStateHolder<vector<DNSDistResponseRuleAction> >& localRespRulactions, DNSResponse& dr, bool muted);
bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop);
bool checkQueryHeaders(const struct dnsheader* dh);
extern std::vector<std::shared_ptr<DNSCryptContext>> g_dnsCryptLocals;
-int handleDNSCryptQuery(char* packet, uint16_t len, std::shared_ptr<DNSCryptQuery> query, uint16_t* decryptedQueryLen, bool tcp, time_t now, std::vector<uint8_t>& response);
-boost::optional<std::vector<uint8_t>> checkDNSCryptQuery(const ClientState& cs, const char* query, uint16_t& len, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
-
-bool addXPF(DNSQuestion& dq, uint16_t optionCode);
+int handleDNSCryptQuery(std::vector<uint8_t>& packet, std::shared_ptr<DNSCryptQuery>& query, bool tcp, time_t now, std::vector<uint8_t>& response);
+bool checkDNSCryptQuery(const ClientState& cs, std::vector<uint8_t>& query, std::shared_ptr<DNSCryptQuery>& dnsCryptQuery, time_t now, bool tcp);
uint16_t getRandomDNSID();
enum class ProcessQueryResult { Drop, SendAnswer, PassToBackend };
ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr<DownstreamState>& selectedBackend);
-DNSResponse makeDNSResponseFromIDState(IDState& ids, struct dnsheader* dh, size_t bufferSize, uint16_t responseLen, bool isTCP);
+DNSResponse makeDNSResponseFromIDState(IDState& ids, std::vector<uint8_t>& data, bool isTCP);
void setIDStateFromDNSQuestion(IDState& ids, DNSQuestion& dq, DNSName&& qname);
int pickBackendSocketForSending(std::shared_ptr<DownstreamState>& state);
-ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const char* request, const size_t requestLen, bool healthCheck=false);
+ssize_t udpClientSendRequestToBackend(const std::shared_ptr<DownstreamState>& ss, const int sd, const std::vector<uint8_t>& request, bool healthCheck = false);
sock.bind(ds->sourceAddr);
}
sock.connect(ds->remote);
- ssize_t sent = udpClientSendRequestToBackend(ds, sock.getHandle(), reinterpret_cast<char*>(&packet[0]), packet.size(), true);
+ ssize_t sent = udpClientSendRequestToBackend(ds, sock.getHandle(), packet, true);
if (sent < 0) {
int ret = errno;
if (g_verboseHealthChecks)
#include "dnsdist.hh"
-DNSResponse makeDNSResponseFromIDState(IDState& ids, struct dnsheader* dh, size_t bufferSize, uint16_t responseLen, bool isTCP)
+DNSResponse makeDNSResponseFromIDState(IDState& ids, std::vector<uint8_t>& data, bool isTCP)
{
- DNSResponse dr(&ids.qname, ids.qtype, ids.qclass, ids.qname.wirelength(), &ids.origDest, &ids.origRemote, dh, bufferSize, responseLen, isTCP, &ids.sentTime.d_start);
+ DNSResponse dr(&ids.qname, ids.qtype, ids.qclass, &ids.origDest, &ids.origRemote, data, isTCP, &ids.sentTime.d_start);
dr.origFlags = ids.origFlags;
dr.ecsAdded = ids.ecsAdded;
dr.ednsAdded = ids.ednsAdded;
void dnsdist_ffi_dnsquestion_unset_temp_failure_ttl(dnsdist_ffi_dnsquestion_t* dq) __attribute__ ((visibility ("default")));
void dnsdist_ffi_dnsquestion_set_tag(dnsdist_ffi_dnsquestion_t* dq, const char* label, const char* value) __attribute__ ((visibility ("default")));
-void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, const char* contentType) __attribute__ ((visibility ("default")));
+void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, size_t bodyLen, const char* contentType) __attribute__ ((visibility ("default")));
size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char** out) __attribute__ ((visibility ("default")));
int dnsdist_ffi_dnsquestion_get_rcode(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->dh->rcode;
+ return dq->dq->getHeader()->rcode;
}
void* dnsdist_ffi_dnsquestion_get_header(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->dh;
+ return dq->dq->getHeader();
}
uint16_t dnsdist_ffi_dnsquestion_get_len(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->len;
+ return dq->dq->getData().size();
}
+#warning FIXME : we need to provide a way to resize
size_t dnsdist_ffi_dnsquestion_get_size(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->size;
+ return dq->dq->getData().size();
}
uint8_t dnsdist_ffi_dnsquestion_get_opcode(const dnsdist_ffi_dnsquestion_t* dq)
{
- return dq->dq->dh->opcode;
+ return dq->dq->getHeader()->opcode;
}
bool dnsdist_ffi_dnsquestion_get_tcp(const dnsdist_ffi_dnsquestion_t* dq)
dq->result = std::string(str, strSize);
}
-void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, const char* contentType)
+void dnsdist_ffi_dnsquestion_set_http_response(dnsdist_ffi_dnsquestion_t* dq, uint16_t statusCode, const char* body, size_t bodyLen, const char* contentType)
{
if (dq->dq->du == nullptr) {
return;
}
#ifdef HAVE_DNS_OVER_HTTPS
- dq->dq->du->setHTTPResponse(statusCode, body, contentType);
- dq->dq->dh->qr = true;
+ std::vector<uint8_t> bodyVect(body, body + bodyLen);
+ dq->dq->du->setHTTPResponse(statusCode, std::move(bodyVect), contentType);
+ dq->dq->getHeader()->qr = true;
#endif
}
void dnsdist_ffi_dnsquestion_set_rcode(dnsdist_ffi_dnsquestion_t* dq, int rcode)
{
- dq->dq->dh->rcode = rcode;
- dq->dq->dh->qr = true;
+ dq->dq->getHeader()->rcode = rcode;
+ dq->dq->getHeader()->qr = true;
}
void dnsdist_ffi_dnsquestion_set_len(dnsdist_ffi_dnsquestion_t* dq, uint16_t len)
{
- dq->dq->len = len;
+ dq->dq->getMutableData().resize(len);
}
void dnsdist_ffi_dnsquestion_set_skip_cache(dnsdist_ffi_dnsquestion_t* dq, bool skipCache)
bool addProxyProtocol(DNSQuestion& dq, const std::string& payload)
{
- if ((dq.size - dq.len) < payload.size()) {
+ if (!dq.hasRoomFor(payload.size())) {
return false;
}
- memmove(reinterpret_cast<char*>(dq.dh) + payload.size(), dq.dh, dq.len);
- memcpy(dq.dh, payload.c_str(), payload.size());
- dq.len += payload.size();
-
- return true;
+ return addProxyProtocol(dq.getMutableData(), payload);
}
bool addProxyProtocol(DNSQuestion& dq)
return false;
}
- buffer.resize(previousSize + payload.size());
- std::copy_backward(buffer.begin(), buffer.begin() + previousSize, buffer.end());
- std::copy(payload.begin(), payload.end(), buffer.begin());
+ buffer.insert(buffer.begin(), payload.begin(), payload.end());
return true;
}
}
bool matches(const DNSQuestion* dq) const override
{
- return dq->dh->cd || (getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
+ return dq->getHeader()->cd || (getEDNSZ(*dq) & EDNS_HEADER_FLAG_DO); // turns out dig sets ad by default..
}
string toString() const override
}
bool matches(const DNSQuestion* dq) const override
{
- return d_opcode == dq->dh->opcode;
+ return d_opcode == dq->getHeader()->opcode;
}
string toString() const override
{
uint16_t count = 0;
switch(d_section) {
case 0:
- count = ntohs(dq->dh->qdcount);
+ count = ntohs(dq->getHeader()->qdcount);
break;
case 1:
- count = ntohs(dq->dh->ancount);
+ count = ntohs(dq->getHeader()->ancount);
break;
case 2:
- count = ntohs(dq->dh->nscount);
+ count = ntohs(dq->getHeader()->nscount);
break;
case 3:
- count = ntohs(dq->dh->arcount);
+ count = ntohs(dq->getHeader()->arcount);
break;
}
return count >= d_minCount && count <= d_maxCount;
uint16_t count = 0;
switch(d_section) {
case 0:
- count = ntohs(dq->dh->qdcount);
+ count = ntohs(dq->getHeader()->qdcount);
break;
case 1:
- count = ntohs(dq->dh->ancount);
+ count = ntohs(dq->getHeader()->ancount);
break;
case 2:
- count = ntohs(dq->dh->nscount);
+ count = ntohs(dq->getHeader()->nscount);
break;
case 3:
- count = ntohs(dq->dh->arcount);
+ count = ntohs(dq->getHeader()->arcount);
break;
}
if (count < d_minCount) {
return false;
}
- count = getRecordsOfTypeCount(reinterpret_cast<const char*>(dq->dh), dq->len, d_section, d_type);
+ count = getRecordsOfTypeCount(reinterpret_cast<const char*>(dq->getData().data()), dq->getData().size(), d_section, d_type);
return count >= d_minCount && count <= d_maxCount;
}
string toString() const override
}
bool matches(const DNSQuestion* dq) const override
{
- uint16_t length = getDNSPacketLength(reinterpret_cast<const char*>(dq->dh), dq->len);
- return length < dq->len;
+ uint16_t length = getDNSPacketLength(reinterpret_cast<const char*>(dq->getData().data()), dq->getData().size());
+ return length < dq->getData().size();
}
string toString() const override
{
}
bool matches(const DNSQuestion* dq) const override
{
- return d_rcode == dq->dh->rcode;
+ return d_rcode == dq->getHeader()->rcode;
}
string toString() const override
{
bool matches(const DNSQuestion* dq) const override
{
// avoid parsing EDNS OPT RR when not needed.
- if (d_rcode != dq->dh->rcode) {
+ if (d_rcode != dq->getHeader()->rcode) {
return false;
}
uint16_t optStart;
size_t optLen = 0;
bool last = false;
- const char * packet = reinterpret_cast<const char*>(dq->dh);
- std::string packetStr(packet, dq->len);
+ std::string packetStr(dq->getData().begin(), dq->getData().end());
int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last);
if (res != 0) {
// no EDNS OPT RR
return false;
}
- if (optStart < dq->len && packetStr.at(optStart) != 0) {
+ if (optStart < dq->getData().size() && packetStr.at(optStart) != 0) {
// OPT RR Name != '.'
return false;
}
}
bool matches(const DNSQuestion* dq) const override
{
- return dq->dh->rd == 1;
+ return dq->getHeader()->rd == 1;
}
string toString() const override
{
}
/* Always called from the main DoH thread */
-static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCode, const std::string& response, const std::vector<std::pair<std::string, std::string>>& customResponseHeaders, const std::string& contentType, bool addContentType)
+static void handleResponse(DOHFrontend& df, st_h2o_req_t* req, uint16_t statusCode, const std::vector<uint8_t>& response, const std::vector<std::pair<std::string, std::string>>& customResponseHeaders, const std::string& contentType, bool addContentType)
{
constexpr int overwrite_if_exists = 1;
constexpr int maybe_token = 1;
}
if (df.d_sendCacheControlHeaders && !response.empty()) {
- uint32_t minTTL = getDNSPacketMinTTL(response.data(), response.size());
+ uint32_t minTTL = getDNSPacketMinTTL(reinterpret_cast<const char*>(response.data()), response.size());
if (minTTL != std::numeric_limits<uint32_t>::max()) {
std::string cacheControlValue = "max-age=" + std::to_string(minTTL);
/* we need to duplicate the header content because h2o keeps a pointer and we will be deleted before the response has been sent */
}
req->res.content_length = response.size();
- h2o_send_inline(req, response.c_str(), response.size());
+ h2o_send_inline(req, reinterpret_cast<const char*>(response.data()), response.size());
}
else if (statusCode >= 300 && statusCode < 400) {
/* in that case the response is actually a URL */
/* we need to duplicate the URL because h2o uses it for the location header, keeping a pointer, and we will be deleted before the response has been sent */
- h2o_iovec_t url = h2o_strdup(&req->pool, response.c_str(), response.size());
+ h2o_iovec_t url = h2o_strdup(&req->pool, reinterpret_cast<const char*>(response.data()), response.size());
h2o_send_redirect(req, statusCode, getReasonFromStatusCode(statusCode).c_str(), url.base, url.len);
++df.d_redirectresponses;
}
else {
- if (!response.empty()) {
- h2o_send_error_generic(req, statusCode, getReasonFromStatusCode(statusCode).c_str(), response.c_str(), H2O_SEND_ERROR_KEEP_HEADERS);
+ // we need to make sure it's null-terminated */
+ if (!response.empty() && response.at(response.size() - 1) == 0) {
+ h2o_send_error_generic(req, statusCode, getReasonFromStatusCode(statusCode).c_str(), reinterpret_cast<const char*>(response.data()), H2O_SEND_ERROR_KEEP_HEADERS);
}
else {
switch(statusCode) {
rings for example */
struct timespec queryRealTime;
gettime(&queryRealTime, true);
- uint16_t len = du->query.length();
- /* We reserve at least 512 additional bytes to be able to add EDNS, but we also want
- at least s_maxPacketCacheEntrySize bytes to be able to spoof the content or fill the answer from the packet cache */
- du->query.resize(std::max(du->query.size() + 512, s_maxPacketCacheEntrySize));
- size_t bufferSize = du->query.size();
- auto query = const_cast<char*>(du->query.c_str());
- struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(query);
- if (!checkQueryHeaders(dh)) {
- du->status_code = 400;
- return -1; // drop
+ {
+ /* don't keep that pointer around, it will be invalidated if the buffer is ever resized */
+ struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(du->query.data());
+
+ if (!checkQueryHeaders(dh)) {
+ du->status_code = 400;
+ return -1; // drop
+ }
+
+ queryId = ntohs(dh->id);
}
uint16_t qtype, qclass;
- unsigned int consumed = 0;
- DNSName qname(query, len, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, &du->dest, &du->remote, dh, bufferSize, len, false, &queryRealTime);
+ unsigned int qnameWireLength = 0;
+ DNSName qname(reinterpret_cast<const char*>(du->query.data()), du->query.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength);
+ DNSQuestion dq(&qname, qtype, qclass, &du->dest, &du->remote, du->query, false, &queryRealTime);
dq.ednsAdded = du->ednsAdded;
dq.du = du;
- queryId = ntohs(dh->id);
dq.sni = std::move(du->sni);
std::shared_ptr<DownstreamState> ss{nullptr};
if (result == ProcessQueryResult::SendAnswer) {
if (du->response.empty()) {
- du->response = std::string(reinterpret_cast<char*>(dq.dh), dq.len);
+ du->response = std::move(du->query);
}
/* increase the ref counter before sending the pointer */
du->get();
static_assert(sizeof(du) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to be interleaved and to either fully succeed or fail");
+
ssize_t sent = write(du->rsock, &du, sizeof(du));
if (sent != sizeof(du)) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
ids->du = du;
ids->cs = &cs;
- ids->origID = dh->id;
+ ids->origID = queryId;
setIDStateFromDNSQuestion(*ids, dq, std::move(qname));
+ dq.getHeader()->id = idOffset;
+
/* If we couldn't harvest the real dest addr, still
write down the listening addr since it will be useful
(especially if it's not an 'any' one).
ids->destHarvested = false;
}
- dh->id = idOffset;
-
if (ss->useProxyProtocol) {
addProxyProtocol(dq);
}
int fd = pickBackendSocketForSending(ss);
try {
/* you can't touch du after this line, because it might already have been freed */
- ssize_t ret = udpClientSendRequestToBackend(ss, fd, query, dq.len);
+ ssize_t ret = udpClientSendRequestToBackend(ss, fd, du->query);
if(ret < 0) {
/* we are about to handle the error, make sure that
/* This executes in the main DoH thread.
We allocate a DOHUnit and send it to dnsdistclient() function in the doh client thread
via a pipe */
-static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_req_t* req, std::string&& query, const ComboAddress& local, const ComboAddress& remote, std::string&& path)
+static void doh_dispatch_query(DOHServerConfig* dsc, h2o_handler_t* self, h2o_req_t* req, std::vector<uint8_t>&& query, const ComboAddress& local, const ComboAddress& remote, std::string&& path)
{
try {
/* we only parse it there as a sanity check, we will parse it again later */
uint16_t qtype;
- DNSName qname(query.c_str(), query.size(), sizeof(dnsheader), false, &qtype);
+ DNSName qname(reinterpret_cast<const char*>(query.data()), query.size(), sizeof(dnsheader), false, &qtype);
auto du = std::unique_ptr<DOHUnit>(new DOHUnit);
du->dsc = dsc;
++dsc->cs->tlsUnknownqueries;
}
+ #warning turn these into string_view?
string path(req->path.base, req->path.len);
-
string pathOnly(req->path_normalized.base, req->path_normalized.len);
+
if (dsc->paths.count(pathOnly) == 0) {
h2o_send_error_404(req, "Not Found", "there is no endpoint configured for this path", 0);
return 0;
else
++dsc->df->d_http1Stats.d_nbQueries;
- std::string query;
+ std::vector<uint8_t> query;
/* We reserve at least 512 additional bytes to be able to add EDNS, but we also want
at least s_maxPacketCacheEntrySize bytes to be able to fill the answer from the packet cache */
query.reserve(std::max(req->entity.len + 512, s_maxPacketCacheEntrySize));
- query.assign(req->entity.base, req->entity.len);
+ query.resize(req->entity.len);
+ memcpy(query.data(), req->entity.base, req->entity.len);
doh_dispatch_query(dsc, self, req, std::move(query), local, remote, std::move(path));
}
else if(req->query_at != SIZE_MAX && (req->path.len - req->query_at > 5)) {
break;
}
- string decoded;
+ std::string decoded;
+
/* rough estimate so we hopefully don't need a new allocation later */
/* We reserve at least 512 additional bytes to be able to add EDNS, but we also want
at least s_maxPacketCacheEntrySize bytes to be able to fill the answer from the packet cache */
else
++dsc->df->d_http1Stats.d_nbQueries;
- doh_dispatch_query(dsc, self, req, std::move(decoded), local, remote, std::move(path));
+#warning FIXME: performance
+ auto vect = std::vector<uint8_t>(decoded.begin(), decoded.end());
+ doh_dispatch_query(dsc, self, req, std::move(vect), local, remote, std::move(path));
}
}
else
}
}
-void DOHUnit::setHTTPResponse(uint16_t statusCode, const std::string& body_, const std::string& contentType_)
+void DOHUnit::setHTTPResponse(uint16_t statusCode, std::vector<uint8_t>&& body_, const std::string& contentType_)
{
status_code = statusCode;
- response = body_;
+ response = std::move(body_);
+ if (!response.empty() && statusCode >= 400) {
+ // we need to make sure it's null-terminated */
+ if (response.at(response.size() - 1) != 0) {
+ response.push_back(0);
+ }
+ }
+
contentType = contentType_;
}
// if there was no EDNS, we add it with a large buffer size
// so we can use UDP to talk to the backend.
- auto dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(du->query.c_str()));
+ auto dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(du->query.data()));
if (!dh->arcount) {
std::string res;
generateOptRR(std::string(), res, 4096, 0, false);
- du->query += res;
- dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(du->query.c_str())); // may have reallocated
+ du->query.insert(du->query.end(), res.begin(), res.end());
+ dh = const_cast<struct dnsheader*>(reinterpret_cast<const struct dnsheader*>(du->query.data())); // may have reallocated
dh->arcount = htons(1);
du->ednsAdded = true;
}
du->get();
static_assert(sizeof(du) <= PIPE_BUF, "Writes up to PIPE_BUF are guaranteed not to be interleaved and to either fully succeed or fail");
+
ssize_t sent = write(du->rsock, &du, sizeof(du));
if (sent != sizeof(du)) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
uint16_t qclass = QClass::IN;
ComboAddress lc("192.0.2.1:53");
ComboAddress rem("192.0.2.128:42");
- struct dnsheader dh;
- memset(&dh, 0, sizeof(dh));
- size_t bufferSize = 0;
- size_t queryLen = 0;
+ std::vector<uint8_t> packet(sizeof(dnsheader));
bool isTcp = false;
struct timespec queryRealTime;
gettime(&queryRealTime, true);
/* the internal QPS limiter does not use the real time */
gettime(&expiredTime);
- DNSQuestion dq(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, &dh, bufferSize, queryLen, isTcp, &queryRealTime);
+ DNSQuestion dq(&qname, qtype, qclass, &lc, &rem, packet, isTcp, &queryRealTime);
ComboAddress v4Masked(v4ToMask);
ComboAddress v6Masked(v6ToMask);
v4Masked.truncate(25);
uint16_t qclass = QClass::IN;
ComboAddress lc("192.0.2.1:53");
ComboAddress rem("192.0.2.128:42");
- struct dnsheader dh;
- memset(&dh, 0, sizeof(dh));
- size_t bufferSize = 0;
- size_t queryLen = 0;
+ std::vector<uint8_t> packet(sizeof(dnsheader));
bool isTcp = false;
struct timespec queryRealTime;
gettime(&queryRealTime, true);
/* the internal QPS limiter does not use the real time */
gettime(&expiredTime);
- DNSQuestion dq(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, &dh, bufferSize, queryLen, isTcp, &queryRealTime);
+ DNSQuestion dq(&qname, qtype, qclass, &lc, &rem, packet, isTcp, &queryRealTime);
ComboAddress v4Masked(v4ToMask);
ComboAddress v6Masked(v6ToMask);
v4Masked.truncate(25);
return "";
}
-void DOHUnit::setHTTPResponse(uint16_t statusCode, const std::string& body_, const std::string& contentType_)
+void DOHUnit::setHTTPResponse(uint16_t statusCode, std::vector<uint8_t>&& body_, const std::string& contentType_)
{
}
#endif /* HAVE_DNS_OVER_HTTPS */
static const ComboAddress lc("127.0.0.1:53");
static const ComboAddress rem("192.0.2.1:42");
static struct timespec queryRealTime;
- static struct dnsheader dh;
+ static std::vector<uint8_t> packet(sizeof(dnsheader));
- memset(&dh, 0, sizeof(dh));
uint16_t qtype = QType::A;
uint16_t qclass = QClass::IN;
- size_t bufferSize = 0;
- size_t queryLen = 0;
bool isTcp = false;
gettime(&queryRealTime, true);
- DNSQuestion dq(providedName ? providedName : &qname, qtype, qclass, qname.wirelength(), &lc, &rem, &dh, bufferSize, queryLen, isTcp, &queryRealTime);
+ DNSQuestion dq(providedName ? providedName : &qname, qtype, qclass, &lc, &rem, packet, isTcp, &queryRealTime);
return dq;
}
uint16_t qclass = QClass::IN;
ComboAddress lc("127.0.0.1:53");
ComboAddress rem("192.0.2.1:42");
- struct dnsheader dh;
- memset(&dh, 0, sizeof(dh));
- size_t bufferSize = 0;
- size_t queryLen = 0;
+ std::vector<uint8_t> packet(sizeof(dnsheader));
bool isTcp = false;
struct timespec queryRealTime;
gettime(&queryRealTime, true);
/* the internal QPS limiter does not use the real time */
gettime(&expiredTime);
- DNSQuestion dq(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, &dh, bufferSize, queryLen, isTcp, &queryRealTime);
+ DNSQuestion dq(&qname, qtype, qclass, &lc, &rem, packet, isTcp, &queryRealTime);
for (size_t idx = 0; idx < maxQPS; idx++) {
/* let's use different source ports, it shouldn't matter */
class DOHResponseMapEntry
{
public:
- DOHResponseMapEntry(const std::string& regex, uint16_t status, const std::string& content, const boost::optional<std::vector<std::pair<std::string, std::string>>>& headers): d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
+ DOHResponseMapEntry(const std::string& regex, uint16_t status, const std::vector<uint8_t>& content, const boost::optional<std::vector<std::pair<std::string, std::string>>>& headers): d_regex(regex), d_customHeaders(headers), d_content(content), d_status(status)
{
+ if (status >= 400 && !d_content.empty() && d_content.at(d_content.size() -1) != 0) {
+ // we need to make sure it's null-terminated
+ d_content.push_back(0);
+ }
}
bool matches(const std::string& path) const
return d_status;
}
- const std::string& getContent() const
+ const std::vector<uint8_t>& getContent() const
{
return d_content;
}
private:
Regex d_regex;
boost::optional<std::vector<std::pair<std::string, std::string>>> d_customHeaders;
- std::string d_content;
+ std::vector<uint8_t> d_content;
uint16_t d_status;
};
}
std::vector<std::pair<std::string, std::string>> headers;
- std::string query;
- std::string response;
+ std::vector<uint8_t> query;
+ std::vector<uint8_t> response;
std::string sni;
std::string path;
std::string scheme;
std::string getHTTPScheme() const;
std::string getHTTPQueryString() const;
std::unordered_map<std::string, std::string> getHTTPHeaders() const;
- void setHTTPResponse(uint16_t statusCode, const std::string& body, const std::string& contentType="");
+ void setHTTPResponse(uint16_t statusCode, std::vector<uint8_t>&& body, const std::string& contentType="");
};
#endif /* HAVE_DNS_OVER_HTTPS */
return true;
}
-/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
-int getEDNSOption(char* optRR, const size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize)
+/* extract the position (relative to the optRR pointer!) and size of a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
+int getEDNSOption(const char* optRR, const size_t len, uint16_t wantedOption, size_t* optionValuePosition, size_t * optionValueSize)
{
- assert(optRR != NULL);
- assert(optionValue != NULL);
- assert(optionValueSize != NULL);
+ assert(optRR != nullptr);
+ assert(optionValuePosition != nullptr);
+ assert(optionValueSize != nullptr);
size_t pos = 0;
if (len < DNS_RDLENGTH_SIZE)
return EINVAL;
}
if (optionCode == wantedOption) {
- *optionValue = optRR + pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE);
+ *optionValuePosition = pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE);
*optionValueSize = optionLen + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE;
return 0;
}
enum EDNSOptionCodeEnum {NSID=3, DAU=5, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13, KEYTAG=14, EXTENDEDERROR=15};
};
-/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
-int getEDNSOption(char* optRR, size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize);
+/* extract the position (relative to the optRR pointer!) and size of a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
+int getEDNSOption(const char* optRR, size_t len, uint16_t wantedOption, size_t* optionValuePosition, size_t* optionValueSize);
struct EDNSOptionViewValue
{
uint16_t qtype;
uint16_t qclass;
unsigned int consumed;
+ std::vector<uint8_t> vect(data, data+size);
const DNSName qname(reinterpret_cast<const char*>(data), size, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- pcSkipCookies.getKey(qname.getStorage(), consumed, data, size, false);
- pcHashCookies.getKey(qname.getStorage(), consumed, data, size, false);
+ pcSkipCookies.getKey(qname.getStorage(), consumed, vect, false);
+ pcHashCookies.getKey(qname.getStorage(), consumed, vect, false);
boost::optional<Netmask> subnet;
- DNSDistPacketCache::getClientSubnet(reinterpret_cast<const char*>(data), consumed, size, subnet);
+ DNSDistPacketCache::getClientSubnet(vect, consumed, subnet);
}
catch(const std::exception& e) {
}
return sendErr;
}
-ssize_t sendfromto(int sock, const char* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to)
+ssize_t sendfromto(int sock, const void* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to)
{
struct msghdr msgh;
struct iovec iov;
/* Set up iov and msgh structures. */
memset(&msgh, 0, sizeof(struct msghdr));
- iov.iov_base = (void*)data;
+ iov.iov_base = const_cast<void*>(data);
iov.iov_len = len;
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
int sendOnNBSocket(int fd, const struct msghdr *msgh);
-ssize_t sendfromto(int sock, const char* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to);
+ssize_t sendfromto(int sock, const void* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to);
size_t sendMsgWithOptions(int fd, const char* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
/* requires a non-blocking, connected TCP socket */
/* OPT root label (1) followed by type (2) */
if(lookForECS && ntohs(drh->d_type) == QType::OPT) {
if (!options) {
- char* ecsStart = nullptr;
+ size_t ecsStartPosition = 0;
size_t ecsLen = 0;
/* we need to pass the record len */
- int res = getEDNSOption(const_cast<char*>(reinterpret_cast<const char*>(&question.at(pos - sizeof(drh->d_clen)))), questionLen - pos + sizeof(drh->d_clen), EDNSOptionCode::ECS, &ecsStart, &ecsLen);
+ int res = getEDNSOption(reinterpret_cast<const char*>(&question.at(pos - sizeof(drh->d_clen))), questionLen - pos + sizeof(drh->d_clen), EDNSOptionCode::ECS, &ecsStartPosition, &ecsLen);
if (res == 0 && ecsLen > 4) {
EDNSSubnetOpts eso;
- if(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso)) {
+ if(getEDNSSubnetOptsFromString(&question.at(pos - sizeof(drh->d_clen) + ecsStartPosition + 4), ecsLen - 4, &eso)) {
*ednssubnet=eso;
foundECS = true;
}
BOOST_REQUIRE_EQUAL(query.at(pos), 0);
BOOST_REQUIRE(query.at(pos + 2) == QType::OPT);
- char* ecsStart = nullptr;
+ size_t ecsStartPosition = 0;
size_t ecsLen = 0;
- int res = getEDNSOption(reinterpret_cast<char*>(query.data()) + pos + 9, questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStart, &ecsLen);
+ int res = getEDNSOption(reinterpret_cast<const char*>(&query.at(pos + 9)), questionLen - pos - 9, EDNSOptionCode::ECS, &ecsStartPosition, &ecsLen);
BOOST_CHECK_EQUAL(res, 0);
EDNSSubnetOpts eso;
- BOOST_REQUIRE(getEDNSSubnetOptsFromString(ecsStart + 4, ecsLen - 4, &eso));
+ BOOST_REQUIRE(getEDNSSubnetOptsFromString(reinterpret_cast<const char*>(&query.at(pos + 9 + ecsStartPosition + 4)), ecsLen - 4, &eso));
BOOST_CHECK(eso.source == ecs);
}
vector<uint8_t> plainQuery;
DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0);
pw.getHeader()->rd = 0;
- uint16_t len = plainQuery.size();
std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
- uint16_t decryptedLen = 0;
-
- query->parsePacket((char*) plainQuery.data(), len, false, &decryptedLen, now);
+ query->parsePacket(plainQuery, false, now);
BOOST_CHECK_EQUAL(query->isValid(), true);
BOOST_CHECK_EQUAL(query->isEncrypted(), false);
vector<uint8_t> plainQuery;
DNSPacketWriter pw(plainQuery, name, QType::A, QClass::IN, 0);
pw.getHeader()->rd = 0;
- uint16_t len = plainQuery.size();
std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
- uint16_t decryptedLen = 0;
-
- query->parsePacket((char*) plainQuery.data(), len, false, &decryptedLen, now);
+ query->parsePacket(plainQuery, false, now);
BOOST_CHECK_EQUAL(query->isValid(), false);
}
vector<uint8_t> plainQuery;
DNSPacketWriter pw(plainQuery, name, QType::TXT, QClass::IN, 0);
pw.getHeader()->rd = 0;
- uint16_t len = plainQuery.size();
std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
- uint16_t decryptedLen = 0;
-
- query->parsePacket((char*) plainQuery.data(), len, false, &decryptedLen, now);
+ query->parsePacket(plainQuery, false, now);
BOOST_CHECK_EQUAL(query->isValid(), false);
}
requiredSize = DNSCryptQuery::s_minUDPLength;
}
- uint16_t len = plainQuery.size();
plainQuery.resize(requiredSize);
- uint16_t encryptedResponseLen = 0;
- int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
+ size_t initialSize = plainQuery.size();
+ int res = ctx->encryptQuery(plainQuery, 4096, clientPublicKey, clientPrivateKey, clientNonce, false, std::make_shared<DNSCryptCert>(resolverCert));
BOOST_CHECK_EQUAL(res, 0);
- BOOST_CHECK(encryptedResponseLen > len);
+ BOOST_CHECK(plainQuery.size() > initialSize);
std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
- uint16_t decryptedLen = 0;
- query->parsePacket((char*) plainQuery.data(), encryptedResponseLen, false, &decryptedLen, now);
+ query->parsePacket(plainQuery, false, now);
BOOST_CHECK_EQUAL(query->isValid(), true);
BOOST_CHECK_EQUAL(query->isEncrypted(), true);
- MOADNSParser mdp(true, (char*) plainQuery.data(), decryptedLen);
+ MOADNSParser mdp(true, (char*) plainQuery.data(), plainQuery.size());
BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
pw.getHeader()->rd = 1;
- uint16_t len = plainQuery.size();
- uint16_t encryptedResponseLen = 0;
-
- int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
-
+ int res = ctx->encryptQuery(plainQuery, /* not enough room */ plainQuery.size(), clientPublicKey, clientPrivateKey, clientNonce, false, std::make_shared<DNSCryptCert>(resolverCert));
BOOST_CHECK_EQUAL(res, ENOBUFS);
}
requiredSize = DNSCryptQuery::s_minUDPLength;
}
- uint16_t len = plainQuery.size();
- plainQuery.resize(requiredSize);
- uint16_t encryptedResponseLen = 0;
-
- int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
+ size_t initialSize = plainQuery.size();
+ int res = ctx->encryptQuery(plainQuery, 4096, clientPublicKey, clientPrivateKey, clientNonce, false, std::make_shared<DNSCryptCert>(resolverCert));
BOOST_CHECK_EQUAL(res, 0);
- BOOST_CHECK(encryptedResponseLen > len);
+ BOOST_CHECK(plainQuery.size() > initialSize);
DNSCryptCert newResolverCert;
DNSCryptContext::generateCertificate(2, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, newResolverCert);
ctx->markInactive(resolverCert.getSerial());
std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
- uint16_t decryptedLen = 0;
- query->parsePacket((char*) plainQuery.data(), encryptedResponseLen, false, &decryptedLen, now);
+ query->parsePacket(plainQuery, false, now);
BOOST_CHECK_EQUAL(query->isValid(), true);
BOOST_CHECK_EQUAL(query->isEncrypted(), true);
- MOADNSParser mdp(true, (char*) plainQuery.data(), decryptedLen);
+ MOADNSParser mdp(true, (char*) plainQuery.data(), plainQuery.size());
BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1U);
BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0U);
DNSPacketWriter pw(plainQuery, name, QType::AAAA, QClass::IN, 0);
pw.getHeader()->rd = 1;
- size_t requiredSize = plainQuery.size() + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE;
- if (requiredSize < DNSCryptQuery::s_minUDPLength) {
- requiredSize = DNSCryptQuery::s_minUDPLength;
- }
-
- uint16_t len = plainQuery.size();
- plainQuery.resize(requiredSize);
- uint16_t encryptedResponseLen = 0;
-
- int res = ctx->encryptQuery((char*) plainQuery.data(), len, plainQuery.capacity(), clientPublicKey, clientPrivateKey, clientNonce, false, &encryptedResponseLen, std::make_shared<DNSCryptCert>(resolverCert));
+ size_t initialSize = plainQuery.size();
+ int res = ctx->encryptQuery(plainQuery, 4096, clientPublicKey, clientPrivateKey, clientNonce, false, std::make_shared<DNSCryptCert>(resolverCert));
BOOST_CHECK_EQUAL(res, 0);
- BOOST_CHECK(encryptedResponseLen > len);
+ BOOST_CHECK(plainQuery.size() > initialSize);
DNSCryptCert newResolverCert;
DNSCryptContext::generateCertificate(2, now, now + (24 * 60 * 3600), DNSCryptExchangeVersion::VERSION1, providerPrivateKey, resolverPrivateKey, newResolverCert);
/* we have removed the old certificate, we can't decrypt this query */
std::shared_ptr<DNSCryptQuery> query = std::make_shared<DNSCryptQuery>(ctx);
- uint16_t decryptedLen = 0;
- query->parsePacket((char*) plainQuery.data(), encryptedResponseLen, false, &decryptedLen, now);
+ query->parsePacket(plainQuery, false, now);
BOOST_CHECK_EQUAL(query->isValid(), false);
}
static const uint16_t ECSSourcePrefixV4 = 24;
static const uint16_t ECSSourcePrefixV6 = 56;
-static void validateQuery(const char * packet, size_t packetSize, bool hasEdns=true, bool hasXPF=false, uint16_t additionals=0, uint16_t answers=0, uint16_t authorities=0)
+static void validateQuery(const std::vector<uint8_t>& packet, bool hasEdns=true, bool hasXPF=false, uint16_t additionals=0, uint16_t answers=0, uint16_t authorities=0)
{
- MOADNSParser mdp(true, packet, packetSize);
+ MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
BOOST_CHECK_EQUAL(mdp.d_header.arcount, expectedARCount);
}
-static void validateECS(const char* packet, size_t packetSize, const ComboAddress& expected)
+static void validateECS(const std::vector<uint8_t>& packet, const ComboAddress& expected)
{
ComboAddress rem("::1");
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, packetSize, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &rem, const_cast<dnsheader*>(reinterpret_cast<const dnsheader*>(packet)), packetSize, packetSize, false, nullptr);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &rem, const_cast<std::vector<uint8_t>&>(packet), false, nullptr);
BOOST_CHECK(parseEDNSOptions(dq));
BOOST_REQUIRE(dq.ednsOptions != nullptr);
BOOST_CHECK_EQUAL(dq.ednsOptions->size(), 1U);
BOOST_CHECK_EQUAL(expectedOption.substr(EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE), std::string(ecsOption->second.values.at(0).content, ecsOption->second.values.at(0).size));
}
-static void validateResponse(const char * packet, size_t packetSize, bool hasEdns, uint8_t additionalCount=0)
+static void validateResponse(const std::vector<uint8_t>& packet, bool hasEdns, uint8_t additionalCount=0)
{
- MOADNSParser mdp(false, packet, packetSize);
+ MOADNSParser mdp(false, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
vector<uint8_t> query;
DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
pw.getHeader()->rd = 1;
- const uint16_t len = query.size();
vector<uint8_t> queryWithXPF;
{
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ std::vector<uint8_t> packet = query;
/* large enough packet */
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
- BOOST_CHECK(addXPF(dq, xpfOptionCode, false));
- BOOST_CHECK(static_cast<size_t>(dq.len) > query.size());
- validateQuery(packet, dq.len, false, true);
- queryWithXPF.resize(dq.len);
- memcpy(queryWithXPF.data(), packet, dq.len);
+ BOOST_CHECK(addXPF(dq, xpfOptionCode));
+ BOOST_CHECK(packet.size() > query.size());
+ validateQuery(packet, false, true);
+ queryWithXPF = packet;
}
{
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ std::vector<uint8_t> packet = query;
- /* not large enough packet */
+ /* packet is already too large for the 4096 limit over UDP */
+ packet.resize(4096);
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
- dq.size = dq.len;
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
- BOOST_CHECK(!addXPF(dq, xpfOptionCode, false));
- BOOST_CHECK_EQUAL(static_cast<size_t>(dq.len), query.size());
- validateQuery(packet, dq.len, false, false);
+ BOOST_REQUIRE(!addXPF(dq, xpfOptionCode));
+ BOOST_CHECK_EQUAL(packet.size(), 4096);
+ packet.resize(query.size());
+ validateQuery(packet, false, false);
}
{
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ std::vector<uint8_t> packet = query;
/* packet with trailing data (overriding it) */
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
/* add trailing data */
const size_t trailingDataSize = 10;
/* Making sure we have enough room to allow for fake trailing data */
- BOOST_REQUIRE(sizeof(packet) > dq.len && (sizeof(packet) - dq.len) > trailingDataSize);
+ packet.resize(packet.size() + trailingDataSize);
for (size_t idx = 0; idx < trailingDataSize; idx++) {
- packet[dq.len + idx] = 'A';
+ packet.push_back('A');
}
- dq.len += trailingDataSize;
- BOOST_CHECK(addXPF(dq, xpfOptionCode, false));
- BOOST_CHECK_EQUAL(static_cast<size_t>(dq.len), queryWithXPF.size());
- BOOST_CHECK_EQUAL(memcmp(queryWithXPF.data(), packet, queryWithXPF.size()), 0);
- validateQuery(packet, dq.len, false, true);
- }
-
- {
- char packet[1500];
- memcpy(packet, query.data(), query.size());
-
- /* packet with trailing data (preserving trailing data) */
- unsigned int consumed = 0;
- uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
- BOOST_CHECK_EQUAL(qname, name);
- BOOST_CHECK(qtype == QType::A);
-
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
-
- /* add trailing data */
- const size_t trailingDataSize = 10;
- /* Making sure we have enough room to allow for fake trailing data */
- BOOST_REQUIRE(sizeof(packet) > dq.len && (sizeof(packet) - dq.len) > trailingDataSize);
- for (size_t idx = 0; idx < trailingDataSize; idx++) {
- packet[dq.len + idx] = 'A';
- }
- dq.len += trailingDataSize;
-
- BOOST_CHECK(addXPF(dq, xpfOptionCode, true));
- BOOST_CHECK(static_cast<size_t>(dq.len) > queryWithXPF.size());
- BOOST_CHECK_EQUAL(memcmp(queryWithXPF.data(), packet, queryWithXPF.size()), 0);
- for (size_t idx = 0; idx < trailingDataSize; idx++) {
- BOOST_CHECK_EQUAL(packet[queryWithXPF.size() + idx], 'A');
- }
- validateQuery(packet, dq.len, false, true);
+ BOOST_CHECK(addXPF(dq, xpfOptionCode));
+ BOOST_CHECK_EQUAL(packet.size(), queryWithXPF.size());
+ BOOST_CHECK_EQUAL(memcmp(queryWithXPF.data(), packet.data(), queryWithXPF.size()), 0);
+ validateQuery(packet, false, true);
}
}
uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ std::vector<uint8_t> packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSName qname(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
- BOOST_CHECK(static_cast<size_t>(len) > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, true);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, len);
- validateECS(packet, len, remote);
- vector<uint8_t> queryWithEDNS;
- queryWithEDNS.resize(len);
- memcpy(queryWithEDNS.data(), packet, len);
+ validateQuery(packet);
+ validateECS(packet, remote);
+ vector<uint8_t> queryWithEDNS = packet;
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
- BOOST_CHECK_EQUAL(static_cast<size_t>(len), query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, false, newECSOption));
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, false);
+ packet.resize(query.size());
+ validateQuery(packet, false);
/* packet with trailing data (overriding it) */
- memcpy(packet, query.data(), query.size());
+ packet = query;
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
/* add trailing data */
const size_t trailingDataSize = 10;
/* Making sure we have enough room to allow for fake trailing data */
- BOOST_REQUIRE(sizeof(packet) > len && (sizeof(packet) - len) > trailingDataSize);
+ packet.resize(packet.size() + trailingDataSize);
for (size_t idx = 0; idx < trailingDataSize; idx++) {
packet[len + idx] = 'A';
}
- len += trailingDataSize;
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
- BOOST_REQUIRE_EQUAL(static_cast<size_t>(len), queryWithEDNS.size());
- BOOST_CHECK_EQUAL(memcmp(queryWithEDNS.data(), packet, queryWithEDNS.size()), 0);
- BOOST_CHECK_EQUAL(ednsAdded, true);
- BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, len);
- /* packet with trailing data (preserving trailing data) */
- memcpy(packet, query.data(), query.size());
- ednsAdded = false;
- ecsAdded = false;
- consumed = 0;
- len = query.size();
- qname = DNSName(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
- BOOST_CHECK_EQUAL(qname, name);
- BOOST_CHECK(qtype == QType::A);
- /* add trailing data */
- /* Making sure we have enough room to allow for fake trailing data */
- BOOST_REQUIRE(sizeof(packet) > len && (sizeof(packet) - len) > trailingDataSize);
- for (size_t idx = 0; idx < trailingDataSize; idx++) {
- packet[len + idx] = 'A';
- }
- len += trailingDataSize;
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, true));
- BOOST_REQUIRE_EQUAL(static_cast<size_t>(len), queryWithEDNS.size() + trailingDataSize);
- BOOST_CHECK_EQUAL(memcmp(queryWithEDNS.data(), packet, queryWithEDNS.size()), 0);
- for (size_t idx = 0; idx < trailingDataSize; idx++) {
- BOOST_CHECK_EQUAL(packet[queryWithEDNS.size() + idx], 'A');
- }
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
+ BOOST_REQUIRE_EQUAL(packet.size(), queryWithEDNS.size());
+ BOOST_CHECK_EQUAL(memcmp(queryWithEDNS.data(), packet.data(), queryWithEDNS.size()), 0);
BOOST_CHECK_EQUAL(ednsAdded, true);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, len);
+ validateQuery(packet);
}
BOOST_AUTO_TEST_CASE(addECSWithoutEDNSAlreadyParsed)
DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
pw.getHeader()->rd = 1;
- /* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSName qname(reinterpret_cast<const char *>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
BOOST_CHECK(qclass == QClass::IN);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
/* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
BOOST_CHECK(!parseEDNSOptions(dq));
/* And now we add our own ECS */
- BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded, false));
- BOOST_CHECK_GT(static_cast<size_t>(dq.len), query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded));
+ BOOST_CHECK_GT(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, true);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, dq.len);
- validateECS(packet, dq.len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
+
+ /* trailing data */
+ packet = query;
+ packet.resize(2048);
- /* not large enough packet */
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- qname = DNSName(reinterpret_cast<char*>(query.data()), query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
BOOST_CHECK(qclass == QClass::IN);
- DNSQuestion dq2(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(query.data()), query.size(), query.size(), false, nullptr);
+ DNSQuestion dq2(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
- BOOST_CHECK(!handleEDNSClientSubnet(dq2, ednsAdded, ecsAdded, false));
- BOOST_CHECK_EQUAL(static_cast<size_t>(dq2.len), query.size());
- BOOST_CHECK_EQUAL(ednsAdded, false);
- BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), dq2.len, false);
+ BOOST_CHECK(handleEDNSClientSubnet(dq2, ednsAdded, ecsAdded));
+ BOOST_CHECK_GT(packet.size(), query.size());
+ BOOST_CHECK_LT(packet.size(), 2048);
+ BOOST_CHECK_EQUAL(ednsAdded, true);
+ BOOST_CHECK_EQUAL(ecsAdded, true);
+ validateQuery(packet);
+ validateECS(packet, remote);
}
BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) {
pw.getHeader()->rd = 1;
pw.addOpt(512, 0, 0);
pw.commit();
- uint16_t len = query.size();
- /* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, false, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, len);
- validateECS(packet, len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
/* not large enough packet */
consumed = 0;
ednsAdded = false;
ecsAdded = false;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ packet = query;
+
+ qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, false, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, false, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len);
+ validateQuery(packet);
}
BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECSAlreadyParsed) {
pw.addOpt(512, 0, 0);
pw.commit();
- /* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
BOOST_CHECK(qclass == QClass::IN);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
/* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
BOOST_CHECK(parseEDNSOptions(dq));
/* And now we add our own ECS */
- BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded, false));
- BOOST_CHECK_GT(static_cast<size_t>(dq.len), query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded));
+ BOOST_CHECK_GT(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, dq.len);
- validateECS(packet, dq.len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
- /* not large enough packet */
+ /* trailing data */
+ packet = query;
+ packet.resize(2048);
consumed = 0;
ednsAdded = false;
ecsAdded = false;
- qname = DNSName(reinterpret_cast<char*>(query.data()), query.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
BOOST_CHECK(qclass == QClass::IN);
- DNSQuestion dq2(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(query.data()), query.size(), query.size(), false, nullptr);
+ DNSQuestion dq2(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
- BOOST_CHECK(!handleEDNSClientSubnet(dq2, ednsAdded, ecsAdded, false));
- BOOST_CHECK_EQUAL(static_cast<size_t>(dq2.len), query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(dq2, ednsAdded, ecsAdded));
+ BOOST_CHECK_GT(packet.size(), query.size());
+ BOOST_CHECK_LT(packet.size(), 2048);
BOOST_CHECK_EQUAL(ednsAdded, false);
- BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), dq2.len);
+ BOOST_CHECK_EQUAL(ecsAdded, true);
+ validateQuery(packet);
+ validateECS(packet, remote);
}
BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) {
opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len);
- validateECS(packet, len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
}
BOOST_AUTO_TEST_CASE(replaceECSWithSameSizeAlreadyParsed) {
pw.addOpt(512, 0, 0, opts);
pw.commit();
- /* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
BOOST_CHECK(qclass == QClass::IN);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
dq.ecsOverride = true;
/* Parse the options before handling ECS, simulating a Lua rule asking for EDNS Options */
BOOST_CHECK(parseEDNSOptions(dq));
/* And now we add our own ECS */
- BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded, false));
- BOOST_CHECK_EQUAL(static_cast<size_t>(dq.len), query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(dq, ednsAdded, ecsAdded));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, dq.len);
- validateECS(packet, dq.len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
}
BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) {
opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
- uint16_t len = query.size();
- /* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len < query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() < query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len);
- validateECS(packet, len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
}
BOOST_AUTO_TEST_CASE(replaceECSWithLarger) {
DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
pw.getHeader()->rd = 1;
EDNSSubnetOpts ecsOpts;
+ // smaller (less specific so less bits) option
+ static_assert(8 < ECSSourcePrefixV4, "The ECS scope should be smaller");
ecsOpts.source = Netmask(origRemote, 8);
string origECSOption = makeEDNSSubnetOptsString(ecsOpts);
DNSPacketWriter::optvect_t opts;
opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len);
- validateECS(packet, len, remote);
+ validateQuery(packet);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len);
+ validateQuery(packet);
}
BOOST_AUTO_TEST_CASE(replaceECSFollowedByTSIG) {
pw.addOpt(512, 0, 0, opts);
pw.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len, true, false, 1);
- validateECS(packet, len, remote);
+ validateQuery(packet, true, false, 1);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, true, false, 1);
+ validateQuery(packet, true, false, 1);
}
BOOST_AUTO_TEST_CASE(replaceECSAfterAN) {
opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len, true, false, 0, 1, 0);
- validateECS(packet, len, remote);
+ validateQuery(packet, true, false, 0, 1, 0);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, true, false, 0, 1, 0);
+ validateQuery(packet, true, false, 0, 1, 0);
}
BOOST_AUTO_TEST_CASE(replaceECSAfterAuth) {
opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption));
pw.addOpt(512, 0, 0, opts);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len, true, false, 0, 0, 1);
- validateECS(packet, len, remote);
+ validateQuery(packet, true, false, 0, 0, 1);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, true, false, 0, 0, 1);
+ validateQuery(packet, true, false, 0, 0, 1);
}
BOOST_AUTO_TEST_CASE(replaceECSBetweenTwoRecords) {
pw.addOpt(512, 0, 0, opts);
pw.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(packet, len, true, false, 2);
- validateECS(packet, len, remote);
+ validateQuery(packet, true, false, 2);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, true, false, 2);
+ validateQuery(packet, true, false, 2);
}
BOOST_AUTO_TEST_CASE(insertECSInEDNSBetweenTwoRecords) {
pw.addOpt(512, 0, 0);
pw.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK(packet.size() > query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, true);
- validateQuery(packet, len, true, false, 2);
- validateECS(packet, len, remote);
+ validateQuery(packet, true, false, 2);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(query, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, true, false, 2);
+ validateQuery(packet, true, false, 2);
}
BOOST_AUTO_TEST_CASE(insertECSAfterTSIG) {
pw.getHeader()->rd = 1;
pw.startRecord(DNSName("tsigname."), QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
pw.commit();
- uint16_t len = query.size();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK((size_t) len > query.size());
+ BOOST_CHECK(handleEDNSClientSubnet(packet, 4096, consumed, ednsAdded, ecsAdded, true, newECSOption));
+ 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, len, true, false, 1), MOADNSException);
- validateECS(packet, len, remote);
+ BOOST_CHECK_THROW(validateQuery(packet, true, false, 1), MOADNSException);
+ validateECS(packet, remote);
/* not large enough packet */
+ packet = query;
+
ednsAdded = false;
ecsAdded = false;
consumed = 0;
- len = query.size();
- qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ qname = DNSName(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, ednsAdded, ecsAdded, true, newECSOption, false));
- BOOST_CHECK_EQUAL((size_t) len, query.size());
+ BOOST_CHECK(!handleEDNSClientSubnet(packet, packet.size(), consumed, ednsAdded, ecsAdded, true, newECSOption));
+ BOOST_CHECK_EQUAL(packet.size(), query.size());
BOOST_CHECK_EQUAL(ednsAdded, false);
BOOST_CHECK_EQUAL(ecsAdded, false);
- validateQuery(reinterpret_cast<char*>(query.data()), len, true, false);
+ validateQuery(packet, true, false);
}
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
- validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
+ validateResponse(newResponse, false, 1);
}
BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
- validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2);
+ validateResponse(newResponse, false, 2);
}
BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */;
BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize);
- validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1);
+ validateResponse(newResponse, false, 1);
}
BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) response.data(), responseLen, true, 1);
+ validateResponse(response, true, 1);
}
BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) response.data(), responseLen, true, 1);
+ validateResponse(response, true, 1);
}
BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) response.data(), responseLen, true, 1);
+ validateResponse(response, true, 1);
}
BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) response.data(), responseLen, true, 1);
+ validateResponse(response, true, 1);
}
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
+ validateResponse(newResponse, true, 1);
}
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
+ validateResponse(newResponse, true, 1);
}
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
+ validateResponse(newResponse, true, 1);
}
BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) {
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed);
+ DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
BOOST_CHECK_EQUAL(qname, name);
BOOST_CHECK(qtype == QType::A);
- validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1);
+ validateResponse(newResponse, true, 1);
}
-static DNSQuestion getDNSQuestion(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& realTime, vector<uint8_t>& query, size_t len)
+static DNSQuestion getDNSQuestion(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& realTime, vector<uint8_t>& query)
{
- dnsheader* dh = reinterpret_cast<dnsheader*>(query.data());
-
- return DNSQuestion(&qname, qtype, qclass, qname.wirelength(), &lc, &rem, dh, query.size(), len, false, &realTime);
+ return DNSQuestion(&qname, qtype, qclass, &lc, &rem, query, false, &realTime);
}
static DNSQuestion turnIntoResponse(const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const ComboAddress& lc, const ComboAddress& rem, const struct timespec& queryRealTime, vector<uint8_t>& query, bool resizeBuffer=true)
{
- size_t length = query.size();
if (resizeBuffer) {
query.resize(4096);
}
- auto dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query, length);
+ auto dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query);
BOOST_CHECK(addEDNSToQueryTurnedResponse(dq));
ComboAddress rem("127.0.0.1");
struct timespec queryRealTime;
gettime(&queryRealTime, true);
- size_t length = query.size();
- DNSQuestion dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query, length);
+ DNSQuestion dq = getDNSQuestion(qname, qtype, qclass, lc, rem, queryRealTime, query);
return getEDNSZ(dq);
}
auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
- BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &udpPayloadSize, &z), false);
+ BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size(), &udpPayloadSize, &z), false);
BOOST_CHECK_EQUAL(z, 0);
BOOST_CHECK_EQUAL(udpPayloadSize, 0);
}
pw.commit();
query.resize(query.size() - (/* RDLEN */ sizeof(uint16_t) + /* last byte of TTL / Z */ 1));
- auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
+ auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query, false);
BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
- BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &udpPayloadSize, &z), false);
+ BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size(), &udpPayloadSize, &z), false);
BOOST_CHECK_EQUAL(z, 0);
BOOST_CHECK_EQUAL(udpPayloadSize, 0);
}
auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
- BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &udpPayloadSize, &z), true);
+ BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size(), &udpPayloadSize, &z), true);
BOOST_CHECK_EQUAL(z, 0);
BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
}
auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
BOOST_CHECK_EQUAL(getEDNSZ(dq), EDNS_HEADER_FLAG_DO);
- BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &udpPayloadSize, &z), true);
+ BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size(), &udpPayloadSize, &z), true);
BOOST_CHECK_EQUAL(z, EDNS_HEADER_FLAG_DO);
BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
}
auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
BOOST_CHECK_EQUAL(getEDNSZ(dq), 0);
- BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &udpPayloadSize, &z), true);
+ BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size(), &udpPayloadSize, &z), true);
BOOST_CHECK_EQUAL(z, 0);
BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
}
auto dq = turnIntoResponse(qname, qtype, qclass, lc, rem, queryRealTime, query);
BOOST_CHECK_EQUAL(getEDNSZ(dq), EDNS_HEADER_FLAG_DO);
- BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.dh), dq.len, &udpPayloadSize, &z), true);
+ BOOST_CHECK_EQUAL(getEDNSUDPPayloadSizeAndZ(reinterpret_cast<const char*>(dq.getData().data()), dq.getData().size(), &udpPayloadSize, &z), true);
BOOST_CHECK_EQUAL(z, EDNS_HEADER_FLAG_DO);
BOOST_CHECK_EQUAL(udpPayloadSize, g_PayloadSizeSelfGenAnswers);
}
pw.getHeader()->rcode = RCode::NXDomain;
pw.commit();
- int res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
+ int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, ENOENT);
/* truncated packet (should not matter) */
query.resize(query.size() - 1);
- res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
+ res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, ENOENT);
}
pw.addOpt(512, 0, 0);
pw.commit();
- int res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
+ int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
/* truncated packet */
query.resize(query.size() - 1);
- res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
+ res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, ENOENT);
}
pw.addOpt(512, 0, 0, opts);
pw.commit();
- int res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
+ int res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
/* truncated options (should not matter for this test) */
query.resize(query.size() - 1);
- res = getEDNSOptionsStart(reinterpret_cast<const char*>(query.data()), qname.wirelength(), query.size(), &optRDPosition, &remaining);
+ res = getEDNSOptionsStart(query, qname.wirelength(), &optRDPosition, &remaining);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK_EQUAL(optRDPosition, optRDExpectedOffset);
BOOST_CHECK_EQUAL(remaining, query.size() - optRDExpectedOffset);
vector<uint8_t> queryWithEDNS;
DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0);
pw.getHeader()->rd = 1;
- const uint16_t len = query.size();
DNSPacketWriter pwEDNS(queryWithEDNS, name, QType::A, QClass::IN, 0);
pwEDNS.getHeader()->rd = 1;
pwEDNS.addOpt(1232, 0, 0);
pwEDNS.commit();
- const uint16_t ednsLen = queryWithEDNS.size();
/* test NXD */
{
/* no incoming EDNS */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5));
- BOOST_CHECK(static_cast<size_t>(dq.len) > query.size());
- MOADNSParser mdp(true, packet, dq.len);
+ BOOST_CHECK(packet.size() > query.size());
+ MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
}
{
/* now with incoming EDNS */
- char packet[1500];
- memcpy(packet, queryWithEDNS.data(), queryWithEDNS.size());
+ auto packet = queryWithEDNS;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, ednsLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), queryWithEDNS.size(), false, &queryTime);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
BOOST_CHECK(setNegativeAndAdditionalSOA(dq, true, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5));
- BOOST_CHECK(static_cast<size_t>(dq.len) > queryWithEDNS.size());
- MOADNSParser mdp(true, packet, dq.len);
+ BOOST_CHECK(packet.size() > queryWithEDNS.size());
+ MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NXDomain);
/* test No Data */
{
/* no incoming EDNS */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), query.size(), false, &queryTime);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5));
- BOOST_CHECK(static_cast<size_t>(dq.len) > query.size());
- MOADNSParser mdp(true, packet, dq.len);
+ BOOST_CHECK(packet.size() > query.size());
+ MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
}
{
/* now with incoming EDNS */
- char packet[1500];
- memcpy(packet, queryWithEDNS.data(), queryWithEDNS.size());
+ auto packet = queryWithEDNS;
unsigned int consumed = 0;
uint16_t qtype;
- DNSName qname(packet, ednsLen, sizeof(dnsheader), false, &qtype, nullptr, &consumed);
- auto dh = reinterpret_cast<dnsheader*>(packet);
- DNSQuestion dq(&qname, qtype, QClass::IN, qname.wirelength(), &remote, &remote, dh, sizeof(packet), queryWithEDNS.size(), false, &queryTime);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, nullptr, &consumed);
+ DNSQuestion dq(&qname, qtype, QClass::IN, &remote, &remote, packet, false, &queryTime);
BOOST_CHECK(setNegativeAndAdditionalSOA(dq, false, DNSName("zone."), 42, DNSName("mname."), DNSName("rname."), 1, 2, 3, 4 , 5));
- BOOST_CHECK(static_cast<size_t>(dq.len) > queryWithEDNS.size());
- MOADNSParser mdp(true, packet, dq.len);
+ BOOST_CHECK(packet.size() > queryWithEDNS.size());
+ MOADNSParser mdp(true, reinterpret_cast<const char*>(packet.data()), packet.size());
BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com.");
BOOST_CHECK_EQUAL(mdp.d_header.rcode, RCode::NoError);
pw.commit();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
BOOST_CHECK(!parseEDNSOptions(dq));
}
pw.commit();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
BOOST_CHECK(!parseEDNSOptions(dq));
}
pw.commit();
/* large enough packet */
- char packet[1500];
- memcpy(packet, query.data(), query.size());
+ auto packet = query;
unsigned int consumed = 0;
uint16_t qtype;
uint16_t qclass;
- DNSName qname(packet, query.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
- DNSQuestion dq(&qname, qtype, qclass, consumed, nullptr, &remote, reinterpret_cast<dnsheader*>(packet), sizeof(packet), query.size(), false, nullptr);
+ DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+ DNSQuestion dq(&qname, qtype, qclass, nullptr, &remote, packet, false, nullptr);
BOOST_CHECK(!parseEDNSOptions(dq));
}
pwR.startRecord(a, QType::A, 7200, QClass::IN, DNSResourceRecord::ANSWER);
pwR.xfr32BitInt(0x01020304);
pwR.commit();
- uint16_t responseLen = response.size();
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- auto dh = reinterpret_cast<dnsheader*>(query.data());
- DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, false, 0, boost::none);
- found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
if (found == true) {
- BOOST_CHECK_EQUAL(responseBufSize, responseLen);
- int match = memcmp(responseBuf, response.data(), responseLen);
+ BOOST_CHECK_EQUAL(dq.getData().size(), response.size());
+ int match = memcmp(dq.getData().data(), response.data(), dq.getData().size());
BOOST_CHECK_EQUAL(match, 0);
BOOST_CHECK(!subnet);
}
vector<uint8_t> query;
DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
pwQ.getHeader()->rd = 1;
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnet, dnssecOK);
if (found == true) {
auto removed = PC.expungeByName(a);
BOOST_CHECK_EQUAL(removed, 1U);
vector<uint8_t> query;
DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
pwQ.getHeader()->rd = 1;
- uint16_t len = query.size();
uint32_t key = 0;
boost::optional<Netmask> subnet;
- char response[4096];
- uint16_t responseSize = sizeof(response);
- DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false, &queryTime);
- if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key, subnet, dnssecOK)) {
+ DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ if (PC.get(dq, pwQ.getHeader()->id, &key, subnet, dnssecOK)) {
matches++;
}
}
pwR.getHeader()->rcode = RCode::ServFail;
pwR.getHeader()->id = pwQ.getHeader()->id;
pwR.commit();
- uint16_t responseLen = response.size();
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- auto dh = reinterpret_cast<dnsheader*>(query.data());
- DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL of 0 (-> should not enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(0));
- found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, false, RCode::ServFail, boost::optional<uint32_t>(0));
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
// Insert with failure-TTL non-zero (-> should enter cache).
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(300));
- found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, false, RCode::ServFail, boost::optional<uint32_t>(300));
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
}
pwR.addOpt(4096, 0, 0);
pwR.commit();
- uint16_t responseLen = response.size();
-
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- auto dh = reinterpret_cast<dnsheader*>(query.data());
- DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&name, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NoError, boost::none);
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, false, RCode::NoError, boost::none);
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
sleep(2);
/* it should have expired by now */
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
}
pwR.addOpt(4096, 0, 0);
pwR.commit();
- uint16_t responseLen = response.size();
-
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- auto dh = reinterpret_cast<dnsheader*>(query.data());
- DNSQuestion dq(&name, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, name.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&name, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnet, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
- PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, name, QType::A, QClass::IN, reinterpret_cast<const char*>(response.data()), responseLen, false, RCode::NXDomain, boost::none);
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, name, QType::A, QClass::IN, response, false, RCode::NXDomain, boost::none);
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK(!subnet);
sleep(2);
/* it should have expired by now */
- found = PC.get(dq, name.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, subnet, dnssecOK, 0, true);
+ found = PC.get(dq, pwR.getHeader()->id, &key, subnet, dnssecOK, 0, true);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK(!subnet);
}
pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER);
pwR.xfr32BitInt(0x01020304);
pwR.commit();
- uint16_t responseLen = response.size();
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- auto dh = reinterpret_cast<dnsheader*>(query.data());
- DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, dh, query.size(), query.size(), false, &queryTime);
- g_PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ g_PC.get(dq, 0, &key, subnet, dnssecOK);
- g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dh)), dnssecOK, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
+ g_PC.insert(key, subnet, *(getFlagsFromDNSHeader(dq.getHeader())), dnssecOK, a, QType::A, QClass::IN, response, false, 0, boost::none);
}
}
catch(PDNSException& e) {
DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
pwQ.getHeader()->rd = 1;
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
uint32_t key = 0;
boost::optional<Netmask> subnet;
- DNSQuestion dq(&a, QType::A, QClass::IN, 0, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false, &queryTime);
- bool found = g_PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key, subnet, dnssecOK);
+ DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = g_PC.get(dq, 0, &key, subnet, dnssecOK);
if (!found) {
g_missing++;
}
pwQ.addOpt(512, 0, 0, ednsOptions);
pwQ.commit();
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
ComboAddress remote("192.0.2.1");
struct timespec queryTime;
gettime(&queryTime);
- DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
+ DNSQuestion dq(&qname, QType::AAAA, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnetOut, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_REQUIRE(subnetOut);
BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
pwR.addOpt(512, 0, 0, ednsOptions);
pwR.commit();
- PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
+ PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), dnssecOK, qname, qtype, QClass::IN, response, false, RCode::NoError, boost::none);
BOOST_CHECK_EQUAL(PC.getSize(), 1U);
- found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, dnssecOK);
+ found = PC.get(dq, 0, &key, subnetOut, dnssecOK);
BOOST_CHECK_EQUAL(found, true);
BOOST_REQUIRE(subnetOut);
BOOST_CHECK_EQUAL(subnetOut->toString(), opt.source.toString());
pwQ.addOpt(512, 0, 0, ednsOptions);
pwQ.commit();
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
ComboAddress remote("192.0.2.1");
struct timespec queryTime;
gettime(&queryTime);
- DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &secondKey, subnetOut, dnssecOK);
+ DNSQuestion dq(&qname, QType::AAAA, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &secondKey, subnetOut, dnssecOK);
BOOST_CHECK_EQUAL(found, false);
BOOST_CHECK_EQUAL(secondKey, key);
BOOST_REQUIRE(subnetOut);
ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
pwFQ.addOpt(512, 0, 0, ednsOptions);
pwFQ.commit();
- secondKey = pc.getKey(qname.toDNSString(), qname.wirelength(), secondQuery.data(), secondQuery.size(), false);
+ secondKey = pc.getKey(qname.toDNSString(), qname.wirelength(), secondQuery, false);
auto pair = colMap.insert(std::make_pair(secondKey, opt.source));
total++;
if (!pair.second) {
pwQ.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
pwQ.commit();
- char responseBuf[4096];
- uint16_t responseBufSize = sizeof(responseBuf);
ComboAddress remote("192.0.2.1");
struct timespec queryTime;
gettime(&queryTime);
- DNSQuestion dq(&qname, QType::AAAA, QClass::IN, 0, &remote, &remote, pwQ.getHeader(), query.size(), query.size(), false, &queryTime);
- bool found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
+ DNSQuestion dq(&qname, QType::AAAA, QClass::IN, &remote, &remote, query, false, &queryTime);
+ bool found = PC.get(dq, 0, &key, subnetOut, true);
BOOST_CHECK_EQUAL(found, false);
vector<uint8_t> response;
pwR.addOpt(512, 0, EDNS_HEADER_FLAG_DO);
pwR.commit();
- PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, qname, qtype, QClass::IN, reinterpret_cast<const char*>(response.data()), response.size(), false, RCode::NoError, boost::none);
+ PC.insert(key, subnetOut, *(getFlagsFromDNSHeader(pwR.getHeader())), /* DNSSEC OK is set */ true, qname, qtype, QClass::IN, response, false, RCode::NoError, boost::none);
BOOST_CHECK_EQUAL(PC.getSize(), 1U);
- found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, false);
+ found = PC.get(dq, 0, &key, subnetOut, false);
BOOST_CHECK_EQUAL(found, false);
- found = PC.get(dq, qname.wirelength(), 0, responseBuf, &responseBufSize, &key, subnetOut, true);
+ found = PC.get(dq, 0, &key, subnetOut, true);
BOOST_CHECK_EQUAL(found, true);
}
addAction("added.trailing.tests.powerdns.com.", LuaAction(replaceTrailingData))
function fillBuffer(dq)
- local available = dq.size - dq.len
+ local available = 4096
local tail = string.rep("A", available)
local success = dq:setTrailingData(tail)
if not success then