::arg().setSwitch("webserver","Start a webserver for monitoring")="no";
::arg().setSwitch("webserver-print-arguments","If the webserver should print arguments")="no";
+ ::arg().setSwitch("edns-subnet-processing","If we should act on EDNS Subnet options")="no";
::arg().set("webserver-address","IP Address of webserver to listen on")="127.0.0.1";
::arg().set("webserver-port","Port of webserver to listen on")="8081";
::arg().set("webserver-password","Password required for accessing the webserver")="";
int newuid=0;
if(!::arg()["setuid"].empty())
newuid=Utility::makeUidNumeric(::arg()["setuid"]);
+
+
+ DNSPacket::s_doEDNSSubnetProcessing = ::arg().mustDo("edns-subnet-processing");
+
#ifndef WIN32
if(!::arg()["chroot"].empty()) {
uint32_t default_ttl;
int domain_id;
DNSBackend *db;
+ uint8_t scopeMask;
};
class DNSResourceRecord
{
public:
- DNSResourceRecord() : qclass(1), priority(0), last_modified(0), d_place(ANSWER), auth(1) {};
+ DNSResourceRecord() : qclass(1), priority(0), last_modified(0), d_place(ANSWER), auth(1), scopeMask(0) {};
~DNSResourceRecord(){};
// data
Place d_place; //!< This specifies where a record goes within the packet
bool auth;
+ uint8_t scopeMask;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
fillSOAData(rr.content, sd);
sd.domain_id=rr.domain_id;
sd.ttl=rr.ttl;
+ sd.scopeMask = rr.scopeMask;
}
if(!hits)
#include "dnsrecords.hh"
#include "dnssecinfra.hh"
#include "base64.hh"
+#include "ednssubnet.hh"
+
+bool DNSPacket::s_doEDNSSubnetProcessing;
DNSPacket::DNSPacket()
{
d_compress=true;
d_tcp=false;
d_wantsnsid=false;
+ d_haveednssubnet = false;
d_dnssecOk=false;
}
d_maxreplylen = orig.d_maxreplylen;
d_ednsping = orig.d_ednsping;
d_wantsnsid = orig.d_wantsnsid;
+
+ d_eso = orig.d_eso;
+ d_haveednssubnet = orig.d_haveednssubnet;
+
d_dnssecOk = orig.d_dnssecOk;
d_rrs=orig.d_rrs;
if(!d_ednsping.empty()) {
opts.push_back(make_pair(4, d_ednsping));
}
-
- if(!d_rrs.empty() || !opts.empty()) {
+
+
+ if(!d_rrs.empty() || !opts.empty() || d_haveednssubnet) {
try {
+ uint8_t maxScopeMask=0;
for(pos=d_rrs.begin(); pos < d_rrs.end(); ++pos) {
+ maxScopeMask = max(maxScopeMask, pos->scopeMask);
// this needs to deal with the 'prio' mismatch:
if(pos->qtype.getCode()==QType::MX || pos->qtype.getCode() == QType::SRV) {
pos->content = lexical_cast<string>(pos->priority) + " " + pos->content;
goto noCommit;
}
}
+
+ if(d_haveednssubnet) {
+ string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso);
+ EDNSSubnetOpts eso = d_eso;
+ eso.scope = Netmask(eso.source.getNetwork(), maxScopeMask);
+
+ string opt = makeEDNSSubnetOptsString(eso);
+ opts.push_back(make_pair(6, opt));
+ }
+
if(!opts.empty() || d_dnssecOk)
pw.addOpt(2800, 0, d_dnssecOk ? EDNSOpts::DNSSECOK : 0, opts);
r->d_ednsping = d_ednsping;
r->d_wantsnsid = d_wantsnsid;
r->d_dnssecOk = d_dnssecOk;
+ r->d_eso = d_eso;
+ r->d_haveednssubnet = d_haveednssubnet;
if(!d_tsigkeyname.empty()) {
r->d_tsigkeyname = d_tsigkeyname;
d_dnssecOk=false;
d_ednsping.clear();
d_havetsig = mdp.getTSIGPos();
+ d_haveednssubnet = false;
if(getEDNSOpts(mdp, &edo)) {
else if(iter->first == 5) {// 'EDNS PING'
d_ednsping = iter->second;
}
- else
- ; // cerr<<"Have an option #"<<iter->first<<endl;
+ else if(iter->first == 6) { // 'EDNS SUBNET'
+ if(s_doEDNSSubnetProcessing && getEDNSSubnetOptsFromString(iter->second, &d_eso)) {
+ //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
+ d_haveednssubnet=true;
+ }
+ }
+ else {
+ // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
+ }
}
}
else {
d_remote=*s;
}
+Netmask DNSPacket::getRealRemote() const
+{
+ if(d_haveednssubnet)
+ return d_eso.source;
+ return Netmask(d_remote);
+}
+
void DNSPacket::setSocket(Utility::sock_t sock)
{
d_socket=sock;
#include <cstdlib>
#include <sys/types.h>
#include "iputils.hh"
+#include "ednssubnet.hh"
#ifndef WIN32
#include <sys/socket.h>
// address & socket manipulation
void setRemote(const ComboAddress*);
string getRemote() const;
+ Netmask getRealRemote() const;
string getLocal() const
{
ComboAddress ca;
vector<DNSResourceRecord>& getRRS() { return d_rrs; }
TSIGRecordContent d_trc;
+ static bool s_doEDNSSubnetProcessing;
private:
void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies
int d_maxreplylen;
string d_ednsping;
bool d_wantsnsid;
-
+ bool d_haveednssubnet;
+ EDNSSubnetOpts d_eso;
string d_tsigsecret;
string d_tsigkeyname;
string d_tsigprevious;
EDNSSubnetOptsWire esow;
memcpy(&esow, options.c_str(), sizeof(esow));
esow.family = ntohs(esow.family);
- cerr<<"Family: "<<esow.family<<endl;
+ //cerr<<"Family when parsing from string: "<<esow.family<<endl;
ComboAddress address;
if(esow.family == 1) {
if(options.size() != 8)
return false;
address.sin4.sin_family = AF_INET;
memcpy(&address.sin4.sin_addr.s_addr, options.c_str()+4, 4);
- cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
- eso->source = Netmask(address, esow.sourceMask);
- eso->scope = Netmask(address, esow.scopeMask);
- return true;
+ } else if(esow.family == 2) {
+ if(options.size() != 4 + 16)
+ return false;
+ memset(&address, 0, sizeof(address));
+ address.sin4.sin_family = AF_INET6;
+ memcpy(&address.sin6.sin6_addr.s6_addr, options.c_str()+4, 16);
}
- return false;
+ else
+ return false;
+ // cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
+ eso->source = Netmask(address, esow.sourceMask);
+ eso->scope = Netmask(address, esow.scopeMask);
+ return true;
}
string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso)
rr.domain_id=sd.domain_id;
rr.d_place=DNSResourceRecord::AUTHORITY;
rr.auth = 1;
+ rr.scopeMask = sd.scopeMask;
r->addRecord(rr);
if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname))
#include "dnswriter.hh"
#include "dnsrecords.hh"
#include "statbag.hh"
+#include "ednssubnet.hh"
StatBag S;
int main(int argc, char** argv)
DNSPacketWriter pw(packet, argv[3], DNSRecordContent::TypeToNumber(argv[4]));
pw.getHeader()->rd=1;
+
+// void addOpt(int udpsize, int extRCode, int Z, const optvect_t& options=optvect_t());
+ DNSPacketWriter::optvect_t opts;
+ EDNSSubnetOpts eso;
+ eso.scope = eso.source = Netmask("2001:960:2:1e5::2");
+
+ string subnet = makeEDNSSubnetOptsString(eso);
+
+ opts.push_back(make_pair(6, subnet));
+
+ pw.addOpt(1200, 0, 0, opts); // 1200 bytes answer size
+ pw.commit();
Socket sock(InterNetwork, Datagram);
ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
cout<<i->first.d_place-1<<"\t"<<i->first.d_label<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->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 == 6) {
+ EDNSSubnetOpts eso;
+ if(getEDNSSubnetOptsFromString(iter->second, &eso)) {
+ cerr<<"Subnet options in reply: source "<<eso.source.toString()<<", scope "<<eso.scope.toString()<<endl;
+ }
+ else
+ cerr<<"EDNS Subnet failed to parse"<<endl;
+ }
+ else
+ cerr<<"Have unknown option "<<(int)iter->first<<endl;
+ }
+ }
+