]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/saxfr.cc
Merge pull request #14021 from Habbie/auth-lua-join-whitespace
[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 tkrc.d_inception = time((time_t*)NULL);
109 tkrc.d_expiration = tkrc.d_inception+15;
110 tkrc.d_mode = 3;
111 tkrc.d_error = 0;
112 tkrc.d_keysize = output.size();
113 tkrc.d_key = output;
114 tkrc.d_othersize = 0;
115 pwtkey.getHeader()->id = dns_random(0xffff);
116 pwtkey.startRecord(gssctx.getLabel(), QType::TKEY, 3600, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
117 tkrc.toPacket(pwtkey);
118 pwtkey.commit();
119 for(const string& msg : gssctx.getErrorStrings()) {
120 cerr<<msg<<endl;
121 }
122
123 len = htons(packet.size());
124 if(sock.write((char *) &len, 2) != 2)
125 throw PDNSException("tcp write failed");
126 sock.writen(string((char*)&packet[0], packet.size()));
127 if(sock.read((char *) &len, 2) != 2)
128 throw PDNSException("tcp read failed");
129
130 len=ntohs(len);
131 char *creply = new char[len];
132 int n=0;
133 int numread;
134 while(n<len) {
135 numread=sock.read(creply+n, len-n);
136 if(numread<0)
137 throw PDNSException("tcp read failed");
138 n+=numread;
139 }
140
141 MOADNSParser mdp(false, string(creply, len));
142 if (mdp.d_header.rcode != 0) {
143 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
144 }
145 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
146 if(i->first.d_type != QType::TKEY) continue;
147 // recover TKEY record
148 tkrc = TKEYRecordContent(i->first.d_content->getZoneRepresentation());
149 input = tkrc.d_key;
150 }
151 }
152
153 if (gssctx.valid() == false) {
154 cerr<<"Could not create GSS context"<<endl;
155 exit(EXIT_FAILURE);
156 }
157
158 tsig_key = DNSName(gssctx.getLabel());
159 #endif
160 }
161
162 DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
163
164 pw.getHeader()->id = dns_random(0xffff);
165
166 if (tsig) {
167 TSIGRecordContent trc;
168 trc.d_algoName = getTSIGAlgoName(tsig_algo);
169 trc.d_time = time((time_t*)NULL);
170 trc.d_fudge = 300;
171 trc.d_origID=ntohs(pw.getHeader()->id);
172 trc.d_eRcode=0;
173 addTSIG(pw, trc, tsig_key, tsig_secret, "", false);
174 }
175
176 len = htons(packet.size());
177 if(sock.write((char *) &len, 2) != 2)
178 throw PDNSException("tcp write failed");
179
180 sock.writen(string(packet.begin(), packet.end()));
181
182 bool isNSEC3 = false;
183 int soacount=0;
184 vector<pair<DNSName,string> > records;
185 set<DNSName> labels;
186 map<string,DNSName> hashes;
187 NSEC3PARAMRecordContent ns3pr;
188
189 while(soacount<2) {
190 TSIGRecordContent trc;
191
192 if(sock.read((char *) &len, 2) != 2)
193 throw PDNSException("tcp read failed");
194
195 len=ntohs(len);
196 char *creply = new char[len];
197 int n=0;
198 int numread;
199 while(n<len) {
200 numread=sock.read(creply+n, len-n);
201 if(numread<0)
202 throw PDNSException("tcp read failed");
203 n+=numread;
204 }
205
206 MOADNSParser mdp(false, string(creply, len));
207 if (mdp.d_header.rcode != 0) {
208 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
209 }
210 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
211 if (i->first.d_type == QType::TSIG) {
212 string message;
213 if (!tsig) {
214 std::cerr<<"Unexpected TSIG signature in data"<<endl;
215 }
216 trc = TSIGRecordContent(i->first.d_content->getZoneRepresentation());
217 continue;
218 }
219 if(i->first.d_type == QType::SOA)
220 {
221 ++soacount;
222 }
223 else if (i->first.d_type == QType::NSEC3PARAM) {
224 ns3pr = NSEC3PARAMRecordContent(i->first.d_content->getZoneRepresentation());
225 isNSEC3 = true;
226 }
227
228 ostringstream o;
229 o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
230 if(showdetails)
231 {
232 o<<"\t"<<i->first.d_content->getZoneRepresentation();
233 }
234 else if(i->first.d_type == QType::RRSIG)
235 {
236 string zoneRep = i->first.d_content->getZoneRepresentation();
237 vector<string> parts;
238 stringtok(parts, zoneRep);
239 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
240 }
241 else if(i->first.d_type == QType::NSEC3)
242 {
243 string zoneRep = i->first.d_content->getZoneRepresentation();
244 vector<string> parts;
245 stringtok(parts, zoneRep);
246 o<<"\t"<<parts[0]<<" ";
247 if (showflags)
248 o<<parts[1];
249 else
250 o<<"[flags]";
251 o<<" "<<parts[2]<<" "<<parts[3]<<" "<<"[next owner]";
252 for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
253 o<<" "<<*iter;
254 }
255 else if(i->first.d_type == QType::DNSKEY)
256 {
257 string zoneRep = i->first.d_content->getZoneRepresentation();
258 vector<string> parts;
259 stringtok(parts, zoneRep);
260 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
261 }
262 else
263 {
264 o<<"\t"<<i->first.d_content->getZoneRepresentation();
265 }
266
267 records.push_back(make_pair(i->first.d_name,o.str()));
268
269 DNSName shorter(i->first.d_name);
270 do {
271 labels.insert(shorter);
272 if (shorter == DNSName(argv[3]))
273 break;
274 }while(shorter.chopOff());
275
276 }
277
278 delete[] creply;
279 }
280
281 if (isNSEC3 && unhash)
282 {
283 string hashed;
284 for(const auto &label: labels) {
285 hashed=toBase32Hex(hashQNameWithSalt(ns3pr, label));
286 hashes.insert(pair<string,DNSName>(hashed, label));
287 }
288 }
289
290 for(auto &record: records) {
291 DNSName label /* FIXME400 rename */=record.first;
292 if (isNSEC3 && unhash)
293 {
294 auto i = hashes.find(label.makeRelative(DNSName(argv[3])).toStringNoDot());
295 if (i != hashes.end())
296 label=i->second;
297 }
298 cout<<label.toString()<<record.second<<endl;
299 }
300
301 }
302 catch(PDNSException &e2) {
303 cerr<<"Fatal: "<<e2.reason<<endl;
304 }
305 catch(std::exception &e)
306 {
307 cerr<<"Fatal: "<<e.what()<<endl;
308 }