-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdns_dot.cc
112 lines (93 loc) · 3.46 KB
/
dns_dot.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include "dns_dot.h"
#include "dnswire.h"
#include <QUrl>
#include <QSslSocket>
#include <QAbstractSocket>
#include <QTimer>
#include <QtDebug>
/*
* DNS over TLS implementation for dnslookup
*/
DotImplementation::DotImplementation(ushort type, const QString& name, const QString& url, QObject *parent) : DnsImplementation(parent), request(WireRequest(type, name)), resolverUrl(url) {
}
QString DotImplementation::ErrorString() const {
return errorString;
}
QList<QHostAddress> DotImplementation::Addresses() const {
if (responseLength() != countedResponse.length() - 2) {
return QList<QHostAddress>();
}
return WireToAddresses(countedResponse.mid(2));
}
QString DotImplementation::PrettyResults() const {
if (responseLength() != countedResponse.length() - 2) {
return QString();
}
return WireToPretty(countedResponse.mid(2));
}
void DotImplementation::lookup() {
if (request.isEmpty()) {
errorString = tr("Failed to serialize query");
emit finished();
return;
}
QUrl u(resolverUrl);
if (!u.isValid() || u.scheme() != "dot" || u.host().isEmpty()) {
errorString = tr("'%1' doesn't look like the name of a dns over TLS resolver").arg(resolverUrl);
emit finished();
return;
}
int port = u.port(853);
connect(&sock, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors),
[=](const QList<QSslError> &errors){
qWarning() << "Ignoring TLS errors: " << errors;
sock.ignoreSslErrors();
});
connect(&sock, static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
[=](QAbstractSocket::SocketError /*socketError*/){
errorString = tr("Socket error connecting to '%1'%2").arg(resolverUrl, sock.errorString());
emit finished();
});
connect(&sock, &QSslSocket::encrypted, [=](){
QByteArray countedRequest;
int requestLength = request.length();
Q_ASSERT(requestLength < 65536);
countedRequest.append(static_cast<unsigned char>((requestLength & 0xff00) >> 8));
countedRequest.append(static_cast<unsigned char>(requestLength & 0xff));
countedRequest.append(request);
timer.start();
sock.write(countedRequest);
});
connect(&sock, &QSslSocket::readyRead, [=](){
while(sock.bytesAvailable() > 0) {
int bytesWanted;
if (countedResponse.length() < 2) {
bytesWanted = 2 - countedResponse.length();
} else {
bytesWanted = responseLength() - (countedResponse.length() - 2);
}
Q_ASSERT(bytesWanted > 0 && bytesWanted < 65537);
QByteArray chunk = sock.read(bytesWanted);
countedResponse.append(chunk);
if (responseLength() == countedResponse.length() - 2) {
responseTime = timer.nsecsElapsed();
emit finished();
return;
}
}
});
QTimer::singleShot(15000, this, [=](){
if (sock.isOpen()) {
sock.close();
errorString = tr("timed out after 15 seconds");
emit finished();
}
});
sock.connectToHostEncrypted(u.host(), port);
}
int DotImplementation::responseLength() const {
if (countedResponse.length() < 2) {
return -1;
}
return static_cast<unsigned char>(countedResponse.at(0)) * 256 + static_cast<unsigned char>(countedResponse.at(1));
}