root/trunk/pdns/modules/opendbxbackend/odbxbackend.cc @ 977

Revision 977, 17.0 KB (checked in by ahu, 6 years ago)

ldap, opendbx updates

Line 
1#include "odbxbackend.hh"
2
3
4
5inline string& strbind( const string& search, const string& replace, string& subject )
6{
7        size_t pos = 0;
8
9        while( ( pos = subject.find( search, pos ) ) != string::npos )
10        {
11                subject.replace( pos, search.size(), replace );
12                pos += replace.size();
13        }
14
15        return subject;
16}
17
18
19
20inline string& toLowerByRef( string& str )
21{
22        for( unsigned int i = 0; i < str.length(); i++ )
23        {
24                str[i] = dns_tolower( str[i] );
25        }
26
27        return str;
28}
29
30
31
32OdbxBackend::OdbxBackend( const string& suffix )
33{
34        vector<string> hosts;
35
36
37        try
38        {
39                m_result = NULL;
40                m_handle[READ] = NULL;
41                m_handle[WRITE] = NULL;
42                m_myname = "[OpendbxBackend]";
43                m_default_ttl = arg().asNum( "default-ttl" );
44                m_qlog = arg().mustDo( "query-logging" );
45
46                setArgPrefix( "opendbx" + suffix );
47
48                if( getArg( "host" ).size() > 0 )
49                {
50                        L.log( m_myname + " WARNING: Using depricated opendbx-host parameter", Logger::Warning );
51                        stringtok( m_hosts[READ], getArg( "host" ), ", " );
52                        m_hosts[WRITE] = m_hosts[READ];
53                }
54                else
55                {
56                        stringtok( m_hosts[READ], getArg( "host-read" ), ", " );
57                        stringtok( m_hosts[WRITE], getArg( "host-write" ), ", " );
58                }
59
60                if( !connectTo( m_hosts[READ], READ ) ) { throw( AhuException( "Fatal: Connecting to server for reading failed" ) ); }
61                if( !connectTo( m_hosts[WRITE], WRITE ) ) { throw( AhuException( "Fatal: Connecting to server for writing failed" ) ); }
62        }
63        catch( exception& e )
64        {
65                L.log( m_myname + " OdbxBackend(): Caught STL exception - " + e.what(),  Logger::Error );
66                throw( AhuException( "Fatal: STL exception" ) );
67        }
68}
69
70
71
72OdbxBackend::~OdbxBackend()
73{
74        odbx_unbind( m_handle[WRITE] );
75        odbx_unbind( m_handle[READ] );
76
77        odbx_finish( m_handle[WRITE] );
78        odbx_finish( m_handle[READ] );
79}
80
81
82
83bool OdbxBackend::getDomainInfo( const string& domain, DomainInfo& di )
84{
85        const char* tmp;
86
87
88        try
89        {
90                DLOG( L.log( m_myname + " getDomainInfo()", Logger::Debug ) );
91
92                string stmt = getArg( "sql-zoneinfo" );
93                string& stmtref = strbind( ":name", escape( toLower( domain ), READ ), stmt );
94
95                if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
96                if( !getRecord( READ ) ) { return false; }
97
98                do
99                {
100                        di.id = 0;
101                        di.zone = "";
102                        di.master = "";
103                        di.last_check = 0;
104                        di.notified_serial = 0;
105                        di.kind = DomainInfo::Native;
106                        di.backend = this;
107                        di.serial = 0;
108
109                        if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
110                        {
111                                di.id = strtol( tmp, NULL, 10 );
112                        }
113
114                        if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
115                        {
116                                di.zone = string( tmp, odbx_field_length( m_result, 1 ) );
117                        }
118
119                        if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
120                        {
121                                if( !strncmp( tmp, "SLAVE", 5 ) )
122                                {
123                                        di.kind = DomainInfo::Slave;
124                                }
125                                else if( !strncmp( tmp, "MASTER", 6 ) )
126                                {
127                                        di.kind = DomainInfo::Master;
128                                }
129                        }
130
131                        if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
132                        {
133                                di.master = string( tmp, odbx_field_length( m_result, 3 ) );
134                        }
135
136                        if( ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
137                        {
138                                di.last_check = strtol( tmp, NULL, 10 );
139                        }
140
141                        if( ( tmp = odbx_field_value( m_result, 6 ) ) != NULL )
142                        {
143                                SOAData sd;
144
145                                sd.serial = 0;
146                                fillSOAData( string( tmp, odbx_field_length( m_result, 6 ) ), sd );
147                                di.serial = sd.serial;
148                        }
149                }
150                while( getRecord( READ ) );
151        }
152        catch( exception& e )
153        {
154                L.log( m_myname + " getDomainInfo: Caught STL exception - " + e.what(),  Logger::Error );
155                return false;
156        }
157
158        return true;
159}
160
161
162
163bool OdbxBackend::list( const string& target, int zoneid )
164{
165        try
166        {
167                DLOG( L.log( m_myname + " list()", Logger::Debug ) );
168
169                m_qname = "";
170                m_result = NULL;
171
172                size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
173
174                if( len < 0 )
175                {
176                        L.log( m_myname + " list: Unable to convert zone id to string - format error",  Logger::Error );
177                        return false;
178                }
179
180                if( len > sizeof( m_buffer ) - 1 )
181                {
182                        L.log( m_myname + " list: Unable to convert zone id to string - insufficient buffer space",  Logger::Error );
183                        return false;
184                }
185
186                string stmt = getArg( "sql-list" );
187                string& stmtref = strbind( ":id", string( m_buffer, len ), stmt );
188
189                if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
190        }
191        catch( exception& e )
192        {
193                L.log( m_myname + " list: Caught STL exception - " + e.what(),  Logger::Error );
194                return false;
195        }
196
197        return true;
198}
199
200
201
202void OdbxBackend::lookup( const QType& qtype, const string& qname, DNSPacket* dnspkt, int zoneid )
203{
204        try
205        {
206                DLOG( L.log( m_myname + " lookup()", Logger::Debug ) );
207
208                string stmt;
209                string& stmtref = stmt;
210
211                m_result = NULL;
212                m_qname = qname;
213               
214                if( zoneid < 0 )
215                {
216                        if( qtype.getCode() == QType::ANY )
217                        {
218                                stmt = getArg( "sql-lookup" );
219                        } else {
220                                stmt = getArg( "sql-lookuptype" );
221                                stmtref = strbind( ":type", qtype.getName(), stmt );
222                        }
223                }
224                else
225                {
226                        if( qtype.getCode() == QType::ANY )
227                        {
228                                stmt = getArg( "sql-lookupid" );
229                        } else {
230                                stmt = getArg( "sql-lookuptypeid" );
231                                stmtref = strbind( ":type", qtype.getName(), stmt );
232                        }
233                       
234                        size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
235
236                        if( len < 0 )
237                        {
238                                L.log( m_myname + " lookup: Unable to convert zone id to string - format error",  Logger::Error );
239                                throw( DBException( "Error: Libc error" ) );
240                        }
241
242                        if( len > sizeof( m_buffer ) - 1 )
243                        {
244                                L.log( m_myname + " lookup: Unable to convert zone id to string - insufficient buffer space",  Logger::Error );
245                                throw( DBException( "Error: Libc error" ) );
246                }
247
248                        stmtref = strbind( ":id", string( m_buffer, len ), stmtref );
249                }
250
251                string tmp = qname;
252                stmtref = strbind( ":name", escape( toLowerByRef( tmp ), READ ), stmtref );
253
254                if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) )
255                {
256                        throw( DBException( "Error: DB statement failed" ) );
257                }
258        }
259        catch( exception& e )
260        {
261                L.log( m_myname + " lookup: Caught STL exception - " + e.what(),  Logger::Error );
262                throw( DBException( "Error: STL exception" ) );
263        }
264}
265
266
267
268bool OdbxBackend::get( DNSResourceRecord& rr )
269{
270        const char* tmp;
271
272
273        try
274        {
275                DLOG( L.log( m_myname + " get()", Logger::Debug ) );
276
277                if( getRecord( READ ) )
278                {
279                        rr.content = "";
280                        rr.priority = 0;
281                        rr.domain_id = 0;
282                        rr.last_modified = 0;
283                        rr.ttl = m_default_ttl;
284                        rr.qname = m_qname;
285
286                        if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
287                        {
288                                rr.domain_id = strtol( tmp, NULL, 10 );
289                        }
290
291                        if( m_qname.empty() && ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
292                        {
293                                rr.qname = string( tmp, odbx_field_length( m_result, 1 ) );
294                        }
295
296                        if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
297                        {
298                                rr.qtype = QType( tmp );
299                        }
300
301                        if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
302                        {
303                                rr.ttl = strtoul( tmp, NULL, 10 );
304                        }
305
306                        if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
307                        {
308                                rr.priority = (u_int16_t) strtoul( tmp, NULL, 10 );
309                        }
310
311                        if( ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
312                        {
313                                rr.content = string( tmp, odbx_field_length( m_result, 5 ) );
314                        }
315
316                        return true;
317                }
318        }
319        catch( exception& e )
320        {
321                L.log( m_myname + " get: Caught STL exception - " + e.what(),  Logger::Error );
322                return false;
323        }
324
325        return false;
326}
327
328
329void OdbxBackend::setFresh( u_int32_t domain_id )
330{
331        size_t len;
332
333
334        try
335        {
336                DLOG( L.log( m_myname + " setFresh()", Logger::Debug ) );
337
338                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
339                {
340                        L.log( m_myname + " setFresh: Master server is unreachable",  Logger::Error );
341                        throw( DBException( "Error: Server unreachable" ) );
342                }
343
344                len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-update-lastcheck" ).c_str(), time( 0 ), domain_id );
345
346                if( len < 0 )
347                {
348                        L.log( m_myname + " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "' - format error",  Logger::Error );
349                        throw( DBException( "Error: Libc error" ) );
350                }
351
352                if( len > sizeof( m_buffer ) - 1 )
353                {
354                        L.log( m_myname + " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "' - insufficient buffer space",  Logger::Error );
355                        throw( DBException( "Error: Libc error" ) );
356                }
357
358                if( !execStmt( m_buffer, len, WRITE ) )
359                {
360                        throw( DBException( "Error: DB statement failed" ) );
361                }
362        }
363        catch ( exception& e )
364        {
365                L.log( m_myname + " setFresh: Caught STL exception - " + e.what(),  Logger::Error );
366                throw( DBException( "Error: STL exception" ) );
367        }
368}
369
370
371
372void OdbxBackend::setNotified( u_int32_t domain_id, u_int32_t serial )
373{
374        try
375        {
376                DLOG( L.log( m_myname + " setNotified()", Logger::Debug ) );
377
378                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
379                {
380                        L.log( m_myname + " setFresh: Master server is unreachable",  Logger::Error );
381                        throw( DBException( "Error: Server unreachable" ) );
382                }
383
384                size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-update-serial" ).c_str(), serial, domain_id );
385
386                if( len < 0 )
387                {
388                        L.log( m_myname + " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "' - format error",  Logger::Error );
389                        throw( DBException( "Error: Libc error" ) );
390                }
391
392                if( len > sizeof( m_buffer ) - 1 )
393                {
394                        L.log( m_myname + " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "' - insufficient buffer space",  Logger::Error );
395                        throw( DBException( "Error: Libc error" ) );
396                }
397
398                if( !execStmt( m_buffer, len, WRITE ) )
399                {
400                        throw( DBException( "Error: DB statement failed" ) );
401                }
402        }
403        catch ( exception& e )
404        {
405                L.log( m_myname + " setNotified: Caught STL exception - " + e.what(),  Logger::Error );
406                throw( DBException( "Error: STL exception" ) );
407        }
408}
409
410
411
412bool OdbxBackend::isMaster( const string& domain, const string& ip )
413{
414        try
415        {
416                DLOG( L.log( m_myname + " isMaster()", Logger::Debug ) );
417
418                string stmt = getArg( "sql-master" );
419                string& stmtref = strbind( ":name", escape( toLower( domain ), READ ), stmt );
420
421                if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
422                if( !getRecord( READ ) ) { return false; }
423
424                do
425                {
426                        if( odbx_field_value( m_result, 0 ) != NULL )
427                        {
428                                if( !strcmp( odbx_field_value( m_result, 0 ), ip.c_str() ) )
429                                {
430                                        while( getRecord( READ ) );
431                                        return true;
432                                }
433                        }
434                }
435                while( getRecord( READ ) );
436        }
437        catch ( exception& e )
438        {
439                L.log( m_myname + " isMaster: Caught STL exception - " + e.what(),  Logger::Error );
440                return false;
441        }
442
443        return false;
444}
445
446
447
448void OdbxBackend::getUnfreshSlaveInfos( vector<DomainInfo>* unfresh )
449{
450        try
451        {
452                DLOG( L.log( m_myname + " getUnfreshSlaveInfos()", Logger::Debug ) );
453
454                if( unfresh == NULL )
455                {
456                        L.log( m_myname + " getUnfreshSlaveInfos: invalid parameter - NULL pointer",  Logger::Error );
457                        return;
458                }
459
460                getDomainList( getArg( "sql-infoslaves" ), unfresh, &checkSlave );
461        }
462        catch ( exception& e )
463        {
464                L.log( m_myname + " getUnfreshSlaveInfo: Caught STL exception - " + e.what(),  Logger::Error );
465        }
466}
467
468
469
470void OdbxBackend::getUpdatedMasters( vector<DomainInfo>* updated )
471{
472        try
473        {
474                DLOG( L.log( m_myname + " getUpdatedMasters()", Logger::Debug ) );
475
476                if( updated == NULL )
477                {
478                        L.log( m_myname + " getUpdatedMasters: invalid parameter - NULL pointer",  Logger::Error );
479                        return;
480                }
481
482                getDomainList( getArg( "sql-infomasters" ), updated, &checkMaster );
483        }
484        catch ( exception& e )
485        {
486                L.log( m_myname + " getUpdatedMasters: Caught STL exception - " + e.what(),  Logger::Error );
487        }
488}
489
490
491
492bool OdbxBackend::superMasterBackend( const string& ip, const string& domain, const vector<DNSResourceRecord>& set, string* account, DNSBackend** ddb )
493{
494        try
495        {
496                DLOG( L.log( m_myname + " superMasterBackend()", Logger::Debug ) );
497
498                if( account != NULL && ddb != NULL )
499                {
500                        vector<DNSResourceRecord>::const_iterator i;
501
502                        for( i = set.begin(); i != set.end(); i++ )
503                        {
504                                string stmt = getArg( "sql-supermaster" );
505                                string& stmtref = strbind( ":ip", escape( ip, READ ), stmt );
506                                stmtref = strbind( ":ns", escape( i->content, READ ), stmtref );
507
508                                if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
509
510                                if( getRecord( READ ) )
511                                {
512                                        if( odbx_field_value( m_result, 0 ) != NULL )
513                                        {
514                                                *account = string( odbx_field_value( m_result, 0 ), odbx_field_length( m_result, 0 ) );
515                                        }
516
517                                        while( getRecord( READ ) );
518
519                                *ddb=this;
520                                return true;
521                        }
522                }
523        }
524        }
525        catch ( exception& e )
526        {
527                L.log( m_myname + " superMasterBackend: Caught STL exception - " + e.what(),  Logger::Error );
528                return false;
529        }
530
531        return false;
532}
533
534
535
536bool OdbxBackend::createSlaveDomain( const string& ip, const string& domain, const string& account )
537{
538        try
539        {
540                DLOG( L.log( m_myname + " createSlaveDomain()", Logger::Debug ) );
541
542                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
543                {
544                        L.log( m_myname + " createSlaveDomain: Master server is unreachable",  Logger::Error );
545                        return false;
546                }
547
548                string tmp = domain;
549                size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-insert-slave" ).c_str(), escape( toLowerByRef( tmp ), WRITE ).c_str(),
550                        escape( ip, WRITE ).c_str(), escape( account, WRITE ).c_str() );
551
552                if( len < 0 )
553                {
554                        L.log( m_myname + " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "' - format error",  Logger::Error );
555                        return false;
556                }
557
558                if( len > sizeof( m_buffer ) - 1 )
559                {
560                        L.log( m_myname + " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "' - insufficient buffer space",  Logger::Error );
561                        return false;
562                }
563
564                if( !execStmt( m_buffer, len, WRITE ) ) { return false; }
565        }
566        catch ( exception& e )
567        {
568                L.log( m_myname + " createSlaveDomain: Caught STL exception - " + e.what(),  Logger::Error );
569                return false;
570        }
571
572        return true;
573}
574
575
576
577bool OdbxBackend::feedRecord( const DNSResourceRecord& rr )
578{
579        try
580        {
581                DLOG( L.log( m_myname + " feedRecord()", Logger::Debug ) );
582
583                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
584                {
585                        L.log( m_myname + " feedRecord: Master server is unreachable",  Logger::Error );
586                        return false;
587                }
588
589                string tmp = rr.qname;
590                size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-insert-record" ).c_str(), rr.domain_id,
591                        escape( toLowerByRef( tmp ), WRITE ).c_str(), rr.qtype.getName().c_str(), rr.ttl, rr.priority,
592                        escape( rr.content, WRITE ).c_str() );
593
594                if( len < 0 )
595                {
596                        L.log( m_myname + " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "' - format error",  Logger::Error );
597                        return false;
598                }
599
600                if( len > sizeof( m_buffer ) - 1 )
601                {
602                        L.log( m_myname + " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "' - insufficient buffer space",  Logger::Error );
603                        return false;
604                }
605
606                if( !execStmt( m_buffer, len, WRITE ) ) { return false; }
607        }
608        catch ( exception& e )
609        {
610                L.log( m_myname + " feedRecord: Caught STL exception - " + e.what(),  Logger::Error );
611                return false;
612        }
613
614        return true;
615}
616
617
618
619bool OdbxBackend::startTransaction( const string& domain, int zoneid )
620{
621        try
622        {
623                DLOG( L.log( m_myname + " startTransaction()", Logger::Debug ) );
624
625                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
626                {
627                        L.log( m_myname + " startTransaction: Master server is unreachable",  Logger::Error );
628                        return false;
629                }
630
631                string& stmtref = const_cast<string&>( getArg( "sql-transactbegin" ) );
632                if( !execStmt( stmtref.c_str(), stmtref.size(), WRITE ) ) { return false; }
633
634                size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
635
636                if( len < 0 )
637                {
638                        L.log( m_myname + " startTransaction: Unable to convert zone id to string - format error",  Logger::Error );
639                        return false;
640                }
641
642                if( len > sizeof( m_buffer ) - 1 )
643                {
644                        L.log( m_myname + " startTransaction: Unable to convert zone id to string - insufficient buffer space",  Logger::Error );
645                        return false;
646                }
647
648                string stmt = getArg( "sql-zonedelete" );
649                stmtref = strbind( ":id", string( m_buffer, len ), stmt );
650                if( !execStmt( stmtref.c_str(), stmtref.size(), WRITE ) ) { return false; }
651        }
652        catch ( exception& e )
653        {
654                L.log( m_myname + " startTransaction: Caught STL exception - " + e.what(),  Logger::Error );
655                return false;
656        }
657
658        return true;
659}
660
661
662
663bool OdbxBackend::commitTransaction()
664{
665        try
666        {
667                DLOG( L.log( m_myname + " commitTransaction()", Logger::Debug ) );
668
669                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
670                {
671                        L.log( m_myname + " commitTransaction: Master server is unreachable",  Logger::Error );
672                        return false;
673                }
674
675                const string& stmt = getArg( "sql-transactend" );
676                if( !execStmt( stmt.c_str(), stmt.size(), WRITE ) ) { return false; }
677        }
678        catch ( exception& e )
679        {
680                L.log( m_myname + " commitTransaction: Caught STL exception - " + e.what(),  Logger::Error );
681                return false;
682        }
683
684        return true;
685}
686
687
688
689bool OdbxBackend::abortTransaction()
690{
691        try
692        {
693                DLOG( L.log( m_myname + " abortTransaction()", Logger::Debug ) );
694
695                if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
696                {
697                        L.log( m_myname + " abortTransaction: Master server is unreachable",  Logger::Error );
698                        return false;
699                }
700
701                const string& stmt = getArg( "sql-transactabort" );
702                if( !execStmt( stmt.c_str(), stmt.size(), WRITE ) ) { return false; }
703        }
704        catch ( exception& e )
705        {
706                L.log( m_myname + " abortTransaction: Caught STL exception - " + e.what(),  Logger::Error );
707                return false;
708        }
709
710        return true;
711}
Note: See TracBrowser for help on using the browser.