]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/saxfr.cc
pkcs11signers: Use emplace_back for attributes
[thirdparty/pdns.git] / pdns / saxfr.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "base64.hh"
5 #include "dnsparser.hh"
6 #include "sstuff.hh"
7 #include "misc.hh"
8 #include "dnswriter.hh"
9 #include "dnsrecords.hh"
10 #include "statbag.hh"
11 #include "base32.hh"
12 #include "dnssecinfra.hh"
13
14 #include "dns_random.hh"
15 #include "gss_context.hh"
16
17 StatBag S;
18
19 int main(int argc, char** argv)
20 try
21 {
22 if(argc < 4) {
23 cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [gss:remote-principal] [tsig:keyname:algo:secret]"<<endl;
24 exit(EXIT_FAILURE);
25 }
26
27 bool showdetails=false;
28 bool showflags=false;
29 bool unhash=false;
30 bool gss=false;
31 bool tsig=false;
32 TSIGHashEnum tsig_algo;
33 DNSName tsig_key;
34 string tsig_secret;
35 string tsigprevious;
36 string remote_principal;
37
38 if (argc > 4) {
39 for(int i=4; i<argc; i++) {
40 if (strcmp(argv[i], "showdetails") == 0)
41 showdetails=true;
42 if (strcmp(argv[i], "showflags") == 0)
43 showflags=true;
44 if (strcmp(argv[i], "unhash") == 0)
45 unhash=true;
46 if (strncmp(argv[i], "gss:",4) == 0) {
47 gss=true;
48 tsig=true;
49 tsig_algo=TSIG_GSS;
50 remote_principal = string(argv[i]+4);
51 if (remote_principal.empty()) {
52 cerr<<"Remote principal is required"<<endl;
53 exit(EXIT_FAILURE);
54 }
55 }
56 if (strncmp(argv[i], "tsig:",5) == 0) {
57 vector<string> parts;
58 tsig=true;
59 stringtok(parts, argv[i], ":");
60 if (parts.size()!=4) {
61 cerr<<"Invalid syntax for tsig"<<endl;
62 exit(EXIT_FAILURE);
63 }
64 if (!getTSIGHashEnum(DNSName(parts[2]), tsig_algo)) {
65 cerr<<"Cannot understand TSIG algorithm '"<<parts[1]<<"'"<<endl;
66 exit(EXIT_FAILURE);
67 }
68 tsig_key = DNSName(parts[1]);
69 if (tsig_key == DNSName()) {
70 cerr<<"Key name must be set for tsig"<<endl;
71 exit(EXIT_FAILURE);
72 }
73 if (B64Decode(parts[3], tsig_secret)) {
74 cerr<<"Secret must be base64 encoded"<<endl;
75 exit(EXIT_FAILURE);
76 }
77 if (tsig_secret.size()==0) {
78 cerr<<"Secret must be set for tsig"<<endl;
79 exit(EXIT_FAILURE);
80 }
81 }
82 }
83 }
84
85 reportAllTypes();
86
87 vector<uint8_t> packet;
88 uint16_t len;
89 ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
90 Socket sock(dest.sin4.sin_family, SOCK_STREAM);
91 sock.connect(dest);
92
93 if (gss) {
94 #ifndef ENABLE_GSS_TSIG
95 cerr<<"No GSS support compiled in"<<endl;
96 exit(EXIT_FAILURE);
97 #else
98 string input,output;
99 GssContext gssctx;
100 gssctx.generateLabel(argv[3]);
101 gssctx.setPeerPrincipal(remote_principal);
102
103 while(gssctx.init(input, output) && gssctx.valid() == false) {
104 input="";
105 DNSPacketWriter pwtkey(packet, gssctx.getLabel(), QType::TKEY, QClass::ANY);
106 TKEYRecordContent tkrc;
107 tkrc.d_algo = DNSName("gss-tsig.");
108 // coverity[store_truncates_time_t]
109 tkrc.d_inception = time((time_t*)NULL);
110 tkrc.d_expiration = tkrc.d_inception+15;
111 tkrc.d_mode = 3;
112 tkrc.d_error = 0;
113 tkrc.d_keysize = output.size();
114 tkrc.d_key = output;
115 tkrc.d_othersize = 0;
116 pwtkey.getHeader()->id = dns_random_uint16();
117 pwtkey.startRecord(gssctx.getLabel(), QType::TKEY, 3600, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
118 tkrc.toPacket(pwtkey);
119 pwtkey.commit();
120 for(const string& msg : gssctx.getErrorStrings()) {
121 cerr<<msg<<endl;
122 }
123
124 len = htons(packet.size());
125 if(sock.write((char *) &len, 2) != 2)
126 throw PDNSException("tcp write failed");
127 sock.writen(string((char*)&packet[0], packet.size()));
128 if(sock.read((char *) &len, 2) != 2)
129 throw PDNSException("tcp read failed");
130
131 len=ntohs(len);
132 std::unique_ptr<char[]> creply(new char[len]);
133 int n=0;
134 int numread;
135 while(n<len) {
136 numread=sock.read(creply.get()+n, len-n);
137 if(numread<0)
138 throw PDNSException("tcp read failed");
139 n+=numread;
140 }
141
142 MOADNSParser mdp(false, string(creply.get(), len));
143 if (mdp.d_header.rcode != 0) {
144 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
145 }
146 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
147 if(i->first.d_type != QType::TKEY) continue;
148 // recover TKEY record
149 tkrc = TKEYRecordContent(i->first.getContent()->getZoneRepresentation());
150 input = tkrc.d_key;
151 }
152 }
153
154 if (gssctx.valid() == false) {
155 cerr<<"Could not create GSS context"<<endl;
156 exit(EXIT_FAILURE);
157 }
158
159 tsig_key = DNSName(gssctx.getLabel());
160 #endif
161 }
162
163 DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
164
165 pw.getHeader()->id = dns_random_uint16();
166
167 if (tsig) {
168 TSIGRecordContent trc;
169 trc.d_algoName = getTSIGAlgoName(tsig_algo);
170 trc.d_time = time((time_t*)NULL);
171 trc.d_fudge = 300;
172 trc.d_origID=ntohs(pw.getHeader()->id);
173 trc.d_eRcode=0;
174 addTSIG(pw, trc, tsig_key, tsig_secret, "", false);
175 }
176
177 len = htons(packet.size());
178 if(sock.write((char *) &len, 2) != 2)
179 throw PDNSException("tcp write failed");
180
181 sock.writen(string(packet.begin(), packet.end()));
182
183 bool isNSEC3 = false;
184 int soacount=0;
185 vector<pair<DNSName,string> > records;
186 set<DNSName> labels;
187 map<string,DNSName> hashes;
188 NSEC3PARAMRecordContent ns3pr;
189
190 while(soacount<2) {
191 TSIGRecordContent trc;
192
193 if(sock.read((char *) &len, 2) != 2)
194 throw PDNSException("tcp read failed");
195
196 len=ntohs(len);
197 auto creply = std::make_unique<char[]>(len);
198 int n=0;
199 int numread;
200 while(n<len) {
201 numread=sock.read(creply.get()+n, len-n);
202 if(numread<0)
203 throw PDNSException("tcp read failed");
204 n+=numread;
205 }
206
207 MOADNSParser mdp(false, string(creply.get(), len));
208 if (mdp.d_header.rcode != 0) {
209 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
210 }
211 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
212 if (i->first.d_type == QType::TSIG) {
213 string message;
214 if (!tsig) {
215 std::cerr<<"Unexpected TSIG signature in data"<<endl;
216 }
217 trc = TSIGRecordContent(i->first.getContent()->getZoneRepresentation());
218 continue;
219 }
220 if(i->first.d_type == QType::SOA)
221 {
222 ++soacount;
223 }
224 else if (i->first.d_type == QType::NSEC3PARAM) {
225 ns3pr = NSEC3PARAMRecordContent(i->first.getContent()->getZoneRepresentation());
226 isNSEC3 = true;
227 }
228
229 ostringstream o;
230 o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
231 if(showdetails)
232 {
233 o<<"\t"<<i->first.getContent()->getZoneRepresentation();
234 }
235 else if(i->first.d_type == QType::RRSIG)
236 {
237 string zoneRep = i->first.getContent()->getZoneRepresentation();
238 vector<string> parts;
239 stringtok(parts, zoneRep);
240 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
241 }
242 else if(i->first.d_type == QType::NSEC3)
243 {
244 string zoneRep = i->first.getContent()->getZoneRepresentation();
245 vector<string> parts;
246 stringtok(parts, zoneRep);
247 o<<"\t"<<parts[0]<<" ";
248 if (showflags)
249 o<<parts[1];
250 else
251 o<<"[flags]";
252 o<<" "<<parts[2]<<" "<<parts[3]<<" "<<"[next owner]";
253 for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
254 o<<" "<<*iter;
255 }
256 else if(i->first.d_type == QType::DNSKEY)
257 {
258 string zoneRep = i->first.getContent()->getZoneRepresentation();
259 vector<string> parts;
260 stringtok(parts, zoneRep);
261 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
262 }
263 else
264 {
265 o<<"\t"<<i->first.getContent()->getZoneRepresentation();
266 }
267
268 records.emplace_back(i->first.d_name, o.str());
269
270 DNSName shorter(i->first.d_name);
271 do {
272 labels.insert(shorter);
273 if (shorter == DNSName(argv[3]))
274 break;
275 }while(shorter.chopOff());
276
277 }
278 }
279
280 if (isNSEC3 && unhash)
281 {
282 string hashed;
283 for(const auto &label: labels) {
284 hashed=toBase32Hex(hashQNameWithSalt(ns3pr, label));
285 hashes.insert(pair<string,DNSName>(hashed, label));
286 }
287 }
288
289 for(auto &record: records) {
290 DNSName label /* FIXME400 rename */=record.first;
291 if (isNSEC3 && unhash)
292 {
293 auto i = hashes.find(label.makeRelative(DNSName(argv[3])).toStringNoDot());
294 if (i != hashes.end())
295 label=i->second;
296 }
297 cout<<label.toString()<<record.second<<endl;
298 }
299
300 }
301 catch(PDNSException &e2) {
302 cerr<<"Fatal: "<<e2.reason<<endl;
303 }
304 catch(std::exception &e)
305 {
306 cerr<<"Fatal: "<<e.what()<<endl;
307 }