Skip to content

Commit

Permalink
Add cookies support for sdig
Browse files Browse the repository at this point in the history
  • Loading branch information
omoerbeek committed Feb 11, 2025
1 parent 99df0b1 commit 6aa1867
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 25 deletions.
2 changes: 2 additions & 0 deletions docs/manpages/sdig.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ tlsProvider *name*
when using DoT, use TLS provider *name*. Currently supported (if compiled in): `openssl` and `gnutls`. Default is `openssl` if available.
opcode *OPNUM*
Use opcode *OPNUM* instead of 0 (Query). For example, ``sdig 192.0.2.1 53 example.com SOA opcode 4`` sends a ``NOTIFY``.
cookie *COOKIE*
if *COOKIE* is -d send a random client cookie. Otherwise send the given cookie, which should be a hex string received from a server earlier.

Examples
--------
Expand Down
1 change: 1 addition & 0 deletions pdns/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,7 @@ sdig_SOURCES = \
dnsrecords.cc \
dnswriter.cc dnswriter.hh \
dolog.hh \
ednscookies.cc ednscookies.hh \
ednsextendederror.cc ednsextendederror.hh \
ednssubnet.cc iputils.cc \
libssl.cc libssl.hh \
Expand Down
11 changes: 11 additions & 0 deletions pdns/ednscookies.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "config.h"

#include "ednscookies.hh"
#include "dns_random.hh"
#include "iputils.hh"

#ifdef HAVE_CRYPTO_SHORTHASH
Expand Down Expand Up @@ -145,6 +146,16 @@ bool EDNSCookiesOpt::shouldRefresh() const
return rfc1982LessThan(timestamp + 1800, now);
}

void EDNSCookiesOpt::makeClientCookie()
{
uint32_t lower = dns_random_uint32();
uint32_t upper = dns_random_uint32();
client = string();
client.resize(8);
memcpy(client.data(), &lower, sizeof(lower));
memcpy(&client.at(4), &upper, sizeof(upper));
}

bool EDNSCookiesOpt::makeServerCookie([[maybe_unused]] const string& secret, [[maybe_unused]] const ComboAddress& source)
{
#ifdef HAVE_CRYPTO_SHORTHASH
Expand Down
1 change: 1 addition & 0 deletions pdns/ednscookies.hh
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct EDNSCookiesOpt
}

[[nodiscard]] bool isValid(const std::string& secret, const ComboAddress& source) const;
void makeClientCookie();
bool makeServerCookie(const std::string& secret, const ComboAddress& source);
[[nodiscard]] std::string makeOptString() const;
[[nodiscard]] std::string getServer() const
Expand Down
7 changes: 4 additions & 3 deletions pdns/misc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -630,15 +630,16 @@ string U32ToIP(uint32_t val)
}


string makeHexDump(const string& str)
string makeHexDump(const string& str, const string& sep)
{
std::array<char, 5> tmp;
string ret;
ret.reserve(static_cast<size_t>(str.size()*2.2));
ret.reserve(static_cast<size_t>(str.size() * (2 + sep.size())));

for (char n : str) {
snprintf(tmp.data(), tmp.size(), "%02x ", static_cast<unsigned char>(n));
snprintf(tmp.data(), tmp.size(), "%02x", static_cast<unsigned char>(n));
ret += tmp.data();
ret += sep;
}
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion pdns/misc.hh
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ inline double getTime()
throw runtime_error(why + ": " + stringerror(errno));
}

string makeHexDump(const string& str);
string makeHexDump(const string& str, const string& sep = " ");
//! Convert the hexstring in to a byte string
string makeBytesFromHex(const string &in);

Expand Down
2 changes: 1 addition & 1 deletion pdns/recursordist/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ pdns_recursor_SOURCES = \
dnsseckeeper.hh \
dnswriter.cc dnswriter.hh \
dolog.hh \
ednsextendederror.cc ednsextendederror.hh \
ednscookies.cc ednscookies.hh \
ednsextendederror.cc ednsextendederror.hh \
ednsoptions.cc ednsoptions.hh \
ednspadding.cc ednspadding.hh \
ednssubnet.cc ednssubnet.hh \
Expand Down
81 changes: 61 additions & 20 deletions pdns/sdig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "dnswriter.hh"
#include "ednsoptions.hh"
#include "ednssubnet.hh"
#include "ednscookies.hh"
#include "ednsextendederror.hh"
#include "misc.hh"
#include "proxy-protocol.hh"
Expand Down Expand Up @@ -41,6 +42,7 @@ static void usage()
"[dnssec] [ednssubnet SUBNET/MASK] [hidesoadetails] [hidettl] [recurse] [showflags] "
"[tcp] [dot] [insecure] [fastOpen] [subjectName name] [caStore file] [tlsProvider openssl|gnutls] "
"[proxy UDP(0)/TCP(1) SOURCE-IP-ADDRESS-AND-PORT DESTINATION-IP-ADDRESS-AND-PORT] "
"[cookie -/HEX] "
"[dumpluaraw] [opcode OPNUM]"
<< endl;
}
Expand All @@ -57,11 +59,11 @@ static std::unordered_set<uint16_t> s_expectedIDs;

