Socket s(InterNetwork, Datagram);
- IPEndpoint rem("127.0.0.1",1232), loc("213.156.2.1", 53);
+ IPEndpoint rem("10.0.1.6",35515), loc("213.156.2.1", 53);
s.bind(loc);
vector<uint8_t> vpacket;
// sleep until we see an answer to this, interface to mtasker
- ret=arecvfrom(reinterpret_cast<char *>(d_buf), d_bufsize-1,0,(struct sockaddr*)(&toaddr), &addrlen, &d_len, pw.getHeader()->id);
+ ret=arecvfrom(reinterpret_cast<char *>(d_buf), d_bufsize-1,0,(struct sockaddr*)(&toaddr), &addrlen, &d_len, pw.getHeader()->id, domain);
}
else {
Socket s(InterNetwork, Stream);
using namespace std;
int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id);
-int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id);
+int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id, const string& domain);
class LWResException : public AhuException
{
}
// -1 is error, 0 is timeout, 1 is success
-int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id)
+int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::socklen_t *addrlen, int *d_len, int id, const string& domain)
{
+ static optional<unsigned int> nearMissLimit;
+ if(!nearMissLimit)
+ nearMissLimit=::arg().asNum("spoof-nearmiss-max");
+
PacketID pident;
pident.id=id;
+ pident.domain=domain;
memcpy(&pident.remote, toaddr, sizeof(pident.remote));
string packet;
if(ret > 0) {
*d_len=packet.size();
memcpy(data,packet.c_str(),min(len,*d_len));
- if(pident.nearMisses > 100) {
- L<<Logger::Error<<"Too many ("<<pident.nearMisses<<") bogus answers came in from "<<sockAddrToString((struct sockaddr_in*)toaddr, sizeof(pident.remote))<<", assuming spoof attempt."<<endl;
+ if(*nearMissLimit && pident.nearMisses > *nearMissLimit) {
+ L<<Logger::Error<<"Too many ("<<pident.nearMisses<<" > "<<*nearMissLimit<<") bogus answers for '"<<domain<<"' from "<<sockAddrToString((struct sockaddr_in*)toaddr, sizeof(pident.remote))<<", assuming spoof attempt."<<endl;
+ g_stats.spoofCount++;
return -1;
}
}
}
#endif
+string questionExpand(const char* packet, uint16_t len)
+{
+ const char* end=packet+len;
+ const char* pos=packet+12;
+ unsigned char labellen;
+ string ret;
+
+ while((labellen=*pos++)) {
+ if(pos+labellen > end)
+ break;
+ ret.append(pos, labellen);
+ ret.append(1,'.');
+ pos+=labellen;
+ }
+ if(ret.empty())
+ ret=".";
+ return ret;
+}
+
int main(int argc, char **argv)
{
reportBasicTypes();
::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12";
::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
::arg().set("fork", "If set, fork the daemon for possible double performance")="no";
+ ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
::arg().setCmd("help","Provide a helpful message");
L.toConsole(Logger::Warning);
if(dh.qr && dh.qdcount) {
pident.remote=fromaddr;
pident.id=dh.id;
+ pident.domain=questionExpand(data, d_len);
string packet;
packet.assign(data, d_len);
if(!MT->sendEvent(pident, &packet)) {
if(logCommonErrors)
- L<<Logger::Warning<<"Discarding unexpected packet from "<<sockAddrToString((struct sockaddr_in*) &fromaddr, addrlen)<<endl;
+ L<<Logger::Warning<<"Discarding unexpected packet answering '"<<pident.domain<<"' from "<<sockAddrToString((struct sockaddr_in*) &fromaddr, addrlen)<<endl;
g_stats.unexpectedCount++;
for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) {
- if(!memcmp(&mthread->key.remote.sin_addr, &pident.remote.sin_addr, sizeof(pident.remote.sin_addr))) {
+ if(!memcmp(&mthread->key.remote.sin_addr, &pident.remote.sin_addr, sizeof(pident.remote.sin_addr)) && !strcasecmp(pident.domain.c_str(), mthread->key.domain.c_str())) {
mthread->key.nearMisses++;
}
}
addGetStat("answers-slow", &g_stats.answersSlow);
addGetStat("qa-latency", &g_stats.avgLatencyUsec);
+ addGetStat("unexpected-packets", &g_stats.unexpectedCount);
+ addGetStat("spoof-prevents", &g_stats.spoofCount);
addGetStat("negcache-entries", boost::bind(&SyncRes::negcache_t::size, ref(SyncRes::s_negcache)));
addGetStat("throttle-entries", boost::bind(&SyncRes::throttle_t::size, ref(SyncRes::s_throttle)));
uint16_t id; // wait for a specific id/remote pair
struct sockaddr_in remote; // this is the remote
+ string domain; // this is the question
Socket* sock; // or wait for an event on a TCP fd
int inNeeded; // if this is set, we'll read until inNeeded bytes are read
{
int ourSock= sock ? sock->getHandle() : 0;
int bSock = b.sock ? b.sock->getHandle() : 0;
- return
- tie(id, remote.sin_addr.s_addr, remote.sin_port, ourSock) <
- tie(b.id, b.remote.sin_addr.s_addr, b.remote.sin_port, bSock);
+ if( tie(id, remote.sin_addr.s_addr, remote.sin_port, ourSock) <
+ tie(b.id, b.remote.sin_addr.s_addr, b.remote.sin_port, bSock))
+ return true;
+ if( tie(id, remote.sin_addr.s_addr, remote.sin_port, ourSock) >
+ tie(b.id, b.remote.sin_addr.s_addr, b.remote.sin_port, bSock))
+ return false;
+
+ return strcasecmp(domain.c_str(), b.domain.c_str()) < 0;
}
};
uint64_t clientParseError;
uint64_t serverParseError;
uint64_t unexpectedCount;
+ uint64_t spoofCount;
};
extern RecursorStats g_stats;