From: bert hubert Date: Wed, 13 Apr 2016 12:53:27 +0000 (+0200) Subject: add ECS logging to pdns_recursor, teach dnsreplay to add original IP address as ECS... X-Git-Tag: dnsdist-1.0.0-beta1~3^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=976ec823d1e76308fa6db3c0d3bc701b4ab0c628;p=thirdparty%2Fpdns.git add ECS logging to pdns_recursor, teach dnsreplay to add original IP address as ECS, plus document all this --- diff --git a/docs/manpages/dnsreplay.1.md b/docs/manpages/dnsreplay.1.md index cf7ac0bc46..ae1b0fb2df 100644 --- a/docs/manpages/dnsreplay.1.md +++ b/docs/manpages/dnsreplay.1.md @@ -33,6 +33,13 @@ PORT --help | -h : Show summary of options. +--ecs-mask *VAL* +: When EDNS forwarding an IP address, mask out first octet with this value + +--ecs-stamp *FLAG* +: Add original IP address as EDNS Client Subnet Option when forwarding to + reference server + --packet-limit *NUM* : Stop after replaying *NUM* packets. Default for *NUM* is 0, which means no limit. diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 90b1a4b30a..d14b6f67a0 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -844,6 +844,8 @@ dnsreplay_SOURCES = \ dnsrecords.cc \ dnsreplay.cc \ dnswriter.cc dnswriter.hh \ + ednssubnet.cc ednssubnet.hh \ + ednsoptions.cc ednsoptions.hh \ logger.cc \ misc.cc \ nsecrecords.cc \ diff --git a/pdns/dnsreplay.cc b/pdns/dnsreplay.cc index 266a0734fa..1f8a7c7df0 100644 --- a/pdns/dnsreplay.cc +++ b/pdns/dnsreplay.cc @@ -48,7 +48,8 @@ What to do with timeouts. We keep around at most 65536 outstanding answers. #include "anadns.hh" #include #include "dnsrecords.hh" - +#include "ednssubnet.hh" +#include "ednsoptions.hh" // this is needed because boost multi_index also uses 'L', as do we (which is sad enough) #undef L @@ -534,7 +535,55 @@ Orig 9 21 29 36 47 57 66 72 bool g_rdSelector; -bool sendPacketFromPR(PcapPacketReader& pr, const ComboAddress& remote) +static void generateOptRR(const std::string& optRData, string& res) +{ + const uint8_t name = 0; + dnsrecordheader dh; + EDNS0Record edns0; + edns0.extRCode = 0; + edns0.version = 0; + edns0.Z = 0; + + dh.d_type = htons(QType::OPT); + dh.d_class = htons(1280); + memcpy(&dh.d_ttl, &edns0, sizeof edns0); + dh.d_clen = htons((uint16_t) optRData.length()); + res.assign((const char *) &name, sizeof name); + res.append((const char *) &dh, sizeof dh); + res.append(optRData.c_str(), optRData.length()); +} + +static void addECSOption(char* packet, const size_t& packetSize, uint16_t* len, const ComboAddress& remote, int stamp) +{ + string EDNSRR; + struct dnsheader* dh = (struct dnsheader*) packet; + + EDNSSubnetOpts eso; + if(stamp < 0) + eso.source = Netmask(remote); + else { + ComboAddress stamped(remote); + *((char*)&stamped.sin4.sin_addr.s_addr)=stamp; + eso.source = Netmask(stamped); + } + string optRData=makeEDNSSubnetOptsString(eso); + string record; + generateEDNSOption(EDNSOptionCode::ECS, optRData, record); + generateOptRR(record, EDNSRR); + + + uint16_t arcount = ntohs(dh->arcount); + /* does it fit in the existing buffer? */ + if (packetSize - *len > EDNSRR.size()) { + arcount++; + dh->arcount = htons(arcount); + memcpy(packet + *len, EDNSRR.c_str(), EDNSRR.size()); + *len += EDNSRR.size(); + } +} + + +bool sendPacketFromPR(PcapPacketReader& pr, const ComboAddress& remote, int stamp) { dnsheader* dh=(dnsheader*)pr.d_payload; bool sent=false; @@ -550,7 +599,11 @@ bool sendPacketFromPR(PcapPacketReader& pr, const ComboAddress& remote) uint16_t tmp=dh->id; dh->id=htons(qd.d_assignedID); // dh->rd=1; // useful to replay traffic to auths to a recursor - s_socket->sendTo((const char*)pr.d_payload, pr.d_len, remote); + uint16_t dlen = pr.d_len; + + addECSOption((char*)pr.d_payload, 1500, &dlen, pr.getSource(), stamp); + pr.d_len=dlen; + s_socket->sendTo((const char*)pr.d_payload, dlen, remote); sent=true; dh->id=tmp; } @@ -600,11 +653,16 @@ bool sendPacketFromPR(PcapPacketReader& pr, const ComboAddress& remote) } catch(MOADNSException &e) { + if(!g_quiet) + cerr<<"Error parsing packet: "<()->default_value(true), "don't be too noisy") ("recursive", po::value()->default_value(true), "look at recursion desired packets, or not (defaults true)") ("speedup", po::value()->default_value(1), "replay at this speedup") - ("timeout-msec", po::value()->default_value(500), "wait at least this many milliseconds for a reply"); + ("timeout-msec", po::value()->default_value(500), "wait at least this many milliseconds for a reply") + ("ecs-stamp", "Add original IP address to ECS in replay") + ("ecs-mask", po::value(), "Replace first octet of src IP address with this value in ECS"); po::options_description alloptions; po::options_description hidden("hidden options"); @@ -675,6 +735,10 @@ try ComboAddress remote(g_vm["target-ip"].as(), g_vm["target-port"].as()); + int stamp = -1; + if(g_vm.count("ecs-stamp") && g_vm.count("ecs-mask")) + stamp=g_vm["ecs-mask"].as(); + cerr<<"Replaying packets to: '"<()<<"', port "<()< packetLimit) diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 0aaf769e4c..8072d2aaa8 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -762,9 +762,14 @@ void startDoResolve(void *p) } - if(!g_quiet || tracedQuery) + if(!g_quiet || tracedQuery) { L<getTid()<<"/"<numProcesses()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<d_mdp.d_qname<<"|" - <d_mdp.d_qtype)<<"' from "<getRemote()<d_mdp.d_qtype)<<"' from "<getRemote(); + if(!dc->ednssubnet.empty()) { + L<<" (ecs "<ednssubnet.toString()<<")"; + } + L<getTid()); if(!dc->d_mdp.d_header.rd)