root/trunk/pdns/pdns/backends/gsql/gsqlbackend.cc @ 477

Revision 477, 11.3 KB (checked in by ahu, 9 years ago)

Move from u_intxx_t to uintxx_t typedefs, which are preferred:
 http://lists.freedesktop.org/pipermail/release-wranglers/2004-August/000926.html
 http://www.oreillynet.com/pub/a/network/2003/10/07/michael_barr.html

massive removal of windows style line-endings

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1// $Id$
2#ifdef WIN32
3# pragma warning ( disable: 4786 )
4#endif // WIN32
5
6#include <string>
7#include <map>
8
9using namespace std;
10
11#include "pdns/dns.hh"
12#include "pdns/dnsbackend.hh"
13#include "gsqlbackend.hh"
14#include "pdns/dnspacket.hh"
15#include "pdns/ueberbackend.hh"
16#include "pdns/ahuexception.hh"
17#include "pdns/logger.hh"
18#include "pdns/arguments.hh"
19
20#include <sstream>
21
22void GSQLBackend::setNotified(uint32_t domain_id, uint32_t serial)
23{
24  char output[1024];
25  snprintf(output,sizeof(output)-1,
26           d_UpdateSerialOfZoneQuery.c_str(),
27           serial, domain_id);
28
29  try {
30    d_db->doCommand(output);
31  }
32  catch(SSqlException &e) {
33    throw AhuException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
34  }
35}
36
37void GSQLBackend::setFresh(uint32_t domain_id)
38{
39  char output[1024];
40  snprintf(output,sizeof(output)-1,d_UpdateLastCheckofZoneQuery.c_str(),
41           time(0),
42           domain_id);
43
44  try {
45    d_db->doCommand(output);
46  }
47  catch (SSqlException &e) {
48    throw AhuException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
49  }
50}
51
52bool GSQLBackend::isMaster(const string &domain, const string &ip)
53{
54  char output[1024];
55  snprintf(output,sizeof(output)-1,
56           d_MasterOfDomainsZoneQuery.c_str(),
57           sqlEscape(domain).c_str());
58  try {
59    d_db->doQuery(output, d_result);
60  }
61  catch (SSqlException &e) {
62    throw AhuException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason());
63  }
64
65  if(d_result.empty())
66    return 0;
67 
68  return !strcmp(ip.c_str(),d_result[0][0].c_str());
69}
70
71bool GSQLBackend::getDomainInfo(const string &domain, DomainInfo &di)
72{
73  /* list all domains that need refreshing for which we are slave, and insert into SlaveDomain:
74     id,name,master IP,serial */
75  char output[1024];
76  snprintf(output,sizeof(output)-1,d_InfoOfDomainsZoneQuery.c_str(),
77           sqlEscape(domain).c_str());
78  try {
79    d_db->doQuery(output,d_result);
80  }
81  catch(SSqlException &e) {
82    throw AhuException("GSQLBackend unable to retrieve information about a domain: "+e.txtReason());
83  }
84
85  int numanswers=d_result.size();
86  if(!numanswers)
87    return false;
88 
89  di.id=atol(d_result[0][0].c_str());
90  di.zone=d_result[0][1];
91  di.master=d_result[0][2];
92  di.last_check=atol(d_result[0][3].c_str());
93  di.backend=this;
94 
95  string type=d_result[0][5];
96  if(type=="SLAVE") {
97    di.serial=0;
98    try {
99      SOAData sd;
100      if(!getSOA(domain,sd))
101        L<<Logger::Notice<<"No serial for '"<<domain<<"' found - zone is missing?"<<endl;
102      di.serial=sd.serial;
103    }
104    catch(AhuException &ae){
105      L<<Logger::Error<<"Error retrieving serial for '"<<domain<<"': "<<ae.reason<<endl;
106    }
107   
108    di.kind=DomainInfo::Slave;
109  }
110  else if(type=="MASTER")
111    di.kind=DomainInfo::Slave;
112  else 
113    di.kind=DomainInfo::Native;
114 
115  return true;
116}
117
118void GSQLBackend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
119{
120  /* list all domains that need refreshing for which we are slave, and insert into SlaveDomain:
121     id,name,master IP,serial */
122  char output[1024];
123  snprintf(output,sizeof(output)-1,d_InfoOfAllSlaveDomainsQuery.c_str());
124
125  try {
126    d_db->doQuery(output,d_result);
127  }
128  catch (SSqlException &e) {
129    throw AhuException("GSQLBackend unable to retrieve list of slave domains: "+e.txtReason());
130  }
131
132  vector<DomainInfo>allSlaves;
133  int numanswers=d_result.size();
134  for(int n=0;n<numanswers;++n) { // id,name,master,last_check
135    DomainInfo sd;
136    sd.id=atol(d_result[n][0].c_str());
137    sd.zone=d_result[n][1];
138    sd.master=d_result[n][2];
139    sd.last_check=atol(d_result[n][3].c_str());
140    sd.backend=this;
141    sd.kind=DomainInfo::Slave;
142    allSlaves.push_back(sd);
143  }
144
145  for(vector<DomainInfo>::iterator i=allSlaves.begin();i!=allSlaves.end();++i) {
146    SOAData sdata;
147    sdata.serial=0;
148    sdata.refresh=0;
149    getSOA(i->zone,sdata);
150    if((time_t)(i->last_check+sdata.refresh) < time(0)) {
151      i->serial=sdata.serial;
152      unfreshDomains->push_back(*i);
153    }
154  }
155}
156
157void GSQLBackend::getUpdatedMasters(vector<DomainInfo> *updatedDomains)
158{
159  /* list all domains that need notifications for which we are master, and insert into updatedDomains
160     id,name,master IP,serial */
161  char output[1024];
162  snprintf(output,sizeof(output)-1,d_InfoOfAllMasterDomainsQuery.c_str());
163
164  try {
165    d_db->doQuery(output,d_result);
166  }
167  catch(SSqlException &e) {
168    throw AhuException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason());
169  }
170
171  vector<DomainInfo>allMasters;
172  int numanswers=d_result.size();
173  for(int n=0;n<numanswers;++n) { // id,name,master,last_check
174    DomainInfo sd;
175    sd.id=atol(d_result[n][0].c_str());
176    sd.zone=d_result[n][1];
177    sd.master=d_result[n][2];
178    sd.last_check=atol(d_result[n][3].c_str());
179    sd.notified_serial=atoi(d_result[n][4].c_str());
180    sd.backend=this;
181    sd.kind=DomainInfo::Master;
182    allMasters.push_back(sd);
183  }
184
185  for(vector<DomainInfo>::iterator i=allMasters.begin();i!=allMasters.end();++i) {
186    SOAData sdata;
187    sdata.serial=0;
188    sdata.refresh=0;
189    getSOA(i->zone,sdata);
190    if(i->notified_serial!=sdata.serial) {
191      i->serial=sdata.serial;
192      updatedDomains->push_back(*i);
193    }
194  }
195}
196
197
198string GSQLBackend::sqlEscape(const string &name)
199{
200  string a;
201
202  for(string::const_iterator i=name.begin();i!=name.end();++i)
203    if(*i=='\'' || *i=='\\'){
204      a+='\\';
205      a+=*i;
206    }
207    else
208      a+=*i;
209  return a;
210}
211
212
213GSQLBackend::GSQLBackend(const string &mode, const string &suffix)
214{
215  setArgPrefix(mode+suffix);
216  d_db=0;
217  d_logprefix="["+mode+"Backend"+suffix+"] ";
218                 
219  d_noWildCardNoIDQuery=getArg("basic-query");
220  d_noWildCardIDQuery=getArg("id-query");
221  d_wildCardNoIDQuery=getArg("wildcard-query");
222  d_wildCardIDQuery=getArg("wildcard-id-query");
223
224  d_noWildCardANYNoIDQuery=getArg("any-query");
225  d_noWildCardANYIDQuery=getArg("any-id-query");
226  d_wildCardANYNoIDQuery=getArg("wildcard-any-query");
227  d_wildCardANYIDQuery=getArg("wildcard-any-id-query");
228 
229  d_listQuery=getArg("list-query");
230
231  d_MasterOfDomainsZoneQuery=getArg("master-zone-query");
232  d_InfoOfDomainsZoneQuery=getArg("info-zone-query");
233  d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query");
234  d_SuperMasterInfoQuery=getArg("supermaster-query");
235  d_InsertSlaveZoneQuery=getArg("insert-slave-query");
236  d_InsertRecordQuery=getArg("insert-record-query");
237  d_UpdateSerialOfZoneQuery=getArg("update-serial-query");
238  d_UpdateLastCheckofZoneQuery=getArg("update-lastcheck-query");
239  d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query");
240  d_DeleteZoneQuery=getArg("delete-zone-query");
241}
242
243
244void GSQLBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int domain_id)
245{
246  string format;
247  char output[1024];
248
249  d_db->setLog(arg().mustDo("query-logging"));
250
251  string lcqname=toLower(qname);
252 
253  if(qtype.getCode()!=QType::ANY) {
254    // qtype qname domain_id
255    if(domain_id<0) {
256      if(qname[0]=='%')
257        format=d_wildCardNoIDQuery;
258      else
259        format=d_noWildCardNoIDQuery;
260
261      snprintf(output,sizeof(output)-1, format.c_str(),sqlEscape(qtype.getName()).c_str(), sqlEscape(lcqname).c_str());
262    }
263    else {
264      if(qname[0]!='%')
265        format=d_noWildCardIDQuery;
266      else
267        format=d_wildCardIDQuery;
268      snprintf(output,sizeof(output)-1, format.c_str(),sqlEscape(qtype.getName()).c_str(),sqlEscape(lcqname).c_str(),domain_id);
269    }
270  }
271  else {
272    // qtype==ANY
273    // qname domain_id
274    if(domain_id<0) {
275      if(qname[0]=='%')
276        format=d_wildCardANYNoIDQuery;
277      else
278        format=d_noWildCardANYNoIDQuery;
279
280      snprintf(output,sizeof(output)-1, format.c_str(),sqlEscape(lcqname).c_str());
281    }
282    else {
283      if(qname[0]!='%')
284        format=d_noWildCardANYIDQuery;
285      else
286        format=d_wildCardANYIDQuery;
287      snprintf(output,sizeof(output)-1, format.c_str(),sqlEscape(lcqname).c_str(),domain_id);
288    }
289  }
290  DLOG(L<< "Query: '" << output << "'"<<endl);
291
292  try {
293    d_db->doQuery(output);
294  }
295  catch(SSqlException &e) {
296    throw AhuException(e.txtReason());
297  }
298
299  d_qname=qname;
300
301  d_qtype=qtype;
302  d_count=0;
303}
304bool GSQLBackend::list(const string &target, int domain_id )
305{
306  DLOG(L<<"GSQLBackend constructing handle for list of domain id'"<<domain_id<<"'"<<endl);
307
308  char output[1024];
309  snprintf(output,sizeof(output)-1,d_listQuery.c_str(),domain_id);
310  try {
311    d_db->doQuery(output);
312  }
313  catch(SSqlException &e) {
314    throw AhuException("GSQLBackend list query: "+e.txtReason());
315  }
316
317  d_qname="";
318  d_count=0;
319  return true;
320}
321
322bool GSQLBackend::superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **ddb)
323{
324  string format;
325  char output[1024];
326  format = d_SuperMasterInfoQuery;
327  // check if we know the ip/ns couple in the database
328  for(vector<DNSResourceRecord>::const_iterator i=nsset.begin();i!=nsset.end();++i) {
329    try {
330      snprintf(output,sizeof(output)-1,format.c_str(),sqlEscape(ip).c_str(),sqlEscape(i->content).c_str());
331      d_db->doQuery(output, d_result);
332    }
333    catch (SSqlException &e) {
334      throw AhuException("GSQLBackend unable to search for a domain: "+e.txtReason());
335    }
336
337    if(!d_result.empty()) {
338      *account=d_result[0][0];
339      *ddb=this;
340      return true;
341    }
342  }
343  return false;
344}
345
346bool GSQLBackend::createSlaveDomain(const string &ip, const string &domain, const string &account)
347{
348  string format;
349  char output[1024];
350  format = d_InsertSlaveZoneQuery;
351  snprintf(output,sizeof(output)-1,format.c_str(),sqlEscape(domain).c_str(),sqlEscape(ip).c_str(),sqlEscape(account).c_str());
352  try {
353    d_db->doCommand(output);
354  }
355  catch(SSqlException &e) {
356    throw AhuException("Database error trying to insert new slave '"+domain+"': "+ e.txtReason());
357  }
358  return true;
359}
360
361
362bool GSQLBackend::get(DNSResourceRecord &r)
363{
364  // L << "GSQLBackend get() was called for "<<qtype.getName() << " record: ";
365  SSql::row_t row;
366  if(d_db->getRow(row)) {
367    r.content=row[0];
368    r.ttl=atol(row[1].c_str());
369    r.priority=atol(row[2].c_str());
370    if(!d_qname.empty())
371      r.qname=d_qname;
372    else
373      r.qname=row[5];
374    r.qtype=row[3];
375    r.last_modified=0;
376   
377    r.domain_id=atoi(row[4].c_str());
378    return true;
379  }
380 
381  return false;
382}
383
384bool GSQLBackend::feedRecord(const DNSResourceRecord &r)
385{
386  char output[1024];
387  snprintf(output,sizeof(output)-1,d_InsertRecordQuery.c_str(),
388           sqlEscape(r.content).c_str(),
389           r.ttl, r.priority,
390           sqlEscape(r.qtype.getName()).c_str(),
391           r.domain_id, toLower(sqlEscape(r.qname)).c_str()); 
392  try {
393    d_db->doCommand(output);
394  }
395  catch (SSqlException &e) {
396    throw AhuException(e.txtReason());
397  }
398  return true; // XXX FIXME this API should not return 'true' I think -ahu
399}
400
401bool GSQLBackend::startTransaction(const string &domain, int domain_id)
402{
403  char output[1024];
404  snprintf(output,sizeof(output)-1,d_DeleteZoneQuery.c_str(),domain_id);
405  try {
406    d_db->doCommand("begin");
407    d_db->doCommand(output);
408  }
409  catch (SSqlException &e) {
410    throw AhuException("Database failed to start transaction: "+e.txtReason());
411  }
412
413  return true;
414}
415
416bool GSQLBackend::commitTransaction()
417{
418  try {
419    d_db->doCommand("commit");
420  }
421  catch (SSqlException &e) {
422    throw AhuException("Database failed to commit transaction: "+e.txtReason());
423  }
424  return true;
425}
426
427bool GSQLBackend::abortTransaction()
428{
429  try {
430    d_db->doCommand("rollback");
431  }
432  catch(SSqlException &e) {
433    throw AhuException("MySQL failed to abort transaction: "+string(e.txtReason()));
434  }
435  return true;
436}
437
Note: See TracBrowser for help on using the browser.