]>
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
);
103 return soa
->d_st
.serial
;
108 static void writeRecords(FILE* fp
, const records_t
& records
)
110 for(const auto& r
: records
) {
111 fprintf(fp
, "%s\t%" PRIu32
"\tIN\t%s\t%s\n",
112 r
.d_name
.isRoot() ? "@" : r
.d_name
.toStringNoDot().c_str(),
114 DNSRecordContent::NumberToType(r
.d_type
).c_str(),
115 r
.d_content
->getZoneRepresentation().c_str());
119 void writeZoneToDisk(const records_t
& records
, const DNSName
& zone
, const std::string
& directory
)
122 auto serial
= getSerialFromRecords(records
, soa
);
123 string fname
=directory
+"/"+std::to_string(serial
);
124 FILE* fp
=fopen((fname
+".partial").c_str(), "w");
126 throw runtime_error("Unable to open file '"+fname
+".partial' for writing: "+string(strerror(errno
)));
129 soarecord
.insert(soa
);
130 fprintf(fp
, "$ORIGIN %s\n", zone
.toString().c_str());
132 writeRecords(fp
, soarecord
);
133 writeRecords(fp
, records
);
134 writeRecords(fp
, soarecord
);
137 rename( (fname
+".partial").c_str(), fname
.c_str());
140 void loadZoneFromDisk(records_t
& records
, const string
& fname
, const DNSName
& zone
)
142 ZoneParserTNG
zpt(fname
, zone
);
144 DNSResourceRecord rr
;
146 unsigned int nrecords
=0;
149 if(rr
.qtype
.getCode() == QType::CNAME
&& rr
.content
.empty())
151 rr
.qname
= rr
.qname
.makeRelative(zone
);
153 if(rr
.qtype
.getCode() != QType::SOA
|| seenSOA
==false)
154 records
.insert(DNSRecord(rr
));
155 if(rr
.qtype
.getCode() == QType::SOA
) {
159 if(!(rr
.qtype
.getCode() == QType::SOA
&& seenSOA
)) {
161 throw runtime_error("Zone not complete!");
166 * Load the zone `zone` from `fname` and put the first found SOA into `soa`
167 * Does NOT check for nullptr
169 void loadSOAFromDisk(const DNSName
& zone
, const string
& fname
, shared_ptr
<SOARecordContent
>& soa
)
171 ZoneParserTNG
zpt(fname
, zone
);
172 DNSResourceRecord rr
;
175 if (rr
.qtype
== QType::SOA
) {
176 soa
= getRR
<SOARecordContent
>(DNSRecord(rr
));