]>
Commit | Line | Data |
---|---|---|
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 | ||
23 | #include <dirent.h> | |
24 | #include "ixfrutils.hh" | |
25 | #include "sstuff.hh" | |
26 | #include "dnssecinfra.hh" | |
27 | #include "zoneparser-tng.hh" | |
28 | ||
29 | uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const TSIGTriplet& tt) | |
30 | { | |
31 | vector<uint8_t> packet; | |
32 | DNSPacketWriter pw(packet, zone, QType::SOA); | |
33 | if(!tt.algo.empty()) { | |
34 | TSIGRecordContent trc; | |
35 | trc.d_algoName = tt.algo; | |
36 | trc.d_time = time(nullptr); | |
37 | trc.d_fudge = 300; | |
38 | trc.d_origID=ntohs(pw.getHeader()->id); | |
39 | trc.d_eRcode=0; | |
40 | addTSIG(pw, trc, tt.name, tt.secret, "", false); | |
41 | } | |
42 | ||
43 | Socket s(master.sin4.sin_family, SOCK_DGRAM); | |
44 | s.connect(master); | |
45 | string msg((const char*)&packet[0], packet.size()); | |
46 | s.writen(msg); | |
47 | ||
48 | string reply; | |
49 | s.read(reply); | |
50 | MOADNSParser mdp(false, reply); | |
51 | if(mdp.d_header.rcode) { | |
52 | throw std::runtime_error("Unable to retrieve SOA serial from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode)); | |
53 | } | |
54 | for(const auto& r: mdp.d_answers) { | |
55 | if(r.first.d_type == QType::SOA) { | |
56 | sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content); | |
57 | return sr->d_st.serial; | |
58 | } | |
59 | } | |
60 | return 0; | |
61 | } | |
62 | ||
63 | uint32_t getSerialsFromDir(const std::string& dir) | |
64 | { | |
65 | uint32_t ret=0; | |
66 | DIR* dirhdl=opendir(dir.c_str()); | |
67 | if(!dirhdl) | |
68 | throw runtime_error("Could not open IXFR directory"); | |
69 | struct dirent *entry; | |
70 | ||
71 | while((entry = readdir(dirhdl))) { | |
72 | uint32_t num = atoi(entry->d_name); | |
73 | if(std::to_string(num) == entry->d_name) | |
74 | ret = max(num, ret); | |
75 | } | |
76 | closedir(dirhdl); | |
77 | return ret; | |
78 | } | |
79 | ||
80 | uint32_t getSerialFromRecords(const records_t& records, DNSRecord& soaret) | |
81 | { | |
82 | DNSName root("."); | |
83 | uint16_t t=QType::SOA; | |
84 | ||
85 | auto found = records.equal_range(tie(root, t)); | |
86 | ||
87 | for(auto iter = found.first; iter != found.second; ++iter) { | |
88 | auto soa = std::dynamic_pointer_cast<SOARecordContent>(iter->d_content); | |
89 | soaret = *iter; | |
90 | return soa->d_st.serial; | |
91 | } | |
92 | return 0; | |
93 | } | |
94 | ||
95 | void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::string& directory) | |
96 | { | |
97 | DNSRecord soa; | |
98 | int serial = getSerialFromRecords(records, soa); | |
99 | string fname=directory +"/"+std::to_string(serial); | |
100 | FILE* fp=fopen((fname+".partial").c_str(), "w"); | |
101 | if(!fp) | |
102 | throw runtime_error("Unable to open file '"+fname+".partial' for writing: "+string(strerror(errno))); | |
103 | ||
104 | records_t soarecord; | |
105 | soarecord.insert(soa); | |
106 | fprintf(fp, "$ORIGIN %s\n", zone.toString().c_str()); | |
107 | for(const auto& outer : {soarecord, records, soarecord} ) { | |
108 | for(const auto& r: outer) { | |
109 | fprintf(fp, "%s\tIN\t%s\t%s\n", | |
110 | r.d_name.isRoot() ? "@" : r.d_name.toStringNoDot().c_str(), | |
111 | DNSRecordContent::NumberToType(r.d_type).c_str(), | |
112 | r.d_content->getZoneRepresentation().c_str()); | |
113 | } | |
114 | } | |
115 | fclose(fp); | |
116 | rename( (fname+".partial").c_str(), fname.c_str()); | |
117 | } | |
118 | ||
119 | void loadZoneFromDisk(records_t& records, const string& fname, const DNSName& zone) | |
120 | { | |
121 | ZoneParserTNG zpt(fname, zone); | |
122 | ||
123 | DNSResourceRecord rr; | |
124 | bool seenSOA=false; | |
125 | unsigned int nrecords=0; | |
126 | while(zpt.get(rr)) { | |
127 | ++nrecords; | |
128 | if(rr.qtype.getCode() == QType::CNAME && rr.content.empty()) | |
129 | rr.content="."; | |
130 | rr.qname = rr.qname.makeRelative(zone); | |
131 | ||
132 | if(rr.qtype.getCode() != QType::SOA || seenSOA==false) | |
133 | records.insert(DNSRecord(rr)); | |
134 | if(rr.qtype.getCode() == QType::SOA) { | |
135 | seenSOA=true; | |
136 | } | |
137 | } | |
138 | cout<<"Parsed "<<nrecords<<" records"<<endl; | |
139 | if(rr.qtype.getCode() == QType::SOA && seenSOA) { | |
140 | cout<<"Zone was complete (SOA at end)"<<endl; | |
141 | } | |
142 | else { | |
143 | records.clear(); | |
144 | throw runtime_error("Zone not complete!"); | |
145 | } | |
146 | } |