~ubuntu-branches/ubuntu/maverick/pdns/maverick-updates

« back to all changes in this revision

Viewing changes to modules/pdnsbackend/pdnsbackend.cc

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Haas
  • Date: 2009-02-25 23:25:51 UTC
  • mfrom: (1.1.7 upstream) (12.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090225232551-ts3d9k9q0ti442i9
Tags: 2.9.22-1
New upstream version (closes: #513409).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// $Id: pdnsbackend.cc 477 2005-09-03 18:15:37Z ahu $ 
 
1
// $Id: pdnsbackend.cc 1317 2008-11-28 15:00:33Z ahu $ 
2
2
 
3
3
#include <string>
4
4
#include <map>
87
87
   }
88
88
}
89
89
 
 
90
void PdnsBackend::Execute(const string& inStatement)
 
91
{
 
92
   //
 
93
   // Cleanup the previous result, if it exists.
 
94
   //
 
95
 
 
96
   if (d_result != NULL) {
 
97
      mysql_free_result(d_result);
 
98
      d_result = NULL;
 
99
   }
 
100
   
 
101
   if (mysql_query(&d_database, inStatement.c_str()) != 0) {
 
102
      throw AhuException(string("mysql_query failed")+string(mysql_error(&d_database)));
 
103
   }
 
104
}
 
105
 
90
106
void PdnsBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int zoneId )
91
107
{
92
108
  string query;
96
112
  // suport wildcard searches
97
113
  
98
114
  if (qname[0]!='%') {
99
 
     query="select r.Content,r.TimeToLive,r.Priority,r.Type,r.ZoneId,r.Name,r.ChangeDate from Records r,Zones z where r.Name='";
 
115
     query  ="select r.Content,r.TimeToLive,r.Priority,r.Type,r.ZoneId,r.Name,r.ChangeDate ";
 
116
     query +="from Records r left join Zones z on r.ZoneId = z.Id where r.Name='";
100
117
  } else {
101
 
     query="select r.Content,r.TimeToLive,r.Priority,r.Type,r.ZoneId,r.Name,r.ChangeDate from Records r,Zones z where r.Name like '";
 
118
     query  ="select r.Content,r.TimeToLive,r.Priority,r.Type,r.ZoneId,r.Name,r.ChangeDate ";
 
119
     query +="from Records r left join Zones z on r.ZoneId = z.Id where r.Name like '";
102
120
  }
103
121
 
104
122
  if (qname.find_first_of("'\\")!=string::npos)
121
139
  }
122
140
  
123
141
  // XXX Make this optional, because it adds an extra load to the db
124
 
  query += " and r.Active <> 0 and r.ZoneId = z.Id and z.Active <> 0";
 
142
  query += " and r.Active <> 0 and z.Active <> 0";
125
143
  
126
144
  DLOG(L<< backendName<<" Query: '" << query << "'"<<endl);
127
145
 
141
159
   return true;
142
160
}
143
161
 
144
 
bool PdnsBackend::getSOA(const string& inZoneName, SOAData& outSoaData)
 
162
bool PdnsBackend::getSOA(const string& inZoneName, SOAData& outSoaData, DNSPacket*)
145
163
{
146
164
   bool theResult = false;
147
165
   MYSQL_ROW theRow = NULL;
174
192
   return theResult;
175
193
}
176
194
 
 
195
bool PdnsBackend::isMaster(const string &name, const string &ip)
 
196
{
 
197
   bool theResult = false;
 
198
   MYSQL_ROW theRow = NULL;
 
199
   string master;
 
200
   
 
201
   ostringstream o;
 
202
   o << "select Master from Zones where Master != '' and Name='"<<sqlEscape(name)<<"'";
 
203
   
 
204
   this->Query(o.str());
 
205
   
 
206
   theRow = mysql_fetch_row(d_result);
 
207
   if (theRow != NULL)
 
208
   {
 
209
      master = theRow[0];
 
210
   }
 
211
   
 
212
   if(master == ip)
 
213
      theResult = true;
 
214
   
 
215
   return theResult;
 
216
}
 
