ObfuscatedTransport: support of emulated_tls flag

GitOrigin-RevId: f0ae7ddb21455d4e8d8c3f486744b1b9643bf2d5
This commit is contained in:
Arseny Smirnov 2019-06-26 15:51:48 +02:00
parent 3d33e52838
commit 345f28330c
9 changed files with 183 additions and 24 deletions

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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;

View 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

View 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

View File

@ -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) {
} }
}; };

View File

@ -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;

View File

@ -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();