mirror of https://github.com/procxx/kepka.git
Add random_padding to dns requests.
This commit is contained in:
parent
3cfc3dcecf
commit
93a967dc74
|
@ -69,7 +69,32 @@ bool CheckPhoneByPrefixesRules(const QString &phone, const QString &rules) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DnsEntry> ParseDnsResponse(const QByteArray &response) {
|
QString GenerateRandomPadding() {
|
||||||
|
constexpr char kValid[] = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
|
||||||
|
auto result = QString();
|
||||||
|
const auto count = [&] {
|
||||||
|
constexpr auto kMinPadding = 13;
|
||||||
|
constexpr auto kMaxPadding = 128;
|
||||||
|
while (true) {
|
||||||
|
const auto result = 1 + (rand_value<uchar>() / 2);
|
||||||
|
Assert(result <= kMaxPadding);
|
||||||
|
if (result >= kMinPadding) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
result.resize(count);
|
||||||
|
for (auto &ch : result) {
|
||||||
|
ch = kValid[rand_value<uchar>() % (sizeof(kValid) - 1)];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DnsEntry> ParseDnsResponse(
|
||||||
|
const QByteArray &bytes,
|
||||||
|
std::optional<int> typeRestriction = std::nullopt) {
|
||||||
// Read and store to "result" all the data bytes from the response:
|
// Read and store to "result" all the data bytes from the response:
|
||||||
// { ..,
|
// { ..,
|
||||||
// "Answer": [
|
// "Answer": [
|
||||||
|
@ -77,48 +102,63 @@ std::vector<DnsEntry> ParseDnsResponse(const QByteArray &response) {
|
||||||
// { .., "data": "bytes2", "TTL": int, .. }
|
// { .., "data": "bytes2", "TTL": int, .. }
|
||||||
// ],
|
// ],
|
||||||
// .. }
|
// .. }
|
||||||
auto result = std::vector<DnsEntry>();
|
|
||||||
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
auto error = QJsonParseError{ 0, QJsonParseError::NoError };
|
||||||
auto document = QJsonDocument::fromJson(response, &error);
|
const auto document = QJsonDocument::fromJson(bytes, &error);
|
||||||
if (error.error != QJsonParseError::NoError) {
|
if (error.error != QJsonParseError::NoError) {
|
||||||
LOG(("Config Error: Failed to parse dns response JSON, error: %1"
|
LOG(("Config Error: Failed to parse dns response JSON, error: %1"
|
||||||
).arg(error.errorString()));
|
).arg(error.errorString()));
|
||||||
|
return {};
|
||||||
} else if (!document.isObject()) {
|
} else if (!document.isObject()) {
|
||||||
LOG(("Config Error: Not an object received in dns response JSON."));
|
LOG(("Config Error: Not an object received in dns response JSON."));
|
||||||
} else {
|
return {};
|
||||||
auto response = document.object();
|
}
|
||||||
auto answerIt = response.find(qsl("Answer"));
|
const auto response = document.object();
|
||||||
|
const auto answerIt = response.find(qsl("Answer"));
|
||||||
if (answerIt == response.constEnd()) {
|
if (answerIt == response.constEnd()) {
|
||||||
LOG(("Config Error: Could not find Answer "
|
LOG(("Config Error: Could not find Answer in dns response JSON."));
|
||||||
"in dns response JSON."));
|
return {};
|
||||||
} else if (!(*answerIt).isArray()) {
|
} else if (!(*answerIt).isArray()) {
|
||||||
LOG(("Config Error: Not an array received "
|
LOG(("Config Error: Not an array received "
|
||||||
"in Answer in dns response JSON."));
|
"in Answer in dns response JSON."));
|
||||||
} else {
|
return {};
|
||||||
for (auto elem : (*answerIt).toArray()) {
|
}
|
||||||
|
|
||||||
|
auto result = std::vector<DnsEntry>();
|
||||||
|
for (const auto elem : (*answerIt).toArray()) {
|
||||||
if (!elem.isObject()) {
|
if (!elem.isObject()) {
|
||||||
LOG(("Config Error: Not an object found "
|
LOG(("Config Error: Not an object found "
|
||||||
"in Answer array in dns response JSON."));
|
"in Answer array in dns response JSON."));
|
||||||
} else {
|
continue;
|
||||||
auto object = elem.toObject();
|
}
|
||||||
auto dataIt = object.find(qsl("data"));
|
const auto object = elem.toObject();
|
||||||
auto ttlIt = object.find(qsl("TTL"));
|
if (typeRestriction) {
|
||||||
auto ttl = (ttlIt != object.constEnd())
|
const auto typeIt = object.find(qsl("type"));
|
||||||
? int64(std::round((*ttlIt).toDouble()))
|
const auto type = int(std::round((*typeIt).toDouble()));
|
||||||
: int64(0);
|
if (!(*typeIt).isDouble()) {
|
||||||
|
LOG(("Config Error: Not a number in type field "
|
||||||
|
"in Answer array in dns response JSON."));
|
||||||
|
continue;
|
||||||
|
} else if (type != *typeRestriction) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto dataIt = object.find(qsl("data"));
|
||||||
if (dataIt == object.constEnd()) {
|
if (dataIt == object.constEnd()) {
|
||||||
LOG(("Config Error: Could not find data "
|
LOG(("Config Error: Could not find data "
|
||||||
"in Answer array entry in dns response JSON."));
|
"in Answer array entry in dns response JSON."));
|
||||||
|
continue;
|
||||||
} else if (!(*dataIt).isString()) {
|
} else if (!(*dataIt).isString()) {
|
||||||
LOG(("Config Error: Not a string data found "
|
LOG(("Config Error: Not a string data found "
|
||||||
"in Answer array entry in dns response JSON."));
|
"in Answer array entry in dns response JSON."));
|
||||||
} else {
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ttlIt = object.find(qsl("TTL"));
|
||||||
|
const auto ttl = (ttlIt != object.constEnd())
|
||||||
|
? int64(std::round((*ttlIt).toDouble()))
|
||||||
|
: int64(0);
|
||||||
result.push_back({ (*dataIt).toString(), ttl });
|
result.push_back({ (*dataIt).toString(), ttl });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +255,9 @@ void SpecialConfigRequest::performRequest(const Attempt &attempt) {
|
||||||
} break;
|
} break;
|
||||||
case Type::Dns: {
|
case Type::Dns: {
|
||||||
url.setPath(qsl("/resolve"));
|
url.setPath(qsl("/resolve"));
|
||||||
url.setQuery(qsl("name=%1&type=16").arg(Global::TxtDomainString()));
|
url.setQuery(qsl("name=%1&type=ANY&random_padding=%2"
|
||||||
|
).arg(Global::TxtDomainString()
|
||||||
|
).arg(GenerateRandomPadding()));
|
||||||
request.setRawHeader("Host", "dns.google.com");
|
request.setRawHeader("Host", "dns.google.com");
|
||||||
} break;
|
} break;
|
||||||
default: Unexpected("Type in SpecialConfigRequest::performRequest.");
|
default: Unexpected("Type in SpecialConfigRequest::performRequest.");
|
||||||
|
@ -236,8 +278,11 @@ void SpecialConfigRequest::requestFinished(
|
||||||
const auto result = finalizeRequest(reply);
|
const auto result = finalizeRequest(reply);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::App: handleResponse(result); break;
|
case Type::App: handleResponse(result); break;
|
||||||
case Type::Dns: handleResponse(
|
case Type::Dns: {
|
||||||
ConcatenateDnsTxtFields(ParseDnsResponse(result))); break;
|
constexpr auto kTypeRestriction = 16; // TXT
|
||||||
|
handleResponse(ConcatenateDnsTxtFields(
|
||||||
|
ParseDnsResponse(result, kTypeRestriction)));
|
||||||
|
} break;
|
||||||
default: Unexpected("Type in SpecialConfigRequest::requestFinished.");
|
default: Unexpected("Type in SpecialConfigRequest::requestFinished.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue