]> granicus.if.org Git - pdns/commitdiff
after a decade+.. finally try to stop notifying ourselves. In convoluted
authorbert hubert <bert.hubert@netherlabs.nl>
Sun, 5 May 2013 19:22:03 +0000 (21:22 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Sun, 5 May 2013 19:22:03 +0000 (21:22 +0200)
cases involving REUSE_PORT and binding to 0.0.0.0 and ::, it might be
possible that we guess wrong, in which case we now provide & document
the setting prevent-self-notification which you could then set to off.

pdns/common_startup.cc
pdns/communicator.cc
pdns/communicator.hh
pdns/docs/pdns.xml
pdns/mastercommunicator.cc
pdns/nameserver.cc
pdns/nameserver.hh

index 4f0959cbdb67d37909d8be165ac2168e69f3e8ba..fc86aca4993de9b2d9c5c017f974a43e40812a10 100644 (file)
@@ -96,7 +96,7 @@ void declareArguments()
   ::arg().setSwitch("guardian","Run within a guardian process")="no";
   ::arg().setSwitch("strict-rfc-axfrs","Perform strictly rfc compliant axfrs (very slow)")="no";
   ::arg().setSwitch("send-root-referral","Send out old-fashioned root-referral instead of ServFail in case of no authority")="no";
-
+  ::arg().setSwitch("prevent-self-notification","Don't send notifications to what we think is ourself")="yes";
   ::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"; 
index 889f1b7135bde5412be6c09f10e73ce530c21275..4f2038e79b02f4867b6c3c741fa7785467dae117 100644 (file)
@@ -58,6 +58,7 @@ void CommunicatorClass::go()
   for(int n=0; n < ::arg().asNum("retrieval-threads"); ++n)
     pthread_create(&tid, 0, &retrieveLaunchhelper, this); // Starts CommunicatorClass::retrievalLoopThread()
 
+  d_preventSelfNotification =::arg().mustDo("prevent-self-notification");
 }
 
 void CommunicatorClass::mainloop(void)
index d2e15a6d6b117e60e952e703121be82cc466984b..267a2a94add07948ff22ea3bd01442b8b6802fd3 100644 (file)
@@ -198,6 +198,7 @@ private:
   bool d_masterschanged, d_slaveschanged;
   set<DomainInfo> d_tocheck;
   vector<DNSPacket> d_potentialsupermasters;
+  bool d_preventSelfNotification;
 };
 
 #endif
index a0b485a1b76030c03bbbecbe4c557b53cda67182..71fb35fa86bc51d52dcba3a0a6e298bc2f8fbdc4 100644 (file)
@@ -14628,6 +14628,12 @@ Tell PowerDNS to log all incoming DNS queries. This will lead to a lot of loggin
            <listitem><para>
              ABI version to use for the pipe backend. See <xref linkend="pipebackend-protocol"/>.
              </para></listitem></varlistentry>
+          <varlistentry><term>prevent-self-notification | prevent-self-notification = yes | prevent-self-notification = no</term>
+           <listitem><para>
+               Available as of 3.3. PowerDNS Authoritative Server attempts to not send out notifications to itself in master mode.
+               In very complicated situations we could guess wrong and not notify a server that should be notified. In that case,
+               set prevent-self-notification to "no".
+             </para></listitem></varlistentry>
 
          <varlistentry><term>query-cache-ttl=...</term>
            <listitem><para>
index 8a72e31a21956306f1733724b4e8c3aaa20e3f34..c8cf3dbf28970c2204e74e3d0dc898db69f3c810 100644 (file)
@@ -25,6 +25,7 @@
 #include "dnsbackend.hh"
 #include "ueberbackend.hh"
 #include "packethandler.hh"
+#include "nameserver.hh"
 #include "resolver.hh"
 #include "logger.hh"
 #include "dns.hh"
@@ -168,6 +169,9 @@ time_t CommunicatorClass::doNotifications()
         if((d_nsock6 < 0 && remote.sin4.sin_family == AF_INET6) ||
            (d_nsock4 < 0 && remote.sin4.sin_family == AF_INET))
              continue; // don't try to notify what we can't!
+       if(d_preventSelfNotification && AddressIsUs(remote))
+         continue;
+
         sendNotification(remote.sin4.sin_family == AF_INET ? d_nsock4 : d_nsock6, domain, remote, id); 
         drillHole(domain, ip);
       }
@@ -225,7 +229,6 @@ void CommunicatorClass::makeNotifySockets()
 void CommunicatorClass::notify(const string &domain, const string &ip)
 {
   d_nq.add(domain, ip);
-
   d_any_sem.post();
 }
 
index 1eb3ae1fb7a9adc364b30e0ccce1497ae7a4dc01..5584a62ac31a09ab1d693ac0b10d580a158e47d8 100644 (file)
@@ -83,6 +83,7 @@ extern StatBag S;
   #define GEN_IP_PKTINFO IP_RECVDSTADDR 
 #endif
 
+vector<ComboAddress> g_localaddresses;
 
 void UDPNameserver::bindIPv4()
 {
@@ -95,7 +96,7 @@ void UDPNameserver::bindIPv4()
   int s;
   for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
     string localname(*i);
-    struct sockaddr_in locala;
+    ComboAddress locala;
 
     s=socket(AF_INET,SOCK_DGRAM,0);
 
@@ -108,12 +109,12 @@ void UDPNameserver::bindIPv4()
       throw AhuException("Unable to set UDP socket to non-blocking: "+stringerror());
   
     memset(&locala,0,sizeof(locala));
-    locala.sin_family=AF_INET;
+    locala.sin4.sin_family=AF_INET;
 
     if(localname=="0.0.0.0") {
       int val=1;
       setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &val, sizeof(val));
-      locala.sin_addr.s_addr = INADDR_ANY;
+      locala.sin4.sin_addr.s_addr = INADDR_ANY;
     }
     else
     {
@@ -122,17 +123,17 @@ void UDPNameserver::bindIPv4()
       if(!h)
         throw AhuException("Unable to resolve local address"); 
 
-      locala.sin_addr.s_addr=*(int*)h->h_addr;
+      locala.sin4.sin_addr.s_addr=*(int*)h->h_addr;
     }
 
-    locala.sin_port=htons(::arg().asNum("local-port"));
-    
-    if(::bind(s, (sockaddr*)&locala,sizeof(locala))<0) {
-      L<<Logger::Error<<"binding UDP socket to '"+localname+"' port "+lexical_cast<string>(ntohs(locala.sin_port))+": "<<strerror(errno)<<endl;
+    locala.sin4.sin_port=htons(::arg().asNum("local-port"));
+    g_localaddresses.push_back(locala);
+    if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
+      L<<Logger::Error<<"binding UDP socket to '"+localname+"' port "+lexical_cast<string>(ntohs(locala.sin4.sin_port))+": "<<strerror(errno)<<endl;
       throw AhuException("Unable to bind to UDP socket");
     }
     d_sockets.push_back(s);
-    L<<Logger::Error<<"UDP server bound to "<<inet_ntoa(locala.sin_addr)<<":"<<::arg().asNum("local-port")<<endl;
+    L<<Logger::Error<<"UDP server bound to "<<inet_ntoa(locala.sin4.sin_addr)<<":"<<::arg().asNum("local-port")<<endl;
     struct pollfd pfd;
     pfd.fd = s;
     pfd.events = POLLIN;
@@ -151,6 +152,40 @@ static bool IsAnyAddress(const ComboAddress& addr)
   return false;
 }
 
+
+bool AddressIsUs(const ComboAddress& remote)
+{
+  BOOST_FOREACH(const ComboAddress& us, g_localaddresses) {
+    if(remote == us)
+      return true;
+    if(IsAnyAddress(us)) {
+      int s = socket(AF_INET, SOCK_DGRAM, 0);
+      if(s < 0) 
+       continue;
+
+      if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
+       close(s);
+       continue;
+      }
+    
+      ComboAddress actualLocal;
+      actualLocal.sin4.sin_family = remote.sin4.sin_family;
+      socklen_t socklen = actualLocal.getSocklen();
+
+      if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
+       close(s);
+       continue;
+      }
+      close(s);
+      actualLocal.sin4.sin_port = us.sin4.sin_port;
+      if(actualLocal == remote)
+       return true;
+    }
+  }
+  return false;
+}
+
+
 void UDPNameserver::bindIPv6()
 {
 #if !WIN32 && HAVE_IPV6
@@ -178,7 +213,7 @@ void UDPNameserver::bindIPv6()
       setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val)); 
       setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));      // if this fails, we report an error in tcpreceiver too
     }
-    
+    g_localaddresses.push_back(locala);
     if(::bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
       L<<Logger::Error<<"binding to UDP ipv6 socket: "<<strerror(errno)<<endl;
       throw AhuException("Unable to bind to UDP ipv6 socket");
index 00574ba71ece86103334c3e063ef7fcc3ca589a9..f7b56cb037465d0268acee1c249e70dadc0423ff 100644 (file)
@@ -83,7 +83,6 @@ private:
   vector<pollfd> d_rfds;
 };
 
-
-
+bool AddressIsUs(const ComboAddress& remote);
 
 #endif