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/SessionConnection.cpp
|
||||
td/mtproto/TcpTransport.cpp
|
||||
td/mtproto/TlsReaderByteFlow.cpp
|
||||
td/mtproto/Transport.cpp
|
||||
td/mtproto/utils.cpp
|
||||
|
||||
@ -478,6 +479,7 @@ set(TDLIB_SOURCE
|
||||
td/mtproto/RawConnection.h
|
||||
td/mtproto/SessionConnection.h
|
||||
td/mtproto/TcpTransport.h
|
||||
td/mtproto/TlsReaderByteFlow.h
|
||||
td/mtproto/Transport.h
|
||||
td/mtproto/TransportType.h
|
||||
td/mtproto/utils.h
|
||||
|
@ -15,7 +15,7 @@ namespace mtproto {
|
||||
unique_ptr<IStreamTransport> create_transport(TransportType type) {
|
||||
switch (type.type) {
|
||||
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:
|
||||
return td::make_unique<tcp::OldTransport>();
|
||||
case TransportType::Http:
|
||||
|
@ -184,7 +184,12 @@ void ObfuscatedTransport::init(ChainBufferReader *input, ChainBufferWriter *outp
|
||||
};
|
||||
fix_key(key);
|
||||
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_;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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 mtproto
|
||||
} // namespace td
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "td/mtproto/IStreamTransport.h"
|
||||
#include "td/mtproto/TransportType.h"
|
||||
#include "td/mtproto/TlsReaderByteFlow.h"
|
||||
|
||||
#include "td/utils/AesCtrByteFlow.h"
|
||||
#include "td/utils/buffer.h"
|
||||
@ -122,24 +123,17 @@ class OldTransport : public IStreamTransport {
|
||||
|
||||
class ObfuscatedTransport : public IStreamTransport {
|
||||
public:
|
||||
ObfuscatedTransport(int16 dc_id, std::string secret)
|
||||
: dc_id_(dc_id), secret_(std::move(secret)), 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);
|
||||
ObfuscatedTransport(int16 dc_id, std::string secret, bool emulate_tls)
|
||||
: 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;
|
||||
|
||||
bool support_quick_ack() const override {
|
||||
return impl_.support_quick_ack();
|
||||
}
|
||||
|
||||
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 write(BufferWriter &&message, bool quick_ack) override;
|
||||
|
||||
void init(ChainBufferReader *input, ChainBufferWriter *output) override;
|
||||
|
||||
@ -152,7 +146,14 @@ class ObfuscatedTransport : public IStreamTransport {
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -166,7 +167,10 @@ class ObfuscatedTransport : public IStreamTransport {
|
||||
private:
|
||||
int16 dc_id_;
|
||||
std::string secret_;
|
||||
bool emulate_tls_;
|
||||
bool is_first_tls_packet_{true};
|
||||
TransportImpl impl_;
|
||||
TlsReaderByteFlow tls_reader_byte_flow_;
|
||||
AesCtrByteFlow aes_ctr_byte_flow_;
|
||||
ByteFlowSink byte_flow_sink_;
|
||||
ChainBufferReader *input_;
|
||||
@ -177,6 +181,10 @@ class ObfuscatedTransport : public IStreamTransport {
|
||||
UInt256 output_key_;
|
||||
AesCtrState output_state_;
|
||||
ChainBufferWriter *output_;
|
||||
|
||||
void do_write_tls(BufferWriter &&message);
|
||||
void do_write_tls(BufferBuilder &&builder);
|
||||
void do_write(BufferSlice &&message);
|
||||
};
|
||||
|
||||
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 {
|
||||
|
||||
struct TransportType {
|
||||
enum Type { Tcp, ObfuscatedTcp, Http } type;
|
||||
int16 dc_id;
|
||||
enum Type { Tcp, ObfuscatedTcp, Http } type = Tcp;
|
||||
int16 dc_id{0};
|
||||
string secret;
|
||||
bool emulate_tls{false};
|
||||
|
||||
TransportType() : type(Tcp), dc_id(0), secret() {
|
||||
}
|
||||
TransportType(Type type, int16 dc_id, string secret) : type(type), dc_id(dc_id), secret(std::move(secret)) {
|
||||
TransportType() = default;
|
||||
TransportType(Type type, int16 dc_id, string secret, bool emulate_tls = false)
|
||||
: 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()) {
|
||||
return buffer_writer_.as_buffer_slice();
|
||||
}
|
||||
size_t total_size = 0;
|
||||
for_each([&](auto &&slice) { total_size += slice.size(); });
|
||||
size_t total_size = 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.confirm_append(slice.size());
|
||||
});
|
||||
@ -144,6 +143,12 @@ BufferSlice BufferBuilder::extract() {
|
||||
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) {
|
||||
if (!to_append_.empty()) {
|
||||
return false;
|
||||
|
@ -731,6 +731,8 @@ class BufferBuilder {
|
||||
BufferBuilder(Slice slice, size_t prepend_size, size_t 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(Slice slice);
|
||||
@ -739,7 +741,7 @@ class BufferBuilder {
|
||||
void prepend(Slice slice);
|
||||
|
||||
template <class F>
|
||||
void for_each(F &&f) {
|
||||
void for_each(F &&f) const & {
|
||||
for (auto &slice : reversed(to_prepend_)) {
|
||||
f(slice);
|
||||
}
|
||||
@ -750,6 +752,19 @@ class BufferBuilder {
|
||||
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();
|
||||
|
||||
|
Reference in New Issue
Block a user