]> granicus.if.org Git - pdns/commitdiff
make anti-spoofing measures question and not ip address specific, make them tunable
authorBert Hubert <bert.hubert@netherlabs.nl>
Fri, 14 Apr 2006 12:35:19 +0000 (12:35 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Fri, 14 Apr 2006 12:35:19 +0000 (12:35 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@700 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/dnspbench.cc
pdns/lwres.cc
pdns/lwres.hh
pdns/pdns_recursor.cc
pdns/rec_channel_rec.cc
pdns/syncres.hh

index bf164dc351e754d7e84702164c1c2bafcc6f288e..b81030602f22177b8045946ebf00d9d914f646cc 100644 (file)
@@ -46,7 +46,7 @@ try
 
   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;
index bddda1d2b073ccac7b4a89e9a4eed0c82e8b31ca..93a18b042846fa7652710f77c56a6f5e974eb152 100644 (file)
@@ -88,7 +88,7 @@ int LWRes::asyncresolve(uint32_t ip, const string& domain, int type, bool doTCP,
   
     // 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);
index 1514c9e9a4de835c1b54d1fbe481fd3579729fd9..66d999072dfe6b89636ae1fcccab2444a41ad2d2 100644 (file)
@@ -44,7 +44,7 @@
 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
 {
index 95cde053238cfe5b18d9694b8f6ecffda36acaf5..418d51afe398566d48ee9a403c78605270411c4f 100644 (file)
@@ -172,10 +172,15 @@ int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int a
 }
 
 // -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;
@@ -183,8 +188,9 @@ int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, Utility::
   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;
     }
   }
@@ -741,6 +747,25 @@ int gettimeofday (struct timeval *__restrict __tv,
 }
 #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();
@@ -778,6 +803,7 @@ int main(int argc, char **argv)
     ::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);
@@ -998,15 +1024,16 @@ int main(int argc, char **argv)
              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++;
                    }
                  }
index c1d675e26c9463e1bfbfe4afd6602a6abe80f32b..a9f1a8d1289057e535b36ca766a29998e7503d8f 100644 (file)
@@ -153,6 +153,8 @@ RecursorControlParser::RecursorControlParser()
   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)));
index e224db35847c9be0aaa39aaaae48967e58eeab55..07ae33468c82627d2aa197ff9a4ee39f63852b38 100644 (file)
@@ -322,6 +322,7 @@ struct PacketID
 
   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
@@ -336,9 +337,14 @@ struct PacketID
   {
     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;
   }
 };
 
@@ -361,6 +367,7 @@ struct RecursorStats
   uint64_t clientParseError;
   uint64_t serverParseError;
   uint64_t unexpectedCount;
+  uint64_t spoofCount;
 };
 
 extern RecursorStats g_stats;