]>
git.ipfire.org Git - thirdparty/pdns.git/blob - modules/opendbxbackend/odbxbackend.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 * originally authored by Norbert Sendetzky
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
10 * In addition, for the avoidance of any doubt, permission is granted to
11 * link this program with OpenSSL and to (re)distribute the binaries
12 * produced as the result of such linking.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "odbxbackend.hh"
30 inline string
& strbind( const string
& search
, const string
& replace
, string
& subject
)
34 while( ( pos
= subject
.find( search
, pos
) ) != string::npos
)
36 subject
.replace( pos
, search
.size(), replace
);
37 pos
+= replace
.size();
45 OdbxBackend::OdbxBackend( const string
& suffix
)
53 m_handle
[READ
] = NULL
;
54 m_handle
[WRITE
] = NULL
;
55 m_myname
= "[OpendbxBackend]";
56 m_default_ttl
= arg().asNum( "default-ttl" );
57 m_qlog
= arg().mustDo( "query-logging" );
59 setArgPrefix( "opendbx" + suffix
);
61 if( getArg( "host" ).size() > 0 )
63 g_log
.log( m_myname
+ " WARNING: Using deprecated opendbx-host parameter", Logger::Warning
);
64 stringtok( m_hosts
[READ
], getArg( "host" ), ", " );
65 m_hosts
[WRITE
] = m_hosts
[READ
];
69 stringtok( m_hosts
[READ
], getArg( "host-read" ), ", " );
70 stringtok( m_hosts
[WRITE
], getArg( "host-write" ), ", " );
73 if( !connectTo( m_hosts
[READ
], READ
) ) { throw( PDNSException( "Fatal: Connecting to server for reading failed" ) ); }
74 if( !connectTo( m_hosts
[WRITE
], WRITE
) ) { throw( PDNSException( "Fatal: Connecting to server for writing failed" ) ); }
76 catch( std::exception
& e
)
78 g_log
.log( m_myname
+ " OdbxBackend(): Caught STL exception - " + e
.what(), Logger::Error
);
79 throw( PDNSException( "Fatal: STL exception" ) );
85 OdbxBackend::~OdbxBackend()
87 odbx_unbind( m_handle
[WRITE
] );
88 odbx_unbind( m_handle
[READ
] );
90 odbx_finish( m_handle
[WRITE
] );
91 odbx_finish( m_handle
[READ
] );
96 bool OdbxBackend::getDomainInfo( const DNSName
& domain
, DomainInfo
& di
, bool getSerial
)
103 DLOG( g_log
.log( m_myname
+ " getDomainInfo()", Logger::Debug
) );
105 string stmt
= getArg( "sql-zoneinfo" );
106 string
& stmtref
= strbind( ":name", escape( domain
.makeLowerCase().toStringRootDot(), READ
), stmt
);
108 if( !execStmt( stmtref
.c_str(), stmtref
.size(), READ
) ) { return false; }
109 if( !getRecord( READ
) ) { return false; }
117 di
.notified_serial
= 0;
118 di
.kind
= DomainInfo::Native
;
122 if( getSerial
&& ( tmp
= odbx_field_value( m_result
, 6 ) ) != NULL
)
127 fillSOAData( string( tmp
, odbx_field_length( m_result
, 6 ) ), sd
);
129 if( sd
.serial
== 0 && ( tmp
= odbx_field_value( m_result
, 5 ) ) != NULL
)
131 sd
.serial
= strtol( tmp
, NULL
, 10 );
134 di
.serial
= sd
.serial
;
137 if( ( tmp
= odbx_field_value( m_result
, 4 ) ) != NULL
)
139 di
.last_check
= strtol( tmp
, NULL
, 10 );
142 if( ( tmp
= odbx_field_value( m_result
, 3 ) ) != NULL
)
144 vector
<string
> masters
;
145 stringtok(masters
, string( tmp
, odbx_field_length( m_result
, 3 ) ), ", \t");
146 for(const auto& m
: masters
)
148 di
.masters
.emplace_back(m
, 53);
152 if( ( tmp
= odbx_field_value( m_result
, 2 ) ) != NULL
)
154 if( !strncmp( tmp
, "SLAVE", 5 ) )
156 di
.kind
= DomainInfo::Slave
;
158 else if( !strncmp( tmp
, "MASTER", 6 ) )
160 di
.kind
= DomainInfo::Master
;
164 if( ( tmp
= odbx_field_value( m_result
, 1 ) ) != NULL
)
166 di
.zone
= DNSName(string( tmp
, odbx_field_length( m_result
, 1 ) ));
169 if( ( tmp
= odbx_field_value( m_result
, 0 ) ) != NULL
)
171 di
.id
= strtol( tmp
, NULL
, 10 );
174 while( getRecord( READ
) );
176 catch( std::exception
& e
)
178 g_log
.log( m_myname
+ " getDomainInfo: Caught STL std::exception - " + e
.what(), Logger::Error
);
187 bool OdbxBackend::getSOA( const DNSName
& domain
, SOAData
& sd
, bool unmodifiedSerial
)
194 DLOG( g_log
.log( m_myname
+ " getSOA()", Logger::Debug
) );
196 string stmt
= getArg( "sql-lookupsoa" );
197 string
& stmtref
= strbind( ":name", escape( domain
.makeLowerCase().toStringRootDot(), READ
), stmt
);
199 if( !execStmt( stmtref
.c_str(), stmtref
.size(), READ
) ) { return false; }
200 if( !getRecord( READ
) ) { return false; }
206 sd
.ttl
= m_default_ttl
;
208 if( ( tmp
= odbx_field_value( m_result
, 3 ) ) != NULL
)
210 fillSOAData( string( tmp
, odbx_field_length( m_result
, 3 ) ), sd
);
213 if( ( tmp
= odbx_field_value( m_result
, 2 ) ) != NULL
)
215 sd
.ttl
= strtoul( tmp
, NULL
, 10 );
218 if( !unmodifiedSerial
&& sd
.serial
== 0 && ( tmp
= odbx_field_value( m_result
, 1 ) ) != NULL
)
220 sd
.serial
= strtol( tmp
, NULL
, 10 );
223 if( ( tmp
= odbx_field_value( m_result
, 0 ) ) != NULL
)
225 sd
.domain_id
= strtol( tmp
, NULL
, 10 );
228 if( sd
.nameserver
.empty() )
230 sd
.nameserver
= DNSName(arg()["default-soa-name"]);
233 if( sd
.hostmaster
.empty() )
235 sd
.hostmaster
= DNSName("hostmaster") + DNSName(domain
);
240 while( getRecord( READ
) );
242 catch( std::exception
& e
)
244 g_log
.log( m_myname
+ " getSOA: Caught STL exception - " + e
.what(), Logger::Error
);
253 bool OdbxBackend::list( const DNSName
& target
, int zoneid
, bool include_disabled
)
257 DLOG( g_log
.log( m_myname
+ " list()", Logger::Debug
) );
262 int len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, "%d", zoneid
);
266 g_log
.log( m_myname
+ " list: Unable to convert zone id to string - format error", Logger::Error
);
270 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
272 g_log
.log( m_myname
+ " list: Unable to convert zone id to string - insufficient buffer space", Logger::Error
);
276 string stmt
= getArg( "sql-list" );
277 string
& stmtref
= strbind( ":id", string( m_buffer
, len
), stmt
);
279 if( !execStmt( stmtref
.c_str(), stmtref
.size(), READ
) ) { return false; }
281 catch( std::exception
& e
)
283 g_log
.log( m_myname
+ " list: Caught STL exception - " + e
.what(), Logger::Error
);
292 void OdbxBackend::lookup( const QType
& qtype
, const DNSName
& qname
, DNSPacket
* dnspkt
, int zoneid
)
296 DLOG( g_log
.log( m_myname
+ " lookup()", Logger::Debug
) );
299 string
& stmtref
= stmt
;
306 if( qtype
.getCode() == QType::ANY
)
308 stmt
= getArg( "sql-lookup" );
310 stmt
= getArg( "sql-lookuptype" );
311 stmtref
= strbind( ":type", qtype
.getName(), stmt
);
316 if( qtype
.getCode() == QType::ANY
)
318 stmt
= getArg( "sql-lookupid" );
320 stmt
= getArg( "sql-lookuptypeid" );
321 stmtref
= strbind( ":type", qtype
.getName(), stmt
);
324 int len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, "%d", zoneid
);
328 g_log
.log( m_myname
+ " lookup: Unable to convert zone id to string - format error", Logger::Error
);
329 throw( DBException( "Error: Libc error" ) );
332 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
334 g_log
.log( m_myname
+ " lookup: Unable to convert zone id to string - insufficient buffer space", Logger::Error
);
335 throw( DBException( "Error: Libc error" ) );
338 stmtref
= strbind( ":id", string( m_buffer
, len
), stmtref
);
341 stmtref
= strbind( ":name", escape( qname
.makeLowerCase().toStringRootDot(), READ
), stmtref
);
343 if( !execStmt( stmtref
.c_str(), stmtref
.size(), READ
) )
345 throw( DBException( "Error: DB statement failed" ) );
348 catch( std::exception
& e
)
350 g_log
.log( m_myname
+ " lookup: Caught STL exception - " + e
.what(), Logger::Error
);
351 throw( DBException( "Error: STL exception" ) );
357 bool OdbxBackend::get( DNSResourceRecord
& rr
)
364 DLOG( g_log
.log( m_myname
+ " get()", Logger::Debug
) );
366 if( getRecord( READ
) )
371 rr
.last_modified
= 0;
372 rr
.ttl
= m_default_ttl
;
375 if( ( tmp
= odbx_field_value( m_result
, 0 ) ) != NULL
)
377 rr
.domain_id
= strtol( tmp
, NULL
, 10 );
380 if( m_qname
.empty() && ( tmp
= odbx_field_value( m_result
, 1 ) ) != NULL
)
382 rr
.qname
= DNSName( string(tmp
, odbx_field_length( m_result
, 1 ) ));
385 if( ( tmp
= odbx_field_value( m_result
, 2 ) ) != NULL
)
390 if( ( tmp
= odbx_field_value( m_result
, 3 ) ) != NULL
)
392 rr
.ttl
= strtoul( tmp
, NULL
, 10 );
395 if( ( tmp
= odbx_field_value( m_result
, 4 ) ) != NULL
)
397 priority
= string( tmp
, odbx_field_length( m_result
, 4 ) );
400 if( ( tmp
= odbx_field_value( m_result
, 5 ) ) != NULL
)
402 rr
.content
= string( tmp
, odbx_field_length( m_result
, 5 ) );
405 if (rr
.qtype
==QType::MX
|| rr
.qtype
==QType::SRV
)
406 rr
.content
= priority
+ " " + rr
.content
;
411 catch( std::exception
& e
)
413 g_log
.log( m_myname
+ " get: Caught STL exception - " + e
.what(), Logger::Error
);
421 void OdbxBackend::setFresh( uint32_t domain_id
)
428 DLOG( g_log
.log( m_myname
+ " setFresh()", Logger::Debug
) );
430 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
432 g_log
.log( m_myname
+ " setFresh: Master server is unreachable", Logger::Error
);
433 throw( DBException( "Error: Server unreachable" ) );
436 len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, getArg( "sql-update-lastcheck" ).c_str(), time( 0 ), domain_id
);
440 g_log
.log( m_myname
+ " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "' - format error", Logger::Error
);
441 throw( DBException( "Error: Libc error" ) );
444 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
446 g_log
.log( m_myname
+ " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "' - insufficient buffer space", Logger::Error
);
447 throw( DBException( "Error: Libc error" ) );
450 if( !execStmt( m_buffer
, len
, WRITE
) )
452 throw( DBException( "Error: DB statement failed" ) );
455 catch ( std::exception
& e
)
457 g_log
.log( m_myname
+ " setFresh: Caught STL exception - " + e
.what(), Logger::Error
);
458 throw( DBException( "Error: STL exception" ) );
464 void OdbxBackend::setNotified( uint32_t domain_id
, uint32_t serial
)
468 DLOG( g_log
.log( m_myname
+ " setNotified()", Logger::Debug
) );
470 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
472 g_log
.log( m_myname
+ " setFresh: Master server is unreachable", Logger::Error
);
473 throw( DBException( "Error: Server unreachable" ) );
476 int len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, getArg( "sql-update-serial" ).c_str(), serial
, domain_id
);
480 g_log
.log( m_myname
+ " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "' - format error", Logger::Error
);
481 throw( DBException( "Error: Libc error" ) );
484 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
486 g_log
.log( m_myname
+ " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "' - insufficient buffer space", Logger::Error
);
487 throw( DBException( "Error: Libc error" ) );
490 if( !execStmt( m_buffer
, len
, WRITE
) )
492 throw( DBException( "Error: DB statement failed" ) );
495 catch ( std::exception
& e
)
497 g_log
.log( m_myname
+ " setNotified: Caught STL exception - " + e
.what(), Logger::Error
);
498 throw( DBException( "Error: STL exception" ) );
504 void OdbxBackend::getUnfreshSlaveInfos( vector
<DomainInfo
>* unfresh
)
508 DLOG( g_log
.log( m_myname
+ " getUnfreshSlaveInfos()", Logger::Debug
) );
510 if( unfresh
== NULL
)
512 g_log
.log( m_myname
+ " getUnfreshSlaveInfos: invalid parameter - NULL pointer", Logger::Error
);
516 getDomainList( getArg( "sql-infoslaves" ), unfresh
, &checkSlave
);
518 catch ( std::exception
& e
)
520 g_log
.log( m_myname
+ " getUnfreshSlaveInfo: Caught STL exception - " + e
.what(), Logger::Error
);
526 void OdbxBackend::getUpdatedMasters( vector
<DomainInfo
>* updated
)
530 DLOG( g_log
.log( m_myname
+ " getUpdatedMasters()", Logger::Debug
) );
532 if( updated
== NULL
)
534 g_log
.log( m_myname
+ " getUpdatedMasters: invalid parameter - NULL pointer", Logger::Error
);
538 getDomainList( getArg( "sql-infomasters" ), updated
, &checkMaster
);
540 catch ( std::exception
& e
)
542 g_log
.log( m_myname
+ " getUpdatedMasters: Caught STL exception - " + e
.what(), Logger::Error
);
548 bool OdbxBackend::superMasterBackend( const string
& ip
, const DNSName
& domain
, const vector
<DNSResourceRecord
>& set
, string
*nameserver
, string
* account
, DNSBackend
** ddb
)
552 DLOG( g_log
.log( m_myname
+ " superMasterBackend()", Logger::Debug
) );
554 if( account
!= NULL
&& ddb
!= NULL
)
556 vector
<DNSResourceRecord
>::const_iterator i
;
558 for( i
= set
.begin(); i
!= set
.end(); i
++ )
560 string stmt
= getArg( "sql-supermaster" );
561 string
& stmtref
= strbind( ":ip", escape( ip
, READ
), stmt
);
562 stmtref
= strbind( ":ns", escape( i
->content
, READ
), stmtref
);
564 if( !execStmt( stmtref
.c_str(), stmtref
.size(), READ
) ) { return false; }
566 if( getRecord( READ
) )
568 if( odbx_field_value( m_result
, 0 ) != NULL
)
570 *account
= string( odbx_field_value( m_result
, 0 ), odbx_field_length( m_result
, 0 ) );
573 while( getRecord( READ
) );
581 catch ( std::exception
& e
)
583 g_log
.log( m_myname
+ " superMasterBackend: Caught STL exception - " + e
.what(), Logger::Error
);
592 bool OdbxBackend::createSlaveDomain( const string
& ip
, const DNSName
& domain
, const string
&nameserver
, const string
& account
)
596 DLOG( g_log
.log( m_myname
+ " createSlaveDomain()", Logger::Debug
) );
598 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
600 g_log
.log( m_myname
+ " createSlaveDomain: Master server is unreachable", Logger::Error
);
604 int len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, getArg( "sql-insert-slave" ).c_str(), escape( domain
.makeLowerCase().toStringRootDot(), WRITE
).c_str(),
605 escape( ip
, WRITE
).c_str(), escape( account
, WRITE
).c_str() );
609 g_log
.log( m_myname
+ " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "' - format error", Logger::Error
);
613 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
615 g_log
.log( m_myname
+ " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "' - insufficient buffer space", Logger::Error
);
619 if( !execStmt( m_buffer
, len
, WRITE
) ) { return false; }
621 catch ( std::exception
& e
)
623 g_log
.log( m_myname
+ " createSlaveDomain: Caught STL exception - " + e
.what(), Logger::Error
);
632 bool OdbxBackend::feedRecord( const DNSResourceRecord
& rr
, const DNSName
& ordername
)
636 DLOG( g_log
.log( m_myname
+ " feedRecord()", Logger::Debug
) );
638 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
640 g_log
.log( m_myname
+ " feedRecord: Master server is unreachable", Logger::Error
);
644 unsigned int priority
=0;
645 string
content(rr
.content
);
647 if(rr
.qtype
== QType::MX
|| rr
.qtype
== QType::SRV
) {
648 priority
=pdns_stou(content
);
649 string::size_type pos
= content
.find_first_not_of("0123456789");
650 if(pos
!= string::npos
)
651 boost::erase_head(content
, pos
);
655 int len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, getArg( "sql-insert-record" ).c_str(), rr
.domain_id
,
656 escape( rr
.qname
.makeLowerCase().toStringRootDot(), WRITE
).c_str(), rr
.qtype
.getName().c_str(), rr
.ttl
, priority
,
657 escape( content
, WRITE
).c_str() );
661 g_log
.log( m_myname
+ " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "' - format error", Logger::Error
);
665 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
667 g_log
.log( m_myname
+ " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "' - insufficient buffer space", Logger::Error
);
671 if( !execStmt( m_buffer
, len
, WRITE
) ) { return false; }
673 catch ( std::exception
& e
)
675 g_log
.log( m_myname
+ " feedRecord: Caught STL exception - " + e
.what(), Logger::Error
);
684 bool OdbxBackend::startTransaction( const DNSName
& domain
, int zoneid
)
688 DLOG( g_log
.log( m_myname
+ " startTransaction()", Logger::Debug
) );
690 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
692 g_log
.log( m_myname
+ " startTransaction: Master server is unreachable", Logger::Error
);
696 string stmtref
= getArg( "sql-transactbegin" );
697 if( !execStmt( stmtref
.c_str(), stmtref
.size(), WRITE
) ) { return false; }
698 int len
= snprintf( m_buffer
, sizeof( m_buffer
) - 1, "%d", zoneid
);
702 g_log
.log( m_myname
+ " startTransaction: Unable to convert zone id to string - format error", Logger::Error
);
706 if( len
> static_cast<int>(sizeof( m_buffer
)) - 1 )
708 g_log
.log( m_myname
+ " startTransaction: Unable to convert zone id to string - insufficient buffer space", Logger::Error
);
713 string stmt
= getArg( "sql-zonedelete" );
714 stmtref
= strbind( ":id", string( m_buffer
, len
), stmt
);
715 if( !execStmt( stmtref
.c_str(), stmtref
.size(), WRITE
) ) { return false; }
718 catch ( std::exception
& e
)
720 g_log
.log( m_myname
+ " startTransaction: Caught STL exception - " + e
.what(), Logger::Error
);
729 bool OdbxBackend::commitTransaction()
733 DLOG( g_log
.log( m_myname
+ " commitTransaction()", Logger::Debug
) );
735 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
737 g_log
.log( m_myname
+ " commitTransaction: Master server is unreachable", Logger::Error
);
741 const string
& stmt
= getArg( "sql-transactend" );
742 if( !execStmt( stmt
.c_str(), stmt
.size(), WRITE
) ) { return false; }
744 catch ( std::exception
& e
)
746 g_log
.log( m_myname
+ " commitTransaction: Caught STL exception - " + e
.what(), Logger::Error
);
755 bool OdbxBackend::abortTransaction()
759 DLOG( g_log
.log( m_myname
+ " abortTransaction()", Logger::Debug
) );
761 if( !m_handle
[WRITE
] && !connectTo( m_hosts
[WRITE
], WRITE
) )
763 g_log
.log( m_myname
+ " abortTransaction: Master server is unreachable", Logger::Error
);
767 const string
& stmt
= getArg( "sql-transactabort" );
768 if( !execStmt( stmt
.c_str(), stmt
.size(), WRITE
) ) { return false; }
770 catch ( std::exception
& e
)
772 g_log
.log( m_myname
+ " abortTransaction: Caught STL exception - " + e
.what(), Logger::Error
);