Skip to content

Commit 8db49a6

Browse files
committed
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.
1 parent 159fe44 commit 8db49a6

File tree

7 files changed

+59
-14
lines changed

7 files changed

+59
-14
lines changed

pdns/common_startup.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ void declareArguments()
9696
::arg().setSwitch("guardian","Run within a guardian process")="no";
9797
::arg().setSwitch("strict-rfc-axfrs","Perform strictly rfc compliant axfrs (very slow)")="no";
9898
::arg().setSwitch("send-root-referral","Send out old-fashioned root-referral instead of ServFail in case of no authority")="no";
99-
99+
::arg().setSwitch("prevent-self-notification","Don't send notifications to what we think is ourself")="yes";
100100
::arg().setSwitch("webserver","Start a webserver for monitoring")="no";
101101
::arg().setSwitch("webserver-print-arguments","If the webserver should print arguments")="no";
102102
::arg().setSwitch("edns-subnet-processing","If we should act on EDNS Subnet options")="no";

pdns/communicator.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ void CommunicatorClass::go()
5858
for(int n=0; n < ::arg().asNum("retrieval-threads"); ++n)
5959
pthread_create(&tid, 0, &retrieveLaunchhelper, this); // Starts CommunicatorClass::retrievalLoopThread()
6060

61+
d_preventSelfNotification =::arg().mustDo("prevent-self-notification");
6162
}
6263

6364
void CommunicatorClass::mainloop(void)

pdns/communicator.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ private:
198198
bool d_masterschanged, d_slaveschanged;
199199
set<DomainInfo> d_tocheck;
200200
vector<DNSPacket> d_potentialsupermasters;
201+
bool d_preventSelfNotification;
201202
};
202203

203204
#endif

pdns/docs/pdns.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14628,6 +14628,12 @@ Tell PowerDNS to log all incoming DNS queries. This will lead to a lot of loggin
1462814628
<listitem><para>
1462914629
ABI version to use for the pipe backend. See <xref linkend="pipebackend-protocol"/>.
1463014630
</para></listitem></varlistentry>
14631+
<varlistentry><term>prevent-self-notification | prevent-self-notification = yes | prevent-self-notification = no</term>
14632+
<listitem><para>
14633+
Available as of 3.3. PowerDNS Authoritative Server attempts to not send out notifications to itself in master mode.
14634+
In very complicated situations we could guess wrong and not notify a server that should be notified. In that case,
14635+
set prevent-self-notification to "no".
14636+
</para></listitem></varlistentry>
1463114637

1463214638
<varlistentry><term>query-cache-ttl=...</term>
1463314639
<listitem><para>

pdns/mastercommunicator.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "dnsbackend.hh"
2626
#include "ueberbackend.hh"
2727
#include "packethandler.hh"
28+
#include "nameserver.hh"
2829
#include "resolver.hh"
2930
#include "logger.hh"
3031
#include "dns.hh"
@@ -168,6 +169,9 @@ time_t CommunicatorClass::doNotifications()
168169
if((d_nsock6 < 0 && remote.sin4.sin_family == AF_INET6) ||
169170
(d_nsock4 < 0 && remote.sin4.sin_family == AF_INET))
170171
continue; // don't try to notify what we can't!
172+
if(d_preventSelfNotification && AddressIsUs(remote))
173+
continue;
174+
171175
sendNotification(remote.sin4.sin_family == AF_INET ? d_nsock4 : d_nsock6, domain, remote, id);
172176
drillHole(domain, ip);
173177
}
@@ -225,7 +229,6 @@ void CommunicatorClass::makeNotifySockets()
225229
void CommunicatorClass::notify(const string &domain, const string &ip)
226230
{
227231
d_nq.add(domain, ip);
228-
229232
d_any_sem.post();
230233
}
231234

pdns/nameserver.cc

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ extern StatBag S;
8383
#define GEN_IP_PKTINFO IP_RECVDSTADDR
8484
#endif
8585

86+
vector<ComboAddress> g_localaddresses;
8687

