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
16 StatBag S;
17
main(int argc,char ** argv)18 int main(int argc, char** argv)
19 try
20 {
21 if(argc < 4) {
22 cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [tsig:keyname:algo:secret]"<<endl;
23 exit(EXIT_FAILURE);
24 }
25
26 bool showdetails=false;
27 bool showflags=false;
28 bool unhash=false;
29 bool tsig=false;
30 TSIGHashEnum tsig_algo;
31 DNSName tsig_key;
32 string tsig_secret;
33 string tsigprevious;
34 string remote_principal;
35
36 if (argc > 4) {
37 for(int i=4; i<argc; i++) {
38 if (strcmp(argv[i], "showdetails") == 0)
39 showdetails=true;
40 if (strcmp(argv[i], "showflags") == 0)
41 showflags=true;
42 if (strcmp(argv[i], "unhash") == 0)
43 unhash=true;
44 if (strncmp(argv[i], "tsig:",5) == 0) {
45 vector<string> parts;
46 tsig=true;
47 stringtok(parts, argv[i], ":");
48 if (parts.size()!=4) {
49 cerr<<"Invalid syntax for tsig"<<endl;
50 exit(EXIT_FAILURE);
51 }
52 if (!getTSIGHashEnum(DNSName(parts[2]), tsig_algo)) {
53 cerr<<"Cannot understand TSIG algorithm '"<<parts[1]<<"'"<<endl;
54 exit(EXIT_FAILURE);
55 }
56 tsig_key = DNSName(parts[1]);
57 if (tsig_key == DNSName()) {
58 cerr<<"Key name must be set for tsig"<<endl;
59 exit(EXIT_FAILURE);
60 }
61 if (B64Decode(parts[3], tsig_secret)) {
62 cerr<<"Secret must be base64 encoded"<<endl;
63 exit(EXIT_FAILURE);
64 }
65 if (tsig_secret.size()==0) {
66 cerr<<"Secret must be set for tsig"<<endl;
67 exit(EXIT_FAILURE);
68 }
69 }
70 }
71 }
72
73 reportAllTypes();
74
75 vector<uint8_t> packet;
76 uint16_t len;
77 ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
78 Socket sock(dest.sin4.sin_family, SOCK_STREAM);
79 sock.connect(dest);
80
81 DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
82
83 pw.getHeader()->id = dns_random_uint16();
84
85 if (tsig) {
86 TSIGRecordContent trc;
87 trc.d_algoName = getTSIGAlgoName(tsig_algo);
88 trc.d_time = time((time_t*)NULL);
89 trc.d_fudge = 300;
90 trc.d_origID=ntohs(pw.getHeader()->id);
91 trc.d_eRcode=0;
92 addTSIG(pw, trc, tsig_key, tsig_secret, "", false);
93 }
94
95 len = htons(packet.size());
96 if(sock.write((char *) &len, 2) != 2)
97 throw PDNSException("tcp write failed");
98
99 sock.writen(string(packet.begin(), packet.end()));
100
101 bool isNSEC3 = false;
102 int soacount=0;
103 vector<pair<DNSName,string> > records;
104 set<DNSName> labels;
105 map<string,DNSName> hashes;
106 NSEC3PARAMRecordContent ns3pr;
107
108 while(soacount<2) {
109 TSIGRecordContent trc;
110
111 if(sock.read((char *) &len, 2) != 2)
112 throw PDNSException("tcp read failed");
113
114 len=ntohs(len);
115 std::unique_ptr<char[]> creply(new char[len]);
116 int n=0;
117 int numread;
118 while(n<len) {
119 numread=sock.read(creply.get()+n, len-n);
120 if(numread<0)
121 throw PDNSException("tcp read failed");
122 n+=numread;
123 }
124
125 MOADNSParser mdp(false, string(creply.get(), len));
126 if (mdp.d_header.rcode != 0) {
127 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
128 }
129 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
130 if (i->first.d_type == QType::TSIG) {
131 string message;
132 if (!tsig) {
133 std::cerr<<"Unexpected TSIG signature in data"<<endl;
134 }
135 trc = TSIGRecordContent(i->first.d_content->getZoneRepresentation());
136 continue;
137 }
138 if(i->first.d_type == QType::SOA)
139 {
140 ++soacount;
141 }
142 else if (i->first.d_type == QType::NSEC3PARAM) {
143 ns3pr = NSEC3PARAMRecordContent(i->first.d_content->getZoneRepresentation());
144 isNSEC3 = true;
145 }
146
147 ostringstream o;
148 o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
149 if(showdetails)
150 {
151 o<<"\t"<<i->first.d_content->getZoneRepresentation();
152 }
153 else if(i->first.d_type == QType::RRSIG)
154 {
155 string zoneRep = i->first.d_content->getZoneRepresentation();
156 vector<string> parts;
157 stringtok(parts, zoneRep);
158 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
159 }
160 else if(i->first.d_type == QType::NSEC3)
161 {
162 string zoneRep = i->first.d_content->getZoneRepresentation();
163 vector<string> parts;
164 stringtok(parts, zoneRep);
165 o<<"\t"<<parts[0]<<" ";
166 if (showflags)
167 o<<parts[1];
168 else
169 o<<"[flags]";
170 o<<" "<<parts[2]<<" "<<parts[3]<<" "<<"[next owner]";
171 for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
172 o<<" "<<*iter;
173 }
174 else if(i->first.d_type == QType::DNSKEY)
175 {
176 string zoneRep = i->first.d_content->getZoneRepresentation();
177 vector<string> parts;
178 stringtok(parts, zoneRep);
179 o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
180 }
181 else
182 {
183 o<<"\t"<<i->first.d_content->getZoneRepresentation();
184 }
185
186 records.push_back(make_pair(i->first.d_name,o.str()));
187
188 DNSName shorter(i->first.d_name);
189 do {
190 labels.insert(shorter);
191 if (shorter == DNSName(argv[3]))
192 break;
193 }while(shorter.chopOff());
194
195 }
196 }
197
198 if (isNSEC3 && unhash)
199 {
200 string hashed;
201 for(const auto &label: labels) {
202 hashed=toBase32Hex(hashQNameWithSalt(ns3pr, label));
203 hashes.insert(pair<string,DNSName>(hashed, label));
204 }
205 }
206
207 for(auto &record: records) {
208 DNSName label /* FIXME400 rename */=record.first;
209 if (isNSEC3 && unhash)
210 {
211 auto i = hashes.find(label.makeRelative(DNSName(argv[3])).toStringNoDot());
212 if (i != hashes.end())
213 label=i->second;
214 }
215 cout<<label.toString()<<record.second<<endl;
216 }
217
218 }
219 catch(PDNSException &e2) {
220 cerr<<"Fatal: "<<e2.reason<<endl;
221 }
222 catch(std::exception &e)
223 {
224 cerr<<"Fatal: "<<e.what()<<endl;
225 }
226