static void fillPacket(vector<uint8_t>& packet, const string& q, const string& t,
bool dnssec, const std::optional<Netmask>& ednsnm,
bool recurse, QClass qclass, uint8_t opcode, uint16_t qid)
bool recurse, QClass qclass, uint8_t opcode, uint16_t qid, const std::optional<string>& cookie)
{
DNSPacketWriter pw(packet, DNSName(q), DNSRecordContent::TypeToNumber(t), qclass, opcode);

if (dnssec || ednsnm || getenv("SDIGBUFSIZE")) {
if (dnssec || ednsnm || getenv("SDIGBUFSIZE") || cookie) {

Check warning on line 66 in pdns/sdig.cc

View workflow job for this annotation

GitHub Actions / Analyze (cpp, auth)

function is not thread safe (concurrency-mt-unsafe - Level=Warning)

Check warning on line 66 in pdns/sdig.cc

View workflow job for this annotation

GitHub Actions / Analyze (cpp, auth)

implicit conversion 'char *' -> bool (readability-implicit-bool-conversion - Level=Warning)
char* sbuf = getenv("SDIGBUFSIZE");
int bufsize;
if (sbuf)
Expand All @@ -74,7 +76,19 @@ static void fillPacket(vector<uint8_t>& packet, const string& q, const string& t
eo.setSource(*ednsnm);
opts.emplace_back(EDNSOptionCode::ECS, eo.makeOptString());
}

if (cookie) {
EDNSCookiesOpt cookieOpt;
if (*cookie == "-") {
cookieOpt.makeClientCookie();
}
else {
string unhex = makeBytesFromHex(*cookie);
if (!cookieOpt.makeFromString(unhex)) {
cerr << "Malformed cookie in argument list, adding anyway" << endl;
}
}
opts.emplace_back(EDNSOptionCode::COOKIE, cookieOpt.makeOptString());
}
pw.addOpt(bufsize, 0, dnssec ? EDNSOpts::DNSSECOK : 0, opts);
pw.commit();
}
Expand Down Expand Up @@ -104,8 +118,18 @@ static void printReply(const string& reply, bool showflags, bool hidesoadetails,
}

cout << endl;
cout << "Rcode: " << mdp.d_header.rcode << " ("
<< RCode::to_s(mdp.d_header.rcode) << "), RD: " << mdp.d_header.rd
EDNSOpts edo{};
bool hasEDNS = getEDNSOpts(mdp, &edo);

if (hasEDNS) {
uint16_t ercode = edo.d_extRCode << 4 | mdp.d_header.rcode;
cout << "Rcode: " << ercode << " (" << ERCode::to_s(ercode);
}
else {
cout << "Rcode: " << mdp.d_header.rcode << " (" << RCode::to_s(mdp.d_header.rcode);
}

cout << "), RD: " << mdp.d_header.rd
<< ", QR: " << mdp.d_header.qr;
cout << ", TC: " << mdp.d_header.tc << ", AA: " << mdp.d_header.aa
<< ", opcode: " << mdp.d_header.opcode << endl;
Expand Down Expand Up @@ -162,28 +186,37 @@ static void printReply(const string& reply, bool showflags, bool hidesoadetails,
cout << "\t" << i->getContent()->getZoneRepresentation() << "\n";
}

EDNSOpts edo;
if (getEDNSOpts(mdp, &edo)) {
// cerr<<"Have "<<edo.d_options.size()<<" options!"<<endl;
for (vector<pair<uint16_t, string>>::const_iterator iter = edo.d_options.begin();
iter != edo.d_options.end(); ++iter) {
if (iter->first == EDNSOptionCode::ECS) { // 'EDNS subnet'
if (hasEDNS) {
for (const auto& iter : edo.d_options) {
if (iter.first == EDNSOptionCode::ECS) { // 'EDNS subnet'
EDNSSubnetOpts reso;
if (EDNSSubnetOpts::getFromString(iter->second, &reso)) {
if (EDNSSubnetOpts::getFromString(iter.second, &reso)) {
cerr << "EDNS Subnet response: " << reso.getSource().toString()
<< ", scope: " << reso.getScope().toString()
<< ", family = " << std::to_string(reso.getFamily())
<< endl;
}
} else if (iter->first == EDNSOptionCode::PADDING) {
cerr << "EDNS Padding size: " << (iter->second.size()) << endl;
} else if (iter->first == EDNSOptionCode::EXTENDEDERROR) {
}
else if (iter.first == EDNSOptionCode::COOKIE) {
EDNSCookiesOpt cookie(iter.second);
auto client = cookie.getClient();
auto server = cookie.getServer();
auto dump = makeHexDump(client, "") + makeHexDump(server, "");
if (cookie.isWellFormed()) {
cerr << "EDNS Cookie response: " << dump << endl;
}
else {
cerr << "EDNS Cookie response malformed: " << dump << endl;
}
} else if (iter.first == EDNSOptionCode::PADDING) {
cerr << "EDNS Padding size: " << iter.second.size() << endl;
} else if (iter.first == EDNSOptionCode::EXTENDEDERROR) {
EDNSExtendedError eee;
if (getEDNSExtendedErrorOptFromString(iter->second, eee)) {
if (getEDNSExtendedErrorOptFromString(iter.second, eee)) {
cerr << "EDNS Extended Error response: " << eee.infoCode << "/" << eee.extraText << endl;
}
} else {
cerr << "Have unknown option " << (int)iter->first << endl;
cerr << "Have unknown option " << (int)iter.first << endl;
}
}
}
Expand Down Expand Up @@ -211,6 +244,7 @@ try {
string caStore;
string tlsProvider = "openssl";
bool dumpluaraw = false;
std::optional<string> cookie;

for (int i = 1; i < argc; i++) {
if ((string)argv[i] == "--help") {
Expand Down Expand Up @@ -303,6 +337,13 @@ try {
ComboAddress dest(argv[++i]);
proxyheader = makeProxyHeader(ptcp, src, dest, {});
}
else if (strcmp(argv[i], "cookie") == 0) {

Check warning on line 340 in pdns/sdig.cc

View workflow job for this annotation

GitHub Actions / Analyze (cpp, auth)

do not use pointer arithmetic (cppcoreguidelines-pro-bounds-pointer-arithmetic - Level=Warning)
if (argc < i + 2) {
cerr << "cookie needs an argument"<<endl;
exit(EXIT_FAILURE);

Check warning on line 343 in pdns/sdig.cc

View workflow job for this annotation

GitHub Actions / Analyze (cpp, auth)

function is not thread safe (concurrency-mt-unsafe - Level=Warning)
}
cookie = argv[++i];

Check warning on line 345 in pdns/sdig.cc

View workflow job for this annotation

GitHub Actions / Analyze (cpp, auth)

do not use pointer arithmetic (cppcoreguidelines-pro-bounds-pointer-arithmetic - Level=Warning)

Check notice

Code scanning / CodeQL

For loop variable changed in body Note

Loop counters should not be modified in the body of the
loop
.
}
else if (strcmp(argv[i], "dumpluaraw") == 0) {
dumpluaraw = true;
}
Expand Down Expand Up @@ -356,7 +397,7 @@ try {
#ifdef HAVE_LIBCURL
vector<uint8_t> packet;
s_expectedIDs.insert(0);
fillPacket(packet, name, type, dnssec, ednsnm, recurse, qclass, opcode, 0);
fillPacket(packet, name, type, dnssec, ednsnm, recurse, qclass, opcode, 0, cookie);
MiniCurl mc;
MiniCurl::MiniCurlHeaders mch;
mch.emplace("Content-Type", "application/dns-message");
Expand Down Expand Up @@ -410,7 +451,7 @@ try {
for (const auto& it : questions) {
vector<uint8_t> packet;
s_expectedIDs.insert(counter);
fillPacket(packet, it.first, it.second, dnssec, ednsnm, recurse, qclass, opcode, counter);
fillPacket(packet, it.first, it.second, dnssec, ednsnm, recurse, qclass, opcode, counter, cookie);
counter++;

// Prefer to do a single write, so that fastopen can send all the data on SYN
Expand Down Expand Up @@ -440,7 +481,7 @@ try {
{
vector<uint8_t> packet;
s_expectedIDs.insert(0);
fillPacket(packet, name, type, dnssec, ednsnm, recurse, qclass, opcode, 0);
fillPacket(packet, name, type, dnssec, ednsnm, recurse, qclass, opcode, 0, cookie);
string question(packet.begin(), packet.end());
Socket sock(dest.sin4.sin_family, SOCK_DGRAM);
question = proxyheader + question;
Expand Down

0 comments on commit 6aa1867

Please sign in to comment.