217
 
 
218
void PdnsBackend::getUnfreshSlaveInfos(vector<DomainInfo>* unfreshDomains)
 
219
{
 
220
   MYSQL_ROW theRow = NULL;
 
221
   
 
222
   string o = "select Id,Name,Master,UNIX_TIMESTAMP(ChangeDate) from Zones where Master != ''";
 
223
   
 
224
   this->Query(o);
 
225
   
 
226
   vector<DomainInfo>allSlaves;
 
227
   while((theRow = mysql_fetch_row(d_result)) != NULL) {
 
228
      DomainInfo di;
 
229
      
 
230
      di.id         = atol(theRow[0]);
 
231
      di.zone       = theRow[1];
 
232
      stringtok(di.masters, theRow[2], ", \t");
 
233
      di.last_check = atol(theRow[3]);
 
234
      di.backend    = this;
 
235
      di.kind       = DomainInfo::Slave;
 
236
      allSlaves.push_back(di);
 
237
   }
 
238
   
 
239
   for(vector<DomainInfo>::iterator i=allSlaves.begin(); i!=allSlaves.end();i++) {
 
240
      SOAData sd;
 
241
      sd.serial=0;
 
242
      sd.refresh=0;
 
243
      getSOA(i->zone,sd);
 
244
      if((time_t)(i->last_check+sd.refresh) < time(0)) {
 
245
         i->serial=sd.serial;
 
246
         unfreshDomains->push_back(*i);
 
247
      }
 
248
   }
 
249
}
 
250
 
 
251
bool PdnsBackend::getDomainInfo(const string &domain, DomainInfo &di)
 
252
{
 
253
   bool theResult = false;
 
254
   MYSQL_ROW theRow = NULL;
 
255
   vector<string> masters;
 
256
   
 
257
   ostringstream o;
 
258
   o << "select Id,Name,Master,UNIX_TIMESTAMP(ChangeDate) from Zones WHERE Name='" << sqlEscape(domain) << "'";
 
259
   
 
260
   this->Query(o.str());
 
261
   
 
262
   theRow = mysql_fetch_row(d_result);
 
263
   if (theRow != NULL)
 
264
   {
 
265
      di.id         = atol(theRow[0]);
 
266
      di.zone       = theRow[1];
 
267
      di.last_check = atol(theRow[3]);
 
268
      di.backend    = this;
 
269
      
 
270
      /* We have to store record in local variabel... theRow[2] == NULL makes it empty in di.master = theRow[2]???? */
 
271
      if(theRow[2] != NULL)
 
272
         stringtok(masters, theRow[2], " ,\t");
 
273
      
 
274
      if (masters.empty())
 
275
      {
 
276
         di.kind = DomainInfo::Native;
 
277
      }
 
278
      else
 
279
      {
 
280
         di.serial = 0;
 
281
         try {
 
282
            SOAData sd;
 
283
            if(!getSOA(domain,sd))
 
284
               L<<Logger::Notice<<"No serial for '"<<domain<<"' found - zone is missing?"<<endl;
 
285
            di.serial = sd.serial;
 
286
         }
 
287
         catch (AhuException &ae) {
 
288
            L<<Logger::Error<<"Error retrieving serial for '"<<domain<<"': "<<ae.reason<<endl;
 
289
         }
 
290
         
 
291
         di.kind   = DomainInfo::Slave;
 
292
         di.masters = masters;
 
293
      }
 
294
      
 
295
      theResult = true;
 
296
   }
 
297
      
 
298
   return theResult;
 
299
}
 
300
 
 
301
bool PdnsBackend::startTransaction(const string &qname, int domain_id)
 
302
{
 
303
   ostringstream o;
 
304
   o << "delete from Records where ZoneId=" << domain_id;
 
305
 
 
306
   this->Execute("begin");
 
307
   this->Execute(o.str());
 
308
   
 
309
   d_axfrcount = 0;
 
310
   
 
311
   return true;
 
312
}
 
