#include "dns.hh"
#include "logger.hh"
#include "statbag.hh"
-
+#include <boost/foreach.hpp>
extern StatBag S;
extern PacketCache PC;
ce.qtype = p->qtype.getCode();
ce.qname = p->qdomain;
ce.anyLocal = p->d_anyLocal;
+ ce.complete=0;
d_conntrack[id]=ce;
}
p->d.id=id^d_xor;
return true;
}
+
+//! look up qname aname with r->qtype, plonk it in the answer section of 'r' with name target
+bool DNSProxy::completePacket(DNSPacket *r, const std::string& target,const std::string& aname)
+{
+ uint16_t id;
+ {
+ Lock l(&d_lock);
+ id=getID_locked();
+
+ ConntrackEntry ce;
+ ce.id = r->d.id;
+ ce.remote = r->d_remote;
+ ce.outsock = r->getSocket();
+ ce.created = time( NULL );
+ ce.qtype = r->qtype.getCode();
+ ce.qname = stripDot(target);
+ ce.anyLocal = r->d_anyLocal;
+ ce.complete = r;
+ ce.aname=aname;
+ d_conntrack[id]=ce;
+ }
+
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, target, r->qtype.getCode());
+ pw.getHeader()->rd=true;
+ pw.getHeader()->id=id ^ d_xor;
+
+ if(send(d_sock,&packet[0], packet.size() , 0)<0) { // zoom
+ L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
+ }
+
+ return true;
+
+}
+
+
/** This finds us an unused or stale ID. Does not actually clean the contents */
int DNSProxy::getID_locked()
{
return n;
}
else if(i->second.created<time(0)-60) {
- if(i->second.created)
+ if(i->second.created) {
L<<Logger::Warning<<"Recursive query for remote "<<
i->second.remote.toStringWithPort()<<" with internal id "<<n<<
" was not answered by backend within timeout, reusing id"<<endl;
-
+
+ delete i->second.complete;
+ }
return n;
}
}
L<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
continue;
}
+
d.id=i->second.id;
memcpy(buffer,&d,sizeof(d)); // commit spoofed id
if(p.qtype.getCode() != i->second.qtype || p.qdomain != i->second.qname) {
L<<Logger::Error<<"Discarding packet from recursor backend with id "<<(d.id^d_xor)<<
- ", qname or qtype mismatch"<<endl;
+ ", qname or qtype mismatch ("<<p.qtype.getCode()<<" v " <<i->second.qtype<<", "<<p.qdomain<<" v "<<i->second.qname<<")"<<endl;
continue;
}
/* Set up iov and msgh structures. */
memset(&msgh, 0, sizeof(struct msghdr));
- iov.iov_base = buffer;
- iov.iov_len = len;
+ string reply; // needs to be alive at time of sendmsg!
+ if(i->second.complete) {
+
+ MOADNSParser mdp(p.getString());
+ // cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
+ for(MOADNSParser::answers_t::const_iterator j=mdp.d_answers.begin(); j!=mdp.d_answers.end(); ++j) {
+ // cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
+ if(j->first.d_place == DNSRecord::Answer || (j->first.d_place == DNSRecord::Nameserver && j->first.d_type == QType::SOA)) {
+
+ DNSResourceRecord rr;
+
+ if(j->first.d_type == i->second.qtype || j->first.d_type==QType::SOA) {
+ rr.qname=i->second.aname;
+ rr.qtype = j->first.d_type;
+ rr.ttl=j->first.d_ttl;
+ rr.d_place= (DNSResourceRecord::Place)j->first.d_place;
+ shared_ptr<MXRecordContent> mx=boost::dynamic_pointer_cast<MXRecordContent>(j->first.d_content);
+ shared_ptr<SRVRecordContent> srv=boost::dynamic_pointer_cast<SRVRecordContent>(j->first.d_content);
+ if(mx) {
+ rr.content=mx->d_mxname;
+ rr.priority=mx->d_preference;
+ }
+ else if(srv) {
+ rr.content = lexical_cast<string>(srv->d_weight)+" "+lexical_cast<string>(srv->d_port)+" "+srv->d_target;
+ rr.priority=srv->d_preference;
+ }
+ else {
+ rr.content=j->first.d_content->getZoneRepresentation();
+ }
+ i->second.complete->addRecord(rr);
+ }
+ }
+ }
+ i->second.complete->setRcode(mdp.d_header.rcode);
+ reply=i->second.complete->getString();
+ iov.iov_base = (void*)reply.c_str();
+ iov.iov_len = reply.length();
+ delete i->second.complete;
+ i->second.complete=0;
+ }
+ else {
+ iov.iov_base = buffer;
+ iov.iov_len = len;
+ }
msgh.msg_iov = &iov;
msgh.msg_iovlen = 1;
msgh.msg_name = (struct sockaddr*)&i->second.remote;
void go(); //!< launches the actual thread
void onlyFrom(const string &ips); //!< Only these netmasks are allowed to recurse via us
bool sendPacket(DNSPacket *p); //!< send out a packet and make a conntrack entry to we can send back the answer
+ bool completePacket(DNSPacket *r, const std::string& target,const std::string& aname);
void mainloop(); //!< this is the main loop that receives reply packets and sends them out again
static void *launchhelper(void *p)
time_t created;
string qname;
uint16_t qtype;
+ DNSPacket* complete;
+ string aname;
boost::optional<ComboAddress> anyLocal;
};
boilerplate_conv(NS, ns_t_ns, conv.xfrLabel(d_content, true));
boilerplate_conv(PTR, ns_t_ptr, conv.xfrLabel(d_content, true));
boilerplate_conv(CNAME, ns_t_cname, conv.xfrLabel(d_content, true));
+boilerplate_conv(ALIAS, QType::ALIAS, conv.xfrLabel(d_content, true));
boilerplate_conv(DNAME, ns_t_dname, conv.xfrLabel(d_content));
boilerplate_conv(MR, ns_t_mr, conv.xfrLabel(d_alias, true));
boilerplate_conv(MINFO, ns_t_minfo, conv.xfrLabel(d_rmailbx, true); conv.xfrLabel(d_emailbx, true));
{
AFSDBRecordContent::report();
DNAMERecordContent::report();
+ ALIASRecordContent::report();
SPFRecordContent::report();
NAPTRRecordContent::report();
LOCRecordContent::report();
includeboilerplate(MX)
-private:
uint16_t d_preference;
string d_mxname;
};
includeboilerplate(SRV)
-private:
uint16_t d_preference, d_weight, d_port;
string d_target;
};
string d_content;
};
+class ALIASRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(ALIAS)
+
+private:
+ string d_content;
+};
+
+
class DNAMERecordContent : public DNSRecordContent
{
public:
vector<DNSResourceRecord> rrset;
bool weDone=0, weRedirected=0, weHaveUnauth=0;
+ string haveAlias;
DNSPacket *r=0;
bool noCache=false;
// see what we get..
B.lookup(QType(QType::ANY), target, p, sd.domain_id);
rrset.clear();
+ haveAlias.clear();
weDone = weRedirected = weHaveUnauth = false;
while(B.get(rr)) {
if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME)
weRedirected=1;
+ if(DP && rr.qtype.getCode() == QType::ALIAS) {
+ haveAlias=rr.content;
+ }
+
// Filter out all SOA's and add them in later
if(rr.qtype.getCode() == QType::SOA)
continue;
}
- DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<endl);
+ DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
DLOG(L<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl);
makeNOError(p, r, target, "", sd, 1);
goto sendit;
}
+ if(!haveAlias.empty() && !weDone) {
+ DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
+ DP->completePacket(r, haveAlias, target);
+ return 0;
+ }
+
if(rrset.empty()) {
DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
if(p->qtype.getCode() == QType::DS)
}
}
-
+
DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
bool wereRetargeted(false), nodata(false);
string wildcard;
#undef DS
enum typeenum {A=1, NS=2, CNAME=5, SOA=6, MR=9, PTR=12, HINFO=13, MX=15, TXT=16, RP=17, AFSDB=18, SIG=24, KEY=25, AAAA=28, LOC=29, SRV=33, NAPTR=35, KX=36,
CERT=37, A6=38, DNAME=39, OPT=41, DS=43, SSHFP=44, IPSECKEY=45, RRSIG=46, NSEC=47, DNSKEY=48, DHCID=49, NSEC3=50, NSEC3PARAM=51,
- TLSA=52, SPF=99, EUI48=108, EUI64=109, TSIG=250, IXFR=251, AXFR=252, MAILB=253, MAILA=254, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259, DLV=32769} types;
+ TLSA=52, SPF=99, EUI48=108, EUI64=109, TSIG=250, IXFR=251, AXFR=252, MAILB=253, MAILA=254, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259, ALIAS=260, DLV=32769} types;
typedef pair<string,uint16_t> namenum;
static vector<namenum> names;
qtype_insert("MBOXFW", 257);
qtype_insert("CURL", 258);
qtype_insert("ADDR", 259);
+ qtype_insert("ALIAS", 260);
qtype_insert("DLV", 32769);
}
} initializer;
}
// pw.setRD(true);
- /*
+ /*
pw.startRecord("powerdns.com", DNSRecordContent::TypeToNumber("NS"));
NSRecordContent nrc("ns1.powerdns.com");
nrc.toPacket(pw);