]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ixfrutils.cc
rec: ensure correct service user on debian
[thirdparty/pdns.git] / pdns / ixfrutils.cc
CommitLineData
4db8fd44
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
22
95453d17 23#include <cinttypes>
4db8fd44 24#include <dirent.h>
38e6a9ee 25#include <errno.h>
4db8fd44
PL
26#include "ixfrutils.hh"
27#include "sstuff.hh"
28#include "dnssecinfra.hh"
29#include "zoneparser-tng.hh"
38e6a9ee 30#include "dnsparser.hh"
4db8fd44 31
2dfb13fe 32uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const TSIGTriplet& tt, const uint16_t timeout)
4db8fd44
PL
33{
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);
40 trc.d_fudge = 300;
41 trc.d_origID=ntohs(pw.getHeader()->id);
42 trc.d_eRcode=0;
43 addTSIG(pw, trc, tt.name, tt.secret, "", false);
44 }
45
46 Socket s(master.sin4.sin_family, SOCK_DGRAM);
47 s.connect(master);
48 string msg((const char*)&packet[0], packet.size());
49 s.writen(msg);
50
51 string reply;
d605f9b1 52 reply.resize(4096);
2dfb13fe 53 // will throw a NetworkError on timeout
d605f9b1
RG
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));
57 }
58
59 reply.resize(got);
2dfb13fe 60
4db8fd44
PL
61 MOADNSParser mdp(false, reply);
62 if(mdp.d_header.rcode) {
2dfb13fe 63 throw std::runtime_error("RCODE from response is not NoError but " + RCode::to_s(mdp.d_header.rcode));
4db8fd44
PL
64 }
65 for(const auto& r: mdp.d_answers) {
66 if(r.first.d_type == QType::SOA) {
38e6a9ee
PL
67 sr = getRR<SOARecordContent>(r.first);
68 if(sr != nullptr) {
69 return sr->d_st.serial;
70 }
4db8fd44
PL
71 }
72 }
73 return 0;
74}
75
76uint32_t getSerialsFromDir(const std::string& dir)
77{
78 uint32_t ret=0;
79 DIR* dirhdl=opendir(dir.c_str());
80 if(!dirhdl)
38e6a9ee 81 throw runtime_error("Could not open IXFR directory '" + dir + "': " + strerror(errno));
4db8fd44
PL
82 struct dirent *entry;
83
84 while((entry = readdir(dirhdl))) {
85 uint32_t num = atoi(entry->d_name);
86 if(std::to_string(num) == entry->d_name)
87 ret = max(num, ret);
88 }
89 closedir(dirhdl);
90 return ret;
91}
92
93uint32_t getSerialFromRecords(const records_t& records, DNSRecord& soaret)
94{
95 DNSName root(".");
96 uint16_t t=QType::SOA;
97
98 auto found = records.equal_range(tie(root, t));
99
100 for(auto iter = found.first; iter != found.second; ++iter) {
101 auto soa = std::dynamic_pointer_cast<SOARecordContent>(iter->d_content);
9a72716f
RG
102 if (soa) {
103 soaret = *iter;
104 return soa->d_st.serial;
105 }
4db8fd44
PL
106 }
107 return 0;
108}
109
451605af
RG
110static void writeRecords(FILE* fp, const records_t& records)
111{
112 for(const auto& r: records) {
113 fprintf(fp, "%s\t%" PRIu32 "\tIN\t%s\t%s\n",
114 r.d_name.isRoot() ? "@" : r.d_name.toStringNoDot().c_str(),
115 r.d_ttl,
116 DNSRecordContent::NumberToType(r.d_type).c_str(),
117 r.d_content->getZoneRepresentation().c_str());
118 }
119}
120
4db8fd44
PL
121void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::string& directory)
122{
123 DNSRecord soa;
eb6e1106 124 auto serial = getSerialFromRecords(records, soa);
4db8fd44
PL
125 string fname=directory +"/"+std::to_string(serial);
126 FILE* fp=fopen((fname+".partial").c_str(), "w");
127 if(!fp)
128 throw runtime_error("Unable to open file '"+fname+".partial' for writing: "+string(strerror(errno)));
129
130 records_t soarecord;
131 soarecord.insert(soa);
132 fprintf(fp, "$ORIGIN %s\n", zone.toString().c_str());
451605af
RG
133
134 writeRecords(fp, soarecord);
135 writeRecords(fp, records);
136 writeRecords(fp, soarecord);
137
4db8fd44 138 fclose(fp);
c15074f0
RG
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)));
141 }
4db8fd44
PL
142}
143
144void loadZoneFromDisk(records_t& records, const string& fname, const DNSName& zone)
145{
146 ZoneParserTNG zpt(fname, zone);
147
148 DNSResourceRecord rr;
149 bool seenSOA=false;
4db8fd44 150 while(zpt.get(rr)) {
4db8fd44
PL
151 if(rr.qtype.getCode() == QType::CNAME && rr.content.empty())
152 rr.content=".";
153 rr.qname = rr.qname.makeRelative(zone);
154
155 if(rr.qtype.getCode() != QType::SOA || seenSOA==false)
156 records.insert(DNSRecord(rr));
157 if(rr.qtype.getCode() == QType::SOA) {
158 seenSOA=true;
159 }
160 }
f79adaa3 161 if(!(rr.qtype.getCode() == QType::SOA && seenSOA)) {
4db8fd44
PL
162 records.clear();
163 throw runtime_error("Zone not complete!");
164 }
165}
772cdea3
PL
166
167/*
168 * Load the zone `zone` from `fname` and put the first found SOA into `soa`
169 * Does NOT check for nullptr
170 */
d56c1443 171void loadSOAFromDisk(const DNSName& zone, const string& fname, shared_ptr<SOARecordContent>& soa, uint32_t& soaTTL)
772cdea3
PL
172{
173 ZoneParserTNG zpt(fname, zone);
174 DNSResourceRecord rr;
175
176 while(zpt.get(rr)) {
177 if (rr.qtype == QType::SOA) {
178 soa = getRR<SOARecordContent>(DNSRecord(rr));
d56c1443 179 soaTTL = rr.ttl;
772cdea3
PL
180 return;
181 }
182 }
183}