313
 
 
314
bool PdnsBackend::feedRecord(const DNSResourceRecord &rr)
 
315
{    
 
316
   int qcode = rr.qtype.getCode();
 
317
   
 
318
   /* Check max records to transfer except for SOA and NS records */
 
319
   if((qcode != QType::SOA) && (qcode != QType::NS))
 
320
   {
 
321
      if (d_axfrcount == atol(arg()["pdns-"+d_suffix+"max-slave-records"].c_str())  - 1)
 
322
      {
 
323
         L<<Logger::Warning<<backendName<<" Maximal AXFR records reached: "<<arg()["pdns-"+d_suffix+"max-slave-records"]
 
324
                           <<". Skipping rest of records"<<endl;
 
325
      }
 
326
      
 
327
      if (d_axfrcount >= atol(arg()["pdns-"+d_suffix+"max-slave-records"].c_str())) {
 
328
         return true;
 
329
      }
 
330
      
 
331
      d_axfrcount++; // increase AXFR count for pdns-max-slave-records
 
332
   }
 
333
   
 
334
   /* SOA is not be feeded into Records.. update serial instead */
 
335
   if(qcode == QType::SOA)
 
336
   {
 
337
      string::size_type emailpos = rr.content.find(" ", 0) + 1;
 
338
      string::size_type serialpos = rr.content.find(" ", emailpos) + 1;
 
339
      string::size_type other = rr.content.find(" ", serialpos);
 
340
      string serial = rr.content.substr(serialpos, other - serialpos);
 
341
      
 
342
      ostringstream q;
 
343
      q << "update Zones set Serial=" << serial << " where Id=" << rr.domain_id;
 
344
      
 
345
      this->Execute(q.str());
 
346
      
 
347
      return true;
 
348
   }
 
349
   
 
350
   ostringstream o;
 
351
   o << "insert into Records (ZoneId, Name, Type, Content, TimeToLive, Priority, Flags, Active) values ("
 
352
     << rr.domain_id << ","
 
353
     << "'" << toLower(sqlEscape(rr.qname)).c_str() << "',"
 
354
     << "'" << sqlEscape(rr.qtype.getName()).c_str() << "',"
 
355
     << "'" << sqlEscape(rr.content).c_str() << "',"
 
356
     << rr.ttl << ","
 
357
     << rr.priority << ","
 
358
     << "4" << ","
 
359
     << "1)";
 
360
   
 
361
   this->Execute(o.str());
 
362
   
 
363
   return true;
 
364
}
 
365
 
 
366
bool PdnsBackend::commitTransaction()
 
367
{
 
368
         this->Execute("commit");
 
369
         
 
370
         d_axfrcount = 0;
 
371
         
 
372
         return true;
 
373
}
 
374
 
 
375
bool PdnsBackend::abortTransaction()
 
376
{
 
377
         this->Execute("rollback");
 
378
         
 
379
         d_axfrcount = 0;
 
380
         
 
381
         return true;
 
382
}
 
383
 
 
384
void PdnsBackend::setFresh(u_int32_t domain_id)
 
385
{
 
386
   ostringstream o;
 
387
   o << "update Zones set ChangeDate = NOW() where Id=" << domain_id;
 
388
   
 
389
   this->Execute(o.str());
 
390
}
 
391
 
177
392
//! For the dynamic loader
178
393
DNSBackend *PdnsBackend::maker()
179
394
{
240
455
         declare(suffix,"password","Pdns backend password to connect with","");
241
456
         declare(suffix,"socket","Pdns backend socket to connect to","");
242
457
         declare(suffix,"soa-refresh","Pdns SOA refresh in seconds","");
 
458
         declare(suffix,"max-slave-records","Pdns backend maximal records to transfer", "100");
243
459
      }
244
460
      
245
461
      DNSBackend *make(const string &suffix="")