]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/mastercommunicator.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2009 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 #include "packetcache.hh"
21 #include "communicator.hh"
23 #include <boost/utility.hpp>
24 #include "dnsbackend.hh"
25 #include "ueberbackend.hh"
26 #include "packethandler.hh"
27 #include "resolver.hh"
30 #include "arguments.hh"
32 #include "packetcache.hh"
33 #include <boost/lexical_cast.hpp>
35 #include "namespaces.hh"
37 // class that one day might be more than a function to help you get IP addresses for a nameserver
41 vector
<string
>lookup(const string
&name
, DNSBackend
*B
)
43 vector
<string
>addresses
;
45 h
=gethostbyname(name
.c_str());
48 for(char **h_addr_list
=h
->h_addr_list
;*h_addr_list
;++h_addr_list
) {
50 unsigned char *p
=reinterpret_cast<unsigned char *>(*h_addr_list
);
56 addresses
.push_back(os
.str());
60 B
->lookup(QType(QType::A
),name
);
63 addresses
.push_back(rr
.content
); // SOL if you have a CNAME for an NS
69 void CommunicatorClass::queueNotifyDomain(const string
&domain
, DNSBackend
*B
)
76 B
->lookup(QType(QType::NS
),domain
);
78 nsset
.insert(rr
.content
);
80 for(set
<string
>::const_iterator j
=nsset
.begin();j
!=nsset
.end();++j
) {
81 vector
<string
>nsips
=d_fns
.lookup(*j
, B
);
83 L
<<Logger::Warning
<<"Unable to queue notification of domain '"<<domain
<<"': nameservers do not resolve!"<<endl
;
84 for(vector
<string
>::const_iterator k
=nsips
.begin();k
!=nsips
.end();++k
)
88 // make calls to d_nq.add(domain, ip);
89 for(set
<string
>::const_iterator j
=ips
.begin();j
!=ips
.end();++j
) {
90 L
<<Logger::Warning
<<"Queued notification of domain '"<<domain
<<"' to "<<*j
<<endl
;
94 set
<string
>alsoNotify
;
95 B
->alsoNotifies(domain
, &alsoNotify
);
97 for(set
<string
>::const_iterator j
=alsoNotify
.begin();j
!=alsoNotify
.end();++j
) {
98 L
<<Logger::Warning
<<"Queued also-notification of domain '"<<domain
<<"' to "<<*j
<<endl
;
103 bool CommunicatorClass::notifyDomain(const string
&domain
)
107 if(!P
.getBackend()->getDomainInfo(domain
, di
)) {
108 L
<<Logger::Error
<<"No such domain '"<<domain
<<"' in our database"<<endl
;
111 queueNotifyDomain(domain
, P
.getBackend());
112 // call backend and tell them we sent out the notification - even though that is premature
113 di
.backend
->setNotified(di
.id
, di
.serial
);
119 void CommunicatorClass::masterUpdateCheck(PacketHandler
*P
)
121 if(!::arg().mustDo("master"))
124 UeberBackend
*B
=dynamic_cast<UeberBackend
*>(P
->getBackend());
125 vector
<DomainInfo
> cmdomains
;
126 B
->getUpdatedMasters(&cmdomains
);
128 if(cmdomains
.empty()) {
130 L
<<Logger::Warning
<<"No master domains need notifications"<<endl
;
131 d_masterschanged
=false;
134 d_masterschanged
=true;
135 L
<<Logger::Error
<<cmdomains
.size()<<" domain"<<(cmdomains
.size()>1 ? "s" : "")<<" for which we are master need"<<
136 (cmdomains
.size()>1 ? "" : "s")<<
137 " notifications"<<endl
;
140 // figure out A records of everybody needing notification
141 // do this via the FindNS class, d_fns
143 for(vector
<DomainInfo
>::const_iterator i
=cmdomains
.begin();i
!=cmdomains
.end();++i
) {
144 extern PacketCache PC
;
145 vector
<string
> topurge
;
146 topurge
.push_back(i
->zone
);
147 PC
.purge(topurge
); // fixes cvstrac ticket #30
148 queueNotifyDomain(i
->zone
,P
->getBackend());
149 i
->backend
->setNotified(i
->id
,i
->serial
);
153 time_t CommunicatorClass::doNotifications()
156 Utility::socklen_t fromlen
=sizeof(from
);
159 static Resolver d_nresolver
;
160 // receive incoming notifications on the nonblocking socket and take them off the list
162 while((size
=recvfrom(d_nsock
,buffer
,sizeof(buffer
),0,(struct sockaddr
*)&from
,&fromlen
))>0) {
167 if(p
.parse(buffer
,size
)<0) {
168 L
<<Logger::Warning
<<"Unable to parse SOA notification answer from "<<p
.getRemote()<<endl
;
173 L
<<Logger::Warning
<<"Received unsuccesful notification report for '"<<p
.qdomain
<<"' from "<<p
.getRemote()<<", rcode: "<<p
.d
.rcode
<<endl
;
175 if(d_nq
.removeIf(p
.getRemote(), p
.d
.id
, p
.qdomain
))
176 L
<<Logger::Warning
<<"Removed from notification list: '"<<p
.qdomain
<<"' to "<<p
.getRemote()<< (p
.d
.rcode
? "" : " (was acknowledged)")<<endl
;
178 L
<<Logger::Warning
<<"Received spurious notify answer for '"<<p
.qdomain
<<"' from "<<p
.getRemote()<<endl
;
181 // send out possible new notifications
186 while(d_nq
.getOne(domain
, ip
, &id
, purged
)) {
189 d_nresolver
.notify(d_nsock
, domain
, ip
, id
);
190 drillHole(domain
, ip
);
192 catch(ResolverException
&re
) {
193 L
<<Logger::Error
<<"Error trying to resolve '"+ip
+"' for notifying '"+domain
+"' to server: "+re
.reason
<<endl
;
197 L
<<Logger::Error
<<Logger::NTLog
<<"Notification for "<<domain
<<" to "<<ip
<<" failed after retries"<<endl
;
200 return d_nq
.earliest();
203 void CommunicatorClass::drillHole(const string
&domain
, const string
&ip
)
206 d_holes
[make_pair(domain
,ip
)]=time(0);
209 bool CommunicatorClass::justNotified(const string
&domain
, const string
&ip
)
212 if(d_holes
.find(make_pair(domain
,ip
))==d_holes
.end()) // no hole
215 if(d_holes
[make_pair(domain
,ip
)]>time(0)-900) // recent hole
218 // do we want to purge this? XXX FIXME
222 void CommunicatorClass::makeNotifySocket()
224 if((d_nsock
=socket(AF_INET
, SOCK_DGRAM
,0))<0)
225 throw AhuException(string("notification socket: ")+strerror(errno
));
227 struct sockaddr_in sin
;
228 memset((char *)&sin
,0, sizeof(sin
));
230 sin
.sin_family
= AF_INET
;
232 // Bind to a specific IP (query-local-address) if specified
233 string
querylocaladdress(::arg()["query-local-address"]);
234 if (querylocaladdress
=="") {
235 sin
.sin_addr
.s_addr
= INADDR_ANY
;
240 h
=gethostbyname(querylocaladdress
.c_str());
242 Utility::closesocket(d_nsock
);
244 throw AhuException("Unable to resolve query local address");
247 sin
.sin_addr
.s_addr
= *(int*)h
->h_addr
;
252 sin
.sin_port
= htons(10000+(Utility::random()%50000));
254 if(::bind(d_nsock
, (struct sockaddr
*)&sin
, sizeof(sin
)) >= 0)
258 Utility::closesocket(d_nsock
);
260 throw AhuException(string("binding notify socket: ")+strerror(errno
));
262 if( !Utility::setNonBlocking( d_nsock
))
263 throw AhuException(string("error getting or setting notify socket non-blocking: ")+strerror(errno
));
267 void CommunicatorClass::notify(const string
&domain
, const string
&ip
)
269 d_nq
.add(domain
, ip
);