]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/saxfr.cc
rec: mention rust compiler in compiling docs
[thirdparty/pdns.git] / pdns / saxfr.cc
CommitLineData
870a0fe4
AT
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
0b122e8f 4#include "base64.hh"
df82962d
KM
5#include "dnsparser.hh"
6#include "sstuff.hh"
7#include "misc.hh"
8#include "dnswriter.hh"
9#include "dnsrecords.hh"
10#include "statbag.hh"
3f6fa55d
KM
11#include "base32.hh"
12#include "dnssecinfra.hh"
fa8fd4d2 13
0b122e8f 14#include "dns_random.hh"
b08f1315 15#include "gss_context.hh"
3f6fa55d 16
df82962d
KM
17StatBag S;
18
19int main(int argc, char** argv)
20try
21{
22 if(argc < 4) {
b08f1315 23 cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [gss:remote-principal] [tsig:keyname:algo:secret]"<<endl;
df82962d
KM
24 exit(EXIT_FAILURE);
25 }
26
75b16c22 27 bool showdetails=false;
df82962d 28 bool showflags=false;
3f6fa55d 29 bool unhash=false;
b08f1315 30 bool gss=false;
0b122e8f
AT
31 bool tsig=false;
32 TSIGHashEnum tsig_algo;
eaedd091 33 DNSName tsig_key;
0b122e8f
AT
34 string tsig_secret;
35 string tsigprevious;
36 string remote_principal;
df82962d
KM
37
38 if (argc > 4) {
39 for(int i=4; i<argc; i++) {
75b16c22
KM
40 if (strcmp(argv[i], "showdetails") == 0)
41 showdetails=true;
df82962d
KM
42 if (strcmp(argv[i], "showflags") == 0)
43 showflags=true;
3f6fa55d
KM
44 if (strcmp(argv[i], "unhash") == 0)
45 unhash=true;
b08f1315
OM
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 }
0b122e8f
AT
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 }
eaedd091 64 if (!getTSIGHashEnum(DNSName(parts[2]), tsig_algo)) {
0b122e8f
AT
65 cerr<<"Cannot understand TSIG algorithm '"<<parts[1]<<"'"<<endl;
66 exit(EXIT_FAILURE);
67 }
eaedd091 68 tsig_key = DNSName(parts[1]);
69 if (tsig_key == DNSName()) {
0b122e8f
AT
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 }
df82962d
KM
82 }
83 }
84
85 reportAllTypes();
86
87 vector<uint8_t> packet;
0b122e8f
AT
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
b08f1315
OM
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.");
5a7a3b67 108 // coverity[store_truncates_time_t]
b08f1315
OM
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);
2a104e81 132 auto creply = std::make_unique<char[]>(len);
b08f1315
OM
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
d06dcda4 149 tkrc = TKEYRecordContent(i->first.getContent()->getZoneRepresentation());
b08f1315
OM
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
eaedd091 163 DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
df82962d 164
a410b176 165 pw.getHeader()->id = dns_random_uint16();
0b122e8f
AT
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;
ea3816cf 174 addTSIG(pw, trc, tsig_key, tsig_secret, "", false);
0b122e8f 175 }
0131659f 176
df82962d
KM
177 len = htons(packet.size());
178 if(sock.write((char *) &len, 2) != 2)
179 throw PDNSException("tcp write failed");
180
16657041 181 sock.writen(string(packet.begin(), packet.end()));
df82962d 182
3f6fa55d 183 bool isNSEC3 = false;
df82962d 184 int soacount=0;
9d7fa327
PD
185 vector<pair<DNSName,string> > records;
186 set<DNSName> labels;
187 map<string,DNSName> hashes;
3f6fa55d
KM
188 NSEC3PARAMRecordContent ns3pr;
189
df82962d 190 while(soacount<2) {
0b122e8f
AT
191 TSIGRecordContent trc;
192
df82962d
KM
193 if(sock.read((char *) &len, 2) != 2)
194 throw PDNSException("tcp read failed");
195
196 len=ntohs(len);
2bbc9eb0 197 auto creply = std::make_unique<char[]>(len);
df82962d
KM
198 int n=0;
199 int numread;
200 while(n<len) {
c2826d2e 201 numread=sock.read(creply.get()+n, len-n);
df82962d
KM
202 if(numread<0)
203 throw PDNSException("tcp read failed");
204 n+=numread;
205 }
206
c2826d2e 207 MOADNSParser mdp(false, string(creply.get(), len));
0b122e8f 208 if (mdp.d_header.rcode != 0) {
335da0ba 209 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
0b122e8f 210 }
df82962d 211 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
0b122e8f
AT
212 if (i->first.d_type == QType::TSIG) {
213 string message;
214 if (!tsig) {
215 std::cerr<<"Unexpected TSIG signature in data"<<endl;
216 }
d06dcda4 217 trc = TSIGRecordContent(i->first.getContent()->getZoneRepresentation());
0b122e8f
AT
218 continue;
219 }
df82962d
KM
220 if(i->first.d_type == QType::SOA)
221 {
222 ++soacount;
223 }
3f6fa55d 224 else if (i->first.d_type == QType::NSEC3PARAM) {
d06dcda4
RG
225 ns3pr = NSEC3PARAMRecordContent(i->first.getContent()->getZoneRepresentation());
226 isNSEC3 = true;
3f6fa55d 227 }
df82962d 228
3f6fa55d 229 ostringstream o;
ac6f97d8 230 o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
75b16c22
KM
231 if(showdetails)
232 {
d06dcda4 233 o<<"\t"<<i->first.getContent()->getZoneRepresentation();
75b16c22
KM
234 }
235 else if(i->first.d_type == QType::RRSIG)
df82962d 236 {
d06dcda4 237 string zoneRep = i->first.getContent()->getZoneRepresentation();
df82962d
KM
238 vector<string> parts;
239 stringtok(parts, zoneRep);
ac6f97d8 240 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
df82962d 241 }
702581e4 242 else if(i->first.d_type == QType::NSEC3)
df82962d 243 {
d06dcda4 244 string zoneRep = i->first.getContent()->getZoneRepresentation();
df82962d
KM
245 vector<string> parts;
246 stringtok(parts, zoneRep);
ac6f97d8 247 o<<"\t"<<parts[0]<<" ";
702581e4
KM
248 if (showflags)
249 o<<parts[1];
250 else
251 o<<"[flags]";
252 o<<" "<<parts[2]<<" "<<parts[3]<<" "<<"[next owner]";
df82962d 253 for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
3f6fa55d 254 o<<" "<<*iter;
df82962d
KM
255 }
256 else if(i->first.d_type == QType::DNSKEY)
257 {
d06dcda4 258 string zoneRep = i->first.getContent()->getZoneRepresentation();
df82962d
KM
259 vector<string> parts;
260 stringtok(parts, zoneRep);
ac6f97d8 261 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
df82962d 262 }
df82962d
KM
263 else
264 {
d06dcda4 265 o<<"\t"<<i->first.getContent()->getZoneRepresentation();
df82962d 266 }
3f6fa55d 267
e32a8d46 268 records.emplace_back(i->first.d_name, o.str());
3f6fa55d 269
f809c028 270 DNSName shorter(i->first.d_name);
3f6fa55d
KM
271 do {
272 labels.insert(shorter);
eaedd091 273 if (shorter == DNSName(argv[3]))
3f6fa55d 274 break;
9d7fa327 275 }while(shorter.chopOff());
3f6fa55d 276
df82962d 277 }
df82962d 278 }
3f6fa55d
KM
279
280 if (isNSEC3 && unhash)
281 {
282 string hashed;
9d7fa327 283 for(const auto &label: labels) {
28e2e78e 284 hashed=toBase32Hex(hashQNameWithSalt(ns3pr, label));
9d7fa327 285 hashes.insert(pair<string,DNSName>(hashed, label));
3f6fa55d
KM
286 }
287 }
288
9d7fa327 289 for(auto &record: records) {
3343ad1f 290 DNSName label /* FIXME400 rename */=record.first;
3f6fa55d
KM
291 if (isNSEC3 && unhash)
292 {
eaedd091 293 auto i = hashes.find(label.makeRelative(DNSName(argv[3])).toStringNoDot());
3f6fa55d
KM
294 if (i != hashes.end())
295 label=i->second;
296 }
d96717f7 297 cout<<label.toString()<<record.second<<endl;
3f6fa55d
KM
298 }
299
df82962d 300}
0b122e8f
AT
301catch(PDNSException &e2) {
302 cerr<<"Fatal: "<<e2.reason<<endl;
303}
df82962d
KM
304catch(std::exception &e)
305{
306 cerr<<"Fatal: "<<e.what()<<endl;
307}