Permalink
Browse files

after a decade+.. finally try to stop notifying ourselves. In convoluted

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.
  • Loading branch information...
1 parent 159fe44 commit 8db49a64b49c747a89f22e1942f77483b6e473b3 @ahupowerdns ahupowerdns committed May 5, 2013
Showing with 59 additions and 14 deletions.
  1. +1 −1 pdns/common_startup.cc
  2. +1 −0 pdns/communicator.cc
  3. +1 −0 pdns/communicator.hh
  4. +6 −0 pdns/docs/pdns.xml
  5. +4 −1 pdns/mastercommunicator.cc
  6. +45 −10 pdns/nameserver.cc
  7. +1 −2 pdns/nameserver.hh
@@ -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";
@@ -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)
@@ -198,6 +198,7 @@ private:
bool d_masterschanged, d_slaveschanged;
set<DomainInfo> d_tocheck;
vector<DNSPacket> d_potentialsupermasters;
+ bool d_preventSelfNotification;
};
#endif
View
@@ -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,
@justinclift
justinclift May 6, 2013 Contributor

Guess what wrong? The address to send notification to?

@ahupowerdns
ahupowerdns May 6, 2013 Member

So, if you bind to 0.0.0.0, you could potentially have both BIND and PowerDNS listening on 0.0.0.0 with some settings (reuseaddr). In that case, we would never notify any IP address that is bound to your machine, since they would all appear to be 'us'.

So we'd guess wrong on if the remote end is 'us' exactly (ie, the same powerdns binary).

Perhaps it's not possible now, but SO_REUSEPORT might make this possible. If stupid.

I basically want to be able to tell people to switch off this logic if it turns out it breaks.

@justinclift
justinclift May 6, 2013 Contributor

Thanks Bert. The question was more "this comment is unclear and should be expanded" type of thing, instead of myself just asking directly.

Bad wording on my part. ;)

@Habbie
Habbie May 6, 2013 Member

I have a rule that says "if people ask, fix the docs, then ask if that helps". But it's hard to remember to apply that rule always!

+ set prevent-self-notification to "no".
+ </para></listitem></varlistentry>
<varlistentry><term>query-cache-ttl=...</term>
<listitem><para>
@@ -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();
}
View
@@ -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");
View
@@ -83,7 +83,6 @@ private:
vector<pollfd> d_rfds;
};
-
-
+bool AddressIsUs(const ComboAddress& remote);
#endif

0 comments on commit 8db49a6

Please sign in to comment.