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