8788
void UDPNameserver::bindIPv4()
8889
{
@@ -95,7 +96,7 @@ void UDPNameserver::bindIPv4()
9596
int s;
9697
for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
9798
string localname(*i);
98-
struct sockaddr_in locala;
99+
ComboAddress locala;
99100

100101
s=socket(AF_INET,SOCK_DGRAM,0);
101102

@@ -108,12 +109,12 @@ void UDPNameserver::bindIPv4()
108109
throw AhuException("Unable to set UDP socket to non-blocking: "+stringerror());
109110

110111
memset(&locala,0,sizeof(locala));
111-
locala.sin_family=AF_INET;
112+
locala.sin4.sin_family=AF_INET;
112113

113114
if(localname=="0.0.0.0") {
114115
int val=1;
115116
setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &val, sizeof(val));
116-
locala.sin_addr.s_addr = INADDR_ANY;
117+
locala.sin4.sin_addr.s_addr = INADDR_ANY;
117118
}
118119
else
119120
{
@@ -122,17 +123,17 @@ void UDPNameserver::bindIPv4()
122123
if(!h)
123124
throw AhuException("Unable to resolve local address");
124125

125-
locala.sin_addr.s_addr=*(int*)h->h_addr;
126+
locala.sin4.sin_addr.s_addr=*(int*)h->h_addr;
126127
}
127128

128-
locala.sin_port=htons(::arg().asNum("local-port"));
129-
130-
if(::bind(s, (sockaddr*)&locala,sizeof(locala))<0) {
131-
L<<Logger::Error<<"binding UDP socket to '"+localname+"' port "+lexical_cast<string>(ntohs(locala.sin_port))+": "<<strerror(errno)<<endl;
129+
locala.sin4.sin_port=htons(::arg().asNum("local-port"));
130+
g_localaddresses.push_back(locala);
131+
if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
132+
L<<Logger::Error<<"binding UDP socket to '"+localname+"' port "+lexical_cast<string>(ntohs(locala.sin4.sin_port))+": "<<strerror(errno)<<endl;
132133
throw AhuException("Unable to bind to UDP socket");
133134
}
134135
d_sockets.push_back(s);
135-
L<<Logger::Error<<"UDP server bound to "<<inet_ntoa(locala.sin_addr)<<":"<<::arg().asNum("local-port")<<endl;
136+
L<<Logger::Error<<"UDP server bound to "<<inet_ntoa(locala.sin4.sin_addr)<<":"<<::arg().asNum("local-port")<<endl;
136137
struct pollfd pfd;
137138
pfd.fd = s;
138139
pfd.events = POLLIN;
@@ -151,6 +152,40 @@ static bool IsAnyAddress(const ComboAddress& addr)
151152
return false;
152153
}
153154

155+
156+
bool AddressIsUs(const ComboAddress& remote)
157+
{
158+
BOOST_FOREACH(const ComboAddress& us, g_localaddresses) {
159+
if(remote == us)
160+
return true;
161+
if(IsAnyAddress(us)) {
162+
int s = socket(AF_INET, SOCK_DGRAM, 0);
163+
if(s < 0)
164+
continue;
165+
166+
if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
167+
close(s);
168+
continue;
169+
}
170+
171+
ComboAddress actualLocal;
172+
actualLocal.sin4.sin_family = remote.sin4.sin_family;
173+
socklen_t socklen = actualLocal.getSocklen();
174+
175+
if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
176+
close(s);
177+
continue;
178+
}
179+
close(s);
180+
actualLocal.sin4.sin_port = us.sin4.sin_port;
181+
if(actualLocal == remote)
182+
return true;
183+
}
184+
}
185+
return false;
186+
}
187+
188+
154189
void UDPNameserver::bindIPv6()
155190
{
156191
#if !WIN32 && HAVE_IPV6
@@ -178,7 +213,7 @@ void UDPNameserver::bindIPv6()
178213
setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
179214
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); // if this fails, we report an error in tcpreceiver too
180215
}
181-
216+
g_localaddresses.push_back(locala);
182217
if(::bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
183218
L<<Logger::Error<<"binding to UDP ipv6 socket: "<<strerror(errno)<<endl;
184219
throw AhuException("Unable to bind to UDP ipv6 socket");

pdns/nameserver.hh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ private:
8383
vector<pollfd> d_rfds;
8484
};
8585

86-
87-
86+
bool AddressIsUs(const ComboAddress& remote);
8887

8988
#endif

0 commit comments

Comments
 (0)