5 #include "dnsparser.hh"
8 #include "dnswriter.hh"
9 #include "dnsrecords.hh"
12 #include "dnssecinfra.hh"
14 #include "dns_random.hh"
15 #include "gss_context.hh"
19 bool validateTSIG(const string
& message
, const TSIGHashEnum
& algo
, const DNSName
& key
, const string
& secret
, const TSIGRecordContent
*trc
) {
20 int64_t now
= time(0);
21 if(abs(static_cast<int64_t>(trc
->d_time
) - now
) > trc
->d_fudge
) {
22 cerr
<<"TSIG (key '"<<key
<<"') time delta "<< abs(static_cast<int64_t>(trc
->d_time
) - now
)<<" > 'fudge' "<<trc
->d_fudge
<<endl
;
25 if (algo
== TSIG_GSS
) {
26 // authorization is done later
27 GssContext
gssctx(key
);
28 if (!gssctx
.valid()) {
29 cerr
<<"no context"<<endl
;
32 if (!gssctx
.verify(message
, trc
->d_mac
)) {
33 cerr
<<"invalid mac"<<endl
;
38 return calculateHMAC(secret
, message
, algo
) == trc
->d_mac
;
42 int main(int argc
, char** argv
)
46 cerr
<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [gss:remote-principal] [tsig:keyname:algo:secret]"<<endl
;
50 bool showdetails
=false;
55 TSIGHashEnum tsig_algo
;
59 string remote_principal
;
62 for(int i
=4; i
<argc
; i
++) {
63 if (strcmp(argv
[i
], "showdetails") == 0)
65 if (strcmp(argv
[i
], "showflags") == 0)
67 if (strcmp(argv
[i
], "unhash") == 0)
69 if (strncmp(argv
[i
], "gss:",4) == 0) {
73 remote_principal
= string(argv
[i
]+4);
74 if (remote_principal
.empty()) {
75 cerr
<<"Remote principal is required"<<endl
;
79 if (strncmp(argv
[i
], "tsig:",5) == 0) {
82 stringtok(parts
, argv
[i
], ":");
83 if (parts
.size()!=4) {
84 cerr
<<"Invalid syntax for tsig"<<endl
;
87 if (!getTSIGHashEnum(DNSName(parts
[2]), tsig_algo
)) {
88 cerr
<<"Cannot understand TSIG algorithm '"<<parts
[1]<<"'"<<endl
;
91 tsig_key
= DNSName(parts
[1]);
92 if (tsig_key
== DNSName()) {
93 cerr
<<"Key name must be set for tsig"<<endl
;
96 if (B64Decode(parts
[3], tsig_secret
)) {
97 cerr
<<"Secret must be base64 encoded"<<endl
;
100 if (tsig_secret
.size()==0) {
101 cerr
<<"Secret must be set for tsig"<<endl
;
109 dns_random_init("0123456789abcdef");
111 vector
<uint8_t> packet
;
113 ComboAddress
dest(argv
[1] + (*argv
[1]=='@'), atoi(argv
[2]));
114 Socket
sock(dest
.sin4
.sin_family
, SOCK_STREAM
);
118 #ifndef ENABLE_GSS_TSIG
119 cerr
<<"No GSS support compiled in"<<endl
;
124 gssctx
.generateLabel(argv
[3]);
125 gssctx
.setPeerPrincipal(remote_principal
);
127 while(gssctx
.init(input
, output
) && gssctx
.valid() == false) {
129 DNSPacketWriter
pwtkey(packet
, gssctx
.getLabel(), QType::TKEY
, QClass::ANY
);
130 TKEYRecordContent tkrc
;
131 tkrc
.d_algo
= DNSName("gss-tsig.");
132 tkrc
.d_inception
= time((time_t*)NULL
);
133 tkrc
.d_expiration
= tkrc
.d_inception
+15;
136 tkrc
.d_keysize
= output
.size();
138 tkrc
.d_othersize
= 0;
139 pwtkey
.getHeader()->id
= dns_random(0xffff);
140 pwtkey
.startRecord(gssctx
.getLabel(), QType::TKEY
, 3600, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
141 tkrc
.toPacket(pwtkey
);
143 for(const string
& msg
: gssctx
.getErrorStrings()) {
147 len
= htons(packet
.size());
148 if(sock
.write((char *) &len
, 2) != 2)
149 throw PDNSException("tcp write failed");
150 sock
.writen(string((char*)&*packet
.begin(), (char*)&*packet
.end()));
151 if(sock
.read((char *) &len
, 2) != 2)
152 throw PDNSException("tcp read failed");
155 char *creply
= new char[len
];
159 numread
=sock
.read(creply
+n
, len
-n
);
161 throw PDNSException("tcp read failed");
165 MOADNSParser
mdp(string(creply
, len
));
166 if (mdp
.d_header
.rcode
!= 0) {
167 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp
.d_header
.rcode
));
169 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!=mdp
.d_answers
.end(); ++i
) {
170 if(i
->first
.d_type
!= QType::TKEY
) continue;
171 // recover TKEY record
172 tkrc
= TKEYRecordContent(i
->first
.d_content
->getZoneRepresentation());
177 if (gssctx
.valid() == false) {
178 cerr
<<"Could not create GSS context"<<endl
;
182 tsig_key
= DNSName(gssctx
.getLabel());
186 DNSPacketWriter
pw(packet
, DNSName(argv
[3]), 252);
188 pw
.getHeader()->id
= dns_random(0xffff);
191 TSIGRecordContent trc
;
192 trc
.d_algoName
= getTSIGAlgoName(tsig_algo
);
193 trc
.d_time
= time((time_t*)NULL
);
195 trc
.d_origID
=ntohs(pw
.getHeader()->id
);
197 addTSIG(pw
, &trc
, tsig_key
, tsig_secret
, "", false);
200 len
= htons(packet
.size());
201 if(sock
.write((char *) &len
, 2) != 2)
202 throw PDNSException("tcp write failed");
204 sock
.writen(string((char*)&*packet
.begin(), (char*)&*packet
.end()));
206 bool isNSEC3
= false;
208 vector
<pair
<DNSName
,string
> > records
;
210 map
<string
,DNSName
> hashes
;
211 NSEC3PARAMRecordContent ns3pr
;
214 TSIGRecordContent trc
;
216 if(sock
.read((char *) &len
, 2) != 2)
217 throw PDNSException("tcp read failed");
220 char *creply
= new char[len
];
224 numread
=sock
.read(creply
+n
, len
-n
);
226 throw PDNSException("tcp read failed");
230 string packet
= string(creply
, len
);
232 MOADNSParser
mdp(packet
);
233 if (mdp
.d_header
.rcode
!= 0) {
234 throw PDNSException(string("Remote server refused: ") + std::to_string(mdp
.d_header
.rcode
));
236 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!=mdp
.d_answers
.end(); ++i
) {
237 if (i
->first
.d_type
== QType::TSIG
) {
240 std::cerr
<<"Unexpected TSIG signature in data"<<endl
;
242 trc
= TSIGRecordContent(i
->first
.d_content
->getZoneRepresentation());
245 if(i
->first
.d_type
== QType::SOA
)
249 else if (i
->first
.d_type
== QType::NSEC3PARAM
) {
250 ns3pr
= NSEC3PARAMRecordContent(i
->first
.d_content
->getZoneRepresentation());
255 o
<<"\t"<<i
->first
.d_ttl
<<"\tIN\t"<<DNSRecordContent::NumberToType(i
->first
.d_type
);
258 o
<<"\t"<<i
->first
.d_content
->getZoneRepresentation();
260 else if(i
->first
.d_type
== QType::RRSIG
)
262 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
263 vector
<string
> parts
;
264 stringtok(parts
, zoneRep
);
265 o
<<"\t"<<parts
[0]<<" "<<parts
[1]<<" "<<parts
[2]<<" "<<parts
[3]<<" [expiry] [inception] [keytag] "<<parts
[7]<<" ...";
267 else if(i
->first
.d_type
== QType::NSEC3
)
269 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
270 vector
<string
> parts
;
271 stringtok(parts
, zoneRep
);
272 o
<<"\t"<<parts
[0]<<" ";
277 o
<<" "<<parts
[2]<<" "<<parts
[3]<<" "<<"[next owner]";
278 for(vector
<string
>::iterator iter
= parts
.begin()+5; iter
!= parts
.end(); ++iter
)
281 else if(i
->first
.d_type
== QType::DNSKEY
)
283 string zoneRep
= i
->first
.d_content
->getZoneRepresentation();
284 vector
<string
> parts
;
285 stringtok(parts
, zoneRep
);
286 o
<<"\t"<<parts
[0]<<" "<<parts
[1]<<" "<<parts
[2]<<" ...";
290 o
<<"\t"<<i
->first
.d_content
->getZoneRepresentation();
293 records
.push_back(make_pair(i
->first
.d_name
,o
.str()));
295 DNSName
shorter(i
->first
.d_name
);
297 labels
.insert(shorter
);
298 if (shorter
== DNSName(argv
[3]))
300 }while(shorter
.chopOff());
307 if (isNSEC3
&& unhash
)
310 for(const auto &label
: labels
) {
311 hashed
=toBase32Hex(hashQNameWithSalt(ns3pr
, label
));
312 hashes
.insert(pair
<string
,DNSName
>(hashed
, label
));
316 for(auto &record
: records
) {
317 DNSName label
/* FIXME400 rename */=record
.first
;
318 if (isNSEC3
&& unhash
)
320 auto i
= hashes
.find(label
.makeRelative(DNSName(argv
[3])).toStringNoDot());
321 if (i
!= hashes
.end())
324 cout
<<label
.toString()<<record
.second
<<endl
;
328 catch(PDNSException
&e2
) {
329 cerr
<<"Fatal: "<<e2
.reason
<<endl
;
331 catch(std::exception
&e
)
333 cerr
<<"Fatal: "<<e
.what()<<endl
;