]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/ixfrutils.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "ixfrutils.hh"
28 #include "dnssecinfra.hh"
29 #include "zoneparser-tng.hh"
30 #include "dnsparser.hh"
32 uint32_t getSerialFromMaster ( const ComboAddress
& master
, const DNSName
& zone
, shared_ptr
< SOARecordContent
>& sr
, const TSIGTriplet
& tt
, const uint16_t timeout
)
34 vector
< uint8_t > packet
;
35 DNSPacketWriter
pw ( packet
, zone
, QType :: SOA
);
36 if (! tt
. algo
. empty ()) {
37 TSIGRecordContent trc
;
38 trc
. d_algoName
= tt
. algo
;
39 trc
. d_time
= time ( nullptr );
41 trc
. d_origID
= ntohs ( pw
. getHeader ()-> id
);
43 addTSIG ( pw
, trc
, tt
. name
, tt
. secret
, "" , false );
46 Socket
s ( master
. sin4
. sin_family
, SOCK_DGRAM
);
48 string
msg (( const char *)& packet
[ 0 ], packet
. size ());
53 // will throw a NetworkError on timeout
54 ssize_t got
= s
. readWithTimeout (& reply
[ 0 ], reply
. size (), timeout
);
55 if ( got
< 0 || static_cast < size_t >( got
) < sizeof ( dnsheader
)) {
56 throw std :: runtime_error ( "Invalid response size " + std :: to_string ( got
));
61 MOADNSParser
mdp ( false , reply
);
62 if ( mdp
. d_header
. rcode
) {
63 throw std :: runtime_error ( "RCODE from response is not NoError but " + RCode :: to_s ( mdp
. d_header
. rcode
));
65 for ( const auto & r
: mdp
. d_answers
) {
66 if ( r
. first
. d_type
== QType :: SOA
) {
67 sr
= getRR
< SOARecordContent
>( r
. first
);
69 return sr
-> d_st
. serial
;
76 uint32_t getSerialsFromDir ( const std :: string
& dir
)
79 DIR * dirhdl
= opendir ( dir
. c_str ());
81 throw runtime_error ( "Could not open IXFR directory '" + dir
+ "': " + strerror ( errno
));
84 while (( entry
= readdir ( dirhdl
))) {
85 uint32_t num
= atoi ( entry
-> d_name
);
86 if ( std :: to_string ( num
) == entry
-> d_name
)
93 uint32_t getSerialFromRecords ( const records_t
& records
, DNSRecord
& soaret
)
96 uint16_t t
= QType :: SOA
;
98 auto found
= records
. equal_range ( tie ( root
, t
));
100 for ( auto iter
= found
. first
; iter
!= found
. second
; ++ iter
) {
101 auto soa
= std :: dynamic_pointer_cast
< SOARecordContent
>( iter
-> d_content
);
104 return soa
-> d_st
. serial
;
110 static void writeRecords ( FILE * fp
, const records_t
& records
)
112 for ( const auto & r
: records
) {
113 fprintf ( fp
, "%s \t %" PRIu32
" \t IN \t %s \t %s \n " ,
114 r
. d_name
. isRoot () ? "@" : r
. d_name
. toStringNoDot (). c_str (),
116 DNSRecordContent :: NumberToType ( r
. d_type
). c_str (),
117 r
. d_content
-> getZoneRepresentation (). c_str ());
121 void writeZoneToDisk ( const records_t
& records
, const DNSName
& zone
, const std :: string
& directory
)
124 auto serial
= getSerialFromRecords ( records
, soa
);
125 string fname
= directory
+ "/" + std :: to_string ( serial
);
126 FILE * fp
= fopen (( fname
+ ".partial" ). c_str (), "w" );
128 throw runtime_error ( "Unable to open file '" + fname
+ ".partial' for writing: " + string ( strerror ( errno
)));
131 soarecord
. insert ( soa
);
132 fprintf ( fp
, "$ORIGIN %s \n " , zone
. toString (). c_str ());
134 writeRecords ( fp
, soarecord
);
135 writeRecords ( fp
, records
);
136 writeRecords ( fp
, soarecord
);
139 if ( rename ( ( fname
+ ".partial" ). c_str (), fname
. c_str ()) != 0 ) {
140 throw std :: runtime_error ( "Unable to move the zone file for " + zone
. toLogString () + " from " + fname
+ ".partial to " + fname
+ ": " + string ( strerror ( errno
)));
144 void loadZoneFromDisk ( records_t
& records
, const string
& fname
, const DNSName
& zone
)
146 ZoneParserTNG
zpt ( fname
, zone
);
148 DNSResourceRecord rr
;
151 if ( rr
. qtype
. getCode () == QType :: CNAME
&& rr
. content
. empty ())
153 rr
. qname
= rr
. qname
. makeRelative ( zone
);
155 if ( rr
. qtype
. getCode () != QType :: SOA
|| seenSOA
== false )
156 records
. insert ( DNSRecord ( rr
));
157 if ( rr
. qtype
. getCode () == QType :: SOA
) {
161 if (!( rr
. qtype
. getCode () == QType :: SOA
&& seenSOA
)) {
163 throw runtime_error ( "Zone not complete!" );
168 * Load the zone `zone` from `fname` and put the first found SOA into `soa`
169 * Does NOT check for nullptr
171 void loadSOAFromDisk ( const DNSName
& zone
, const string
& fname
, shared_ptr
< SOARecordContent
>& soa
, uint32_t & soaTTL
)
173 ZoneParserTNG
zpt ( fname
, zone
);
174 DNSResourceRecord rr
;
177 if ( rr
. qtype
== QType :: SOA
) {
178 soa
= getRR
< SOARecordContent
>( DNSRecord ( rr
));