ObfuscatedTransport: support of emulated_tls flag
GitOrigin-RevId: f0ae7ddb21455d4e8d8c3f486744b1b9643bf2d5
This commit is contained in:
parent
3d33e52838
commit
345f28330c
@ -348,6 +348,7 @@ set(TDLIB_SOURCE
|
|||||||
td/mtproto/RawConnection.cpp
|
td/mtproto/RawConnection.cpp
|
||||||
td/mtproto/SessionConnection.cpp
|
td/mtproto/SessionConnection.cpp
|
||||||
td/mtproto/TcpTransport.cpp
|
td/mtproto/TcpTransport.cpp
|
||||||
|
td/mtproto/TlsReaderByteFlow.cpp
|
||||||
td/mtproto/Transport.cpp
|
td/mtproto/Transport.cpp
|
||||||
td/mtproto/utils.cpp
|
td/mtproto/utils.cpp
|
||||||
|
|
||||||
@ -478,6 +479,7 @@ set(TDLIB_SOURCE
|
|||||||
td/mtproto/RawConnection.h
|
td/mtproto/RawConnection.h
|
||||||
td/mtproto/SessionConnection.h
|
td/mtproto/SessionConnection.h
|
||||||
td/mtproto/TcpTransport.h
|
td/mtproto/TcpTransport.h
|
||||||
|
td/mtproto/TlsReaderByteFlow.h
|
||||||
td/mtproto/Transport.h
|
td/mtproto/Transport.h
|
||||||
td/mtproto/TransportType.h
|
td/mtproto/TransportType.h
|
||||||
td/mtproto/utils.h
|
td/mtproto/utils.h
|
||||||
|
@ -15,7 +15,7 @@ namespace mtproto {
|
|||||||
unique_ptr<IStreamTransport> create_transport(TransportType type) {
|
unique_ptr<IStreamTransport> create_transport(TransportType type) {
|
||||||
switch (type.type) {
|
switch (type.type) {
|
||||||
case TransportType::ObfuscatedTcp:
|
case TransportType::ObfuscatedTcp:
|
||||||
return td::make_unique<tcp::ObfuscatedTransport>(type.dc_id, std::move(type.secret));
|
return td::make_unique<tcp::ObfuscatedTransport>(type.dc_id, std::move(type.secret), type.emulate_tls);
|
||||||
case TransportType::Tcp:
|
case TransportType::Tcp:
|
||||||
return td::make_unique<tcp::OldTransport>();
|
return td::make_unique<tcp::OldTransport>();
|
||||||
case TransportType::Http:
|
case TransportType::Http:
|
||||||
|
@ -184,7 +184,12 @@ void ObfuscatedTransport::init(ChainBufferReader *input, ChainBufferWriter *outp
|
|||||||
};
|
};
|
||||||
fix_key(key);
|
fix_key(key);
|
||||||
aes_ctr_byte_flow_.init(key, as<UInt128>(rheader.data() + 8 + 32));
|
aes_ctr_byte_flow_.init(key, as<UInt128>(rheader.data() + 8 + 32));
|
||||||
aes_ctr_byte_flow_.set_input(input_);
|
if (emulate_tls_) {
|
||||||
|
tls_reader_byte_flow_.set_input(input_);
|
||||||
|
tls_reader_byte_flow_ >> aes_ctr_byte_flow_;
|
||||||
|
} else {
|
||||||
|
aes_ctr_byte_flow_.set_input(input_);
|
||||||
|
}
|
||||||
aes_ctr_byte_flow_ >> byte_flow_sink_;
|
aes_ctr_byte_flow_ >> byte_flow_sink_;
|
||||||
|
|
||||||
output_key_ = as<UInt256>(header.data() + 8);
|
output_key_ = as<UInt256>(header.data() + 8);
|
||||||
@ -195,6 +200,67 @@ void ObfuscatedTransport::init(ChainBufferReader *input, ChainBufferWriter *outp
|
|||||||
output_->append(header_slice.substr(56, 8));
|
output_->append(header_slice.substr(56, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<size_t> ObfuscatedTransport::read_next(BufferSlice *message, uint32 *quick_ack) {
|
||||||
|
if (emulate_tls_) {
|
||||||
|
tls_reader_byte_flow_.wakeup();
|
||||||
|
} else {
|
||||||
|
aes_ctr_byte_flow_.wakeup();
|
||||||
|
}
|
||||||
|
return impl_.read_from_stream(byte_flow_sink_.get_output(), message, quick_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObfuscatedTransport::write(BufferWriter &&message, bool quick_ack) {
|
||||||
|
impl_.write_prepare_inplace(&message, quick_ack);
|
||||||
|
output_state_.encrypt(message.as_slice(), message.as_slice());
|
||||||
|
if (emulate_tls_) {
|
||||||
|
do_write_tls(std::move(message));
|
||||||
|
} else {
|
||||||
|
do_write(message.as_buffer_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObfuscatedTransport::do_write_tls(BufferWriter &&message) {
|
||||||
|
size_t size = message.size();
|
||||||
|
|
||||||
|
if (size > (1 << 14)) {
|
||||||
|
auto buffer_slice = message.as_buffer_slice();
|
||||||
|
auto slice = buffer_slice.as_slice();
|
||||||
|
while (!slice.empty()) {
|
||||||
|
auto buf = buffer_slice.from_slice(slice.substr(0, 1 << 14));
|
||||||
|
slice.remove_prefix(buf.size());
|
||||||
|
BufferBuilder builder;
|
||||||
|
builder.append(std::move(buf));
|
||||||
|
do_write_tls(std::move(builder));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferBuilder builder(std::move(message));
|
||||||
|
do_write_tls(std::move(builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObfuscatedTransport::do_write_tls(BufferBuilder &&builder) {
|
||||||
|
size_t size = builder.size();
|
||||||
|
CHECK(size <= (1 << 14));
|
||||||
|
|
||||||
|
char buf[] = "\x17\x03\x03\x00\x00";
|
||||||
|
buf[3] = (size >> 8) & 0xff;
|
||||||
|
buf[4] = size & 0xff;
|
||||||
|
builder.prepend(Slice(buf, 5));
|
||||||
|
|
||||||
|
if (is_first_tls_packet_) {
|
||||||
|
is_first_tls_packet_ = false;
|
||||||
|
Slice first_prefix("\x14\x03\x03\x00\x01\x01");
|
||||||
|
builder.prepend(first_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_write(builder.extract());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObfuscatedTransport::do_write(BufferSlice &&slice) {
|
||||||
|
output_->append(std::move(slice));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tcp
|
} // namespace tcp
|
||||||
} // namespace mtproto
|
} // namespace mtproto
|
||||||
} // namespace td
|
} // namespace td
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "td/mtproto/IStreamTransport.h"
|
#include "td/mtproto/IStreamTransport.h"
|
||||||
#include "td/mtproto/TransportType.h"
|
#include "td/mtproto/TransportType.h"
|
||||||
|
#include "td/mtproto/TlsReaderByteFlow.h"
|
||||||
|
|
||||||
#include "td/utils/AesCtrByteFlow.h"
|
#include "td/utils/AesCtrByteFlow.h"
|
||||||
#include "td/utils/buffer.h"
|
#include "td/utils/buffer.h"
|
||||||
@ -122,24 +123,17 @@ class OldTransport : public IStreamTransport {
|
|||||||
|
|
||||||
class ObfuscatedTransport : public IStreamTransport {
|
class ObfuscatedTransport : public IStreamTransport {
|
||||||
public:
|
public:
|
||||||
ObfuscatedTransport(int16 dc_id, std::string secret)
|
ObfuscatedTransport(int16 dc_id, std::string secret, bool emulate_tls)
|
||||||
: dc_id_(dc_id), secret_(std::move(secret)), impl_(secret_.size() >= 17) {
|
: dc_id_(dc_id), secret_(std::move(secret)), emulate_tls_(emulate_tls), impl_(secret_.size() >= 17) {
|
||||||
}
|
|
||||||
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT {
|
|
||||||
aes_ctr_byte_flow_.wakeup();
|
|
||||||
return impl_.read_from_stream(byte_flow_sink_.get_output(), message, quick_ack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
bool support_quick_ack() const override {
|
bool support_quick_ack() const override {
|
||||||
return impl_.support_quick_ack();
|
return impl_.support_quick_ack();
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(BufferWriter &&message, bool quick_ack) override {
|
void write(BufferWriter &&message, bool quick_ack) override;
|
||||||
impl_.write_prepare_inplace(&message, quick_ack);
|
|
||||||
auto slice = message.as_buffer_slice();
|
|
||||||
output_state_.encrypt(slice.as_slice(), slice.as_slice());
|
|
||||||
output_->append(std::move(slice));
|
|
||||||
}
|
|
||||||
|
|
||||||
void init(ChainBufferReader *input, ChainBufferWriter *output) override;
|
void init(ChainBufferReader *input, ChainBufferWriter *output) override;
|
||||||
|
|
||||||
@ -152,7 +146,14 @@ class ObfuscatedTransport : public IStreamTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t max_prepend_size() const override {
|
size_t max_prepend_size() const override {
|
||||||
return 4;
|
size_t res = 4;
|
||||||
|
if (emulate_tls_) {
|
||||||
|
res += 5;
|
||||||
|
if (is_first_tls_packet_) {
|
||||||
|
res += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t max_append_size() const override {
|
size_t max_append_size() const override {
|
||||||
@ -166,7 +167,10 @@ class ObfuscatedTransport : public IStreamTransport {
|
|||||||
private:
|
private:
|
||||||
int16 dc_id_;
|
int16 dc_id_;
|
||||||
std::string secret_;
|
std::string secret_;
|
||||||
|
bool emulate_tls_;
|
||||||
|
bool is_first_tls_packet_{true};
|
||||||
TransportImpl impl_;
|
TransportImpl impl_;
|
||||||
|
TlsReaderByteFlow tls_reader_byte_flow_;
|
||||||
AesCtrByteFlow aes_ctr_byte_flow_;
|
AesCtrByteFlow aes_ctr_byte_flow_;
|
||||||
ByteFlowSink byte_flow_sink_;
|
ByteFlowSink byte_flow_sink_;
|
||||||
ChainBufferReader *input_;
|
ChainBufferReader *input_;
|
||||||
@ -177,6 +181,10 @@ class ObfuscatedTransport : public IStreamTransport {
|
|||||||
UInt256 output_key_;
|
UInt256 output_key_;
|
||||||
AesCtrState output_state_;
|
AesCtrState output_state_;
|
||||||
ChainBufferWriter *output_;
|
ChainBufferWriter *output_;
|
||||||
|
|
||||||
|
void do_write_tls(BufferWriter &&message);
|
||||||
|
void do_write_tls(BufferBuilder &&builder);
|
||||||
|
void do_write(BufferSlice &&message);
|
||||||
};
|
};
|
||||||
|
|
||||||
using Transport = ObfuscatedTransport;
|
using Transport = ObfuscatedTransport;
|
||||||
|
43
td/mtproto/TlsReaderByteFlow.cpp
Normal file
43
td/mtproto/TlsReaderByteFlow.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
#include "td/mtproto/TlsReaderByteFlow.h"
|
||||||
|
|
||||||
|
#include "td/utils/Status.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
void TlsReaderByteFlow::loop() {
|
||||||
|
while (true) {
|
||||||
|
if (input_->size() < 5) {
|
||||||
|
set_need_size(5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = input_->clone();
|
||||||
|
uint8 buf[5];
|
||||||
|
it.advance(5, MutableSlice(buf, 5));
|
||||||
|
if (Slice(buf, 3) != Slice("\x17\x03\x03")) {
|
||||||
|
close_input(td::Status::Error("Invalid bytes at the beginning of a packet (emulated tls)"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t len = (buf[3] << 8) | buf[4];
|
||||||
|
if (len > (1 << 14)) {
|
||||||
|
close_input(td::Status::Error("Packet lenght is too big (emulated tls)"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.size() < len) {
|
||||||
|
set_need_size(5 + len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
output_.append(it.cut_head(len));
|
||||||
|
*input_ = std::move(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace td
|
19
td/mtproto/TlsReaderByteFlow.h
Normal file
19
td/mtproto/TlsReaderByteFlow.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "td/utils/ByteFlow.h"
|
||||||
|
|
||||||
|
namespace td {
|
||||||
|
|
||||||
|
class TlsReaderByteFlow final : public ByteFlowBase {
|
||||||
|
public:
|
||||||
|
TlsReaderByteFlow() = default;
|
||||||
|
void loop() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace td
|
@ -12,13 +12,14 @@ namespace td {
|
|||||||
namespace mtproto {
|
namespace mtproto {
|
||||||
|
|
||||||
struct TransportType {
|
struct TransportType {
|
||||||
enum Type { Tcp, ObfuscatedTcp, Http } type;
|
enum Type { Tcp, ObfuscatedTcp, Http } type = Tcp;
|
||||||
int16 dc_id;
|
int16 dc_id{0};
|
||||||
string secret;
|
string secret;
|
||||||
|
bool emulate_tls{false};
|
||||||
|
|
||||||
TransportType() : type(Tcp), dc_id(0), secret() {
|
TransportType() = default;
|
||||||
}
|
TransportType(Type type, int16 dc_id, string secret, bool emulate_tls = false)
|
||||||
TransportType(Type type, int16 dc_id, string secret) : type(type), dc_id(dc_id), secret(std::move(secret)) {
|
: type(type), dc_id(dc_id), secret(std::move(secret)), emulate_tls(emulate_tls) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -133,10 +133,9 @@ BufferSlice BufferBuilder::extract() {
|
|||||||
if (to_append_.empty() && to_prepend_.empty()) {
|
if (to_append_.empty() && to_prepend_.empty()) {
|
||||||
return buffer_writer_.as_buffer_slice();
|
return buffer_writer_.as_buffer_slice();
|
||||||
}
|
}
|
||||||
size_t total_size = 0;
|
size_t total_size = size();
|
||||||
for_each([&](auto &&slice) { total_size += slice.size(); });
|
|
||||||
BufferWriter writer(0, 0, total_size);
|
BufferWriter writer(0, 0, total_size);
|
||||||
for_each([&](auto &&slice) {
|
std::move(*this).for_each([&](auto &&slice) {
|
||||||
writer.prepare_append().truncate(slice.size()).copy_from(slice.as_slice());
|
writer.prepare_append().truncate(slice.size()).copy_from(slice.as_slice());
|
||||||
writer.confirm_append(slice.size());
|
writer.confirm_append(slice.size());
|
||||||
});
|
});
|
||||||
@ -144,6 +143,12 @@ BufferSlice BufferBuilder::extract() {
|
|||||||
return writer.as_buffer_slice();
|
return writer.as_buffer_slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t BufferBuilder::size() const {
|
||||||
|
size_t total_size = 0;
|
||||||
|
for_each([&](auto &&slice) { total_size += slice.size(); });
|
||||||
|
return total_size;
|
||||||
|
}
|
||||||
|
|
||||||
bool BufferBuilder::append_inplace(Slice slice) {
|
bool BufferBuilder::append_inplace(Slice slice) {
|
||||||
if (!to_append_.empty()) {
|
if (!to_append_.empty()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -731,6 +731,8 @@ class BufferBuilder {
|
|||||||
BufferBuilder(Slice slice, size_t prepend_size, size_t append_size)
|
BufferBuilder(Slice slice, size_t prepend_size, size_t append_size)
|
||||||
: buffer_writer_(slice, prepend_size, append_size) {
|
: buffer_writer_(slice, prepend_size, append_size) {
|
||||||
}
|
}
|
||||||
|
explicit BufferBuilder(BufferWriter &&buffer_writer) : buffer_writer_(std::move(buffer_writer)) {
|
||||||
|
}
|
||||||
|
|
||||||
void append(BufferSlice slice);
|
void append(BufferSlice slice);
|
||||||
void append(Slice slice);
|
void append(Slice slice);
|
||||||
@ -739,7 +741,7 @@ class BufferBuilder {
|
|||||||
void prepend(Slice slice);
|
void prepend(Slice slice);
|
||||||
|
|
||||||
template <class F>
|
template <class F>
|
||||||
void for_each(F &&f) {
|
void for_each(F &&f) const & {
|
||||||
for (auto &slice : reversed(to_prepend_)) {
|
for (auto &slice : reversed(to_prepend_)) {
|
||||||
f(slice);
|
f(slice);
|
||||||
}
|
}
|
||||||
@ -750,6 +752,19 @@ class BufferBuilder {
|
|||||||
f(slice);
|
f(slice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
template <class F>
|
||||||
|
void for_each(F &&f) && {
|
||||||
|
for (auto &slice : reversed(to_prepend_)) {
|
||||||
|
f(std::move(slice));
|
||||||
|
}
|
||||||
|
if (!buffer_writer_.empty()) {
|
||||||
|
f(buffer_writer_.as_buffer_slice());
|
||||||
|
}
|
||||||
|
for (auto &slice : to_append_) {
|
||||||
|
f(std::move(slice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
BufferSlice extract();
|
BufferSlice extract();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user