2018-12-31 20:04:05 +01:00
|
|
|
//
|
2018-12-31 23:02:34 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// 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/mtproto/IStreamTransport.h"
|
2019-06-26 15:51:48 +02:00
|
|
|
#include "td/mtproto/TlsReaderByteFlow.h"
|
2019-07-01 15:18:28 +02:00
|
|
|
#include "td/mtproto/TransportType.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
#include "td/utils/AesCtrByteFlow.h"
|
|
|
|
#include "td/utils/buffer.h"
|
|
|
|
#include "td/utils/ByteFlow.h"
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/crypto.h"
|
2018-09-07 02:41:21 +02:00
|
|
|
#include "td/utils/port/detail/PollableFd.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/Status.h"
|
2018-12-19 22:18:53 +01:00
|
|
|
#include "td/utils/UInt.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
namespace td {
|
|
|
|
namespace mtproto {
|
|
|
|
namespace tcp {
|
2018-07-27 02:54:25 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class ITransport {
|
|
|
|
// Writes packet into message.
|
|
|
|
// Returns 0 if everything is ok, and [expected_size] otherwise.
|
|
|
|
// There is no sense to call this function when [stream->size > expected_size]
|
|
|
|
//
|
|
|
|
// (tpc is stream-base protocol. So the input message is a stream, not a slice)
|
|
|
|
virtual size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) = 0;
|
|
|
|
|
|
|
|
// Writes header inplace.
|
|
|
|
virtual void write_prepare_inplace(BufferWriter *message, bool quick_ack) = 0;
|
|
|
|
|
|
|
|
// Writes first several bytes into output stream.
|
|
|
|
virtual void init_output_stream(ChainBufferWriter *stream) = 0;
|
|
|
|
|
|
|
|
virtual bool support_quick_ack() const = 0;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ITransport() = default;
|
|
|
|
ITransport(const ITransport &) = delete;
|
|
|
|
ITransport &operator=(const ITransport &) = delete;
|
|
|
|
ITransport(ITransport &&) = delete;
|
|
|
|
ITransport &operator=(ITransport &&) = delete;
|
|
|
|
virtual ~ITransport() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
class AbridgedTransport : public ITransport {
|
|
|
|
public:
|
|
|
|
size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) override;
|
|
|
|
void write_prepare_inplace(BufferWriter *message, bool quick_ack) override;
|
|
|
|
void init_output_stream(ChainBufferWriter *stream) override;
|
|
|
|
bool support_quick_ack() const override {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class IntermediateTransport : ITransport {
|
|
|
|
public:
|
2018-06-15 20:54:22 +02:00
|
|
|
explicit IntermediateTransport(bool with_padding) : with_padding_(with_padding) {
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
size_t read_from_stream(ChainBufferReader *stream, BufferSlice *message, uint32 *quick_ack) override;
|
|
|
|
void write_prepare_inplace(BufferWriter *message, bool quick_ack) override;
|
|
|
|
void init_output_stream(ChainBufferWriter *stream) override;
|
|
|
|
bool support_quick_ack() const override {
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-15 20:54:22 +02:00
|
|
|
bool with_padding() const {
|
|
|
|
return with_padding_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
bool with_padding_;
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
using TransportImpl = IntermediateTransport;
|
|
|
|
|
|
|
|
class OldTransport : public IStreamTransport {
|
|
|
|
public:
|
|
|
|
OldTransport() = default;
|
|
|
|
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT {
|
|
|
|
return impl_.read_from_stream(input_, message, quick_ack);
|
|
|
|
}
|
|
|
|
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);
|
|
|
|
output_->append(message.as_buffer_slice());
|
|
|
|
}
|
|
|
|
void init(ChainBufferReader *input, ChainBufferWriter *output) override {
|
|
|
|
input_ = input;
|
|
|
|
output_ = output;
|
|
|
|
impl_.init_output_stream(output_);
|
|
|
|
}
|
|
|
|
bool can_read() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool can_write() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t max_prepend_size() const override {
|
|
|
|
return 4;
|
|
|
|
}
|
2018-06-15 20:54:22 +02:00
|
|
|
|
|
|
|
size_t max_append_size() const override {
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
TransportType get_type() const override {
|
2018-04-30 19:01:18 +02:00
|
|
|
return TransportType{TransportType::Tcp, 0, ""};
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2019-07-04 12:56:10 +02:00
|
|
|
bool use_random_padding() const override {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
private:
|
2018-06-15 20:54:22 +02:00
|
|
|
TransportImpl impl_{false};
|
2018-12-31 20:04:05 +01:00
|
|
|
ChainBufferReader *input_;
|
|
|
|
ChainBufferWriter *output_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ObfuscatedTransport : public IStreamTransport {
|
|
|
|
public:
|
2019-06-26 17:27:19 +02:00
|
|
|
ObfuscatedTransport(int16 dc_id, std::string secret)
|
|
|
|
: dc_id_(dc_id), secret_(std::move(secret)), impl_(secret_.size() >= 17) {
|
2019-07-01 15:18:28 +02:00
|
|
|
emulate_tls_ = secret_.size() >= 17 && secret_[0] == '\xee';
|
2019-07-04 12:56:10 +02:00
|
|
|
use_random_padding_ = secret_.size() >= 17;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2019-06-26 15:51:48 +02:00
|
|
|
Result<size_t> read_next(BufferSlice *message, uint32 *quick_ack) override TD_WARN_UNUSED_RESULT;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
bool support_quick_ack() const override {
|
|
|
|
return impl_.support_quick_ack();
|
|
|
|
}
|
|
|
|
|
2019-06-26 15:51:48 +02:00
|
|
|
void write(BufferWriter &&message, bool quick_ack) override;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-02-12 10:01:11 +01:00
|
|
|
void init(ChainBufferReader *input, ChainBufferWriter *output) override;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
bool can_read() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool can_write() const override {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t max_prepend_size() const override {
|
2019-06-26 15:51:48 +02:00
|
|
|
size_t res = 4;
|
|
|
|
if (emulate_tls_) {
|
|
|
|
res += 5;
|
|
|
|
if (is_first_tls_packet_) {
|
|
|
|
res += 6;
|
|
|
|
}
|
|
|
|
}
|
2019-07-01 15:34:39 +02:00
|
|
|
res += header_.size();
|
2019-07-01 15:18:28 +02:00
|
|
|
if (res & 3) {
|
|
|
|
res += 4 - (res & 3);
|
|
|
|
}
|
2019-06-26 15:51:48 +02:00
|
|
|
return res;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-06-15 20:54:22 +02:00
|
|
|
size_t max_append_size() const override {
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
TransportType get_type() const override {
|
2018-04-30 19:01:18 +02:00
|
|
|
return TransportType{TransportType::ObfuscatedTcp, dc_id_, secret_};
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2019-07-04 12:56:10 +02:00
|
|
|
bool use_random_padding() const override {
|
|
|
|
return use_random_padding_;
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
private:
|
2018-04-30 19:01:18 +02:00
|
|
|
int16 dc_id_;
|
|
|
|
std::string secret_;
|
2019-07-01 15:18:28 +02:00
|
|
|
bool emulate_tls_{false};
|
2019-07-04 12:56:10 +02:00
|
|
|
bool use_random_padding_{false};
|
2019-06-26 15:51:48 +02:00
|
|
|
bool is_first_tls_packet_{true};
|
2019-07-01 15:34:39 +02:00
|
|
|
std::string header_;
|
2018-06-16 02:03:14 +02:00
|
|
|
TransportImpl impl_;
|
2019-06-26 15:51:48 +02:00
|
|
|
TlsReaderByteFlow tls_reader_byte_flow_;
|
2018-12-31 20:04:05 +01:00
|
|
|
AesCtrByteFlow aes_ctr_byte_flow_;
|
|
|
|
ByteFlowSink byte_flow_sink_;
|
|
|
|
ChainBufferReader *input_;
|
|
|
|
|
2019-07-02 00:58:01 +02:00
|
|
|
static constexpr int32 MAX_TLS_PACKET_LENGTH = 2878;
|
2019-07-01 15:18:28 +02:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
// TODO: use ByteFlow?
|
|
|
|
// One problem is that BufferedFd owns output_buffer_
|
|
|
|
// The other problem is that first 56 bytes must be sent unencrypted.
|
|
|
|
UInt256 output_key_;
|
|
|
|
AesCtrState output_state_;
|
|
|
|
ChainBufferWriter *output_;
|
2019-06-26 15:51:48 +02:00
|
|
|
|
|
|
|
void do_write_tls(BufferWriter &&message);
|
|
|
|
void do_write_tls(BufferBuilder &&builder);
|
2019-07-01 15:34:39 +02:00
|
|
|
void do_write_main(BufferWriter &&message);
|
2019-06-26 15:51:48 +02:00
|
|
|
void do_write(BufferSlice &&message);
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
using Transport = ObfuscatedTransport;
|
|
|
|
|
|
|
|
} // namespace tcp
|
|
|
|
} // namespace mtproto
|
|
|
|
} // namespace td
|