1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #include "mtproto/connection_abstract.h"
9
10 #include "mtproto/connection_tcp.h"
11 #include "mtproto/connection_http.h"
12 #include "mtproto/connection_resolving.h"
13 #include "mtproto/session.h"
14 #include "base/unixtime.h"
15 #include "base/random.h"
16
17 namespace MTP {
18 namespace details {
19
20 ConnectionPointer::ConnectionPointer() = default;
21
ConnectionPointer(std::nullptr_t)22 ConnectionPointer::ConnectionPointer(std::nullptr_t) {
23 }
24
ConnectionPointer(AbstractConnection * value)25 ConnectionPointer::ConnectionPointer(AbstractConnection *value)
26 : _value(value) {
27 }
28
ConnectionPointer(ConnectionPointer && other)29 ConnectionPointer::ConnectionPointer(ConnectionPointer &&other)
30 : _value(base::take(other._value)) {
31 }
32
operator =(ConnectionPointer && other)33 ConnectionPointer &ConnectionPointer::operator=(ConnectionPointer &&other) {
34 reset(base::take(other._value));
35 return *this;
36 }
37
get() const38 AbstractConnection *ConnectionPointer::get() const {
39 return _value;
40 }
41
reset(AbstractConnection * value)42 void ConnectionPointer::reset(AbstractConnection *value) {
43 if (_value == value) {
44 return;
45 } else if (const auto old = base::take(_value)) {
46 const auto disconnect = [&](auto signal) {
47 old->disconnect(old, signal, nullptr, nullptr);
48 };
49 disconnect(&AbstractConnection::receivedData);
50 disconnect(&AbstractConnection::receivedSome);
51 disconnect(&AbstractConnection::error);
52 disconnect(&AbstractConnection::connected);
53 disconnect(&AbstractConnection::disconnected);
54 old->disconnectFromServer();
55 old->deleteLater();
56 }
57 _value = value;
58 }
59
operator AbstractConnection*() const60 ConnectionPointer::operator AbstractConnection*() const {
61 return get();
62 }
63
operator ->() const64 AbstractConnection *ConnectionPointer::operator->() const {
65 return get();
66 }
67
operator *() const68 AbstractConnection &ConnectionPointer::operator*() const {
69 return *get();
70 }
71
operator bool() const72 ConnectionPointer::operator bool() const {
73 return get() != nullptr;
74 }
75
~ConnectionPointer()76 ConnectionPointer::~ConnectionPointer() {
77 reset();
78 }
79
prepareSecurePacket(uint64 keyId,MTPint128 msgKey,uint32 size) const80 mtpBuffer AbstractConnection::prepareSecurePacket(
81 uint64 keyId,
82 MTPint128 msgKey,
83 uint32 size) const {
84 auto result = mtpBuffer();
85 constexpr auto kTcpPrefixInts = 2;
86 constexpr auto kAuthKeyIdPosition = kTcpPrefixInts;
87 constexpr auto kAuthKeyIdInts = 2;
88 constexpr auto kMessageKeyPosition = kAuthKeyIdPosition
89 + kAuthKeyIdInts;
90 constexpr auto kMessageKeyInts = 4;
91 constexpr auto kPrefixInts = kTcpPrefixInts
92 + kAuthKeyIdInts
93 + kMessageKeyInts;
94 constexpr auto kTcpPostfixInts = 4;
95 result.reserve(kPrefixInts + size + kTcpPostfixInts);
96 result.resize(kPrefixInts);
97 *reinterpret_cast<uint64*>(&result[kAuthKeyIdPosition]) = keyId;
98 *reinterpret_cast<MTPint128*>(&result[kMessageKeyPosition]) = msgKey;
99 return result;
100 }
101
parseNotSecureResponse(const mtpBuffer & buffer) const102 gsl::span<const mtpPrime> AbstractConnection::parseNotSecureResponse(
103 const mtpBuffer &buffer) const {
104 const auto answer = buffer.data();
105 const auto len = buffer.size();
106 if (len < 6) {
107 LOG(("Not Secure Error: bad request answer, len = %1"
108 ).arg(len * sizeof(mtpPrime)));
109 DEBUG_LOG(("Not Secure Error: answer bytes %1"
110 ).arg(Logs::mb(answer, len * sizeof(mtpPrime)).str()));
111 return {};
112 }
113 if (answer[0] != 0
114 || answer[1] != 0
115 || (((uint32)answer[2]) & 0x03) != 1
116 //|| (base::unixtime::now() - answer[3] > 300) // We didn't sync time yet.
117 //|| (answer[3] - base::unixtime::now() > 60)
118 || false) {
119 LOG(("Not Secure Error: bad request answer start (%1 %2 %3)"
120 ).arg(answer[0]
121 ).arg(answer[1]
122 ).arg(answer[2]));
123 DEBUG_LOG(("Not Secure Error: answer bytes %1"
124 ).arg(Logs::mb(answer, len * sizeof(mtpPrime)).str()));
125 return {};
126 }
127 const auto answerLen = (uint32)answer[4];
128 if (answerLen < 1 || answerLen > (len - 5) * sizeof(mtpPrime)) {
129 LOG(("Not Secure Error: bad request answer 1 <= %1 <= %2"
130 ).arg(answerLen
131 ).arg((len - 5) * sizeof(mtpPrime)));
132 DEBUG_LOG(("Not Secure Error: answer bytes %1"
133 ).arg(Logs::mb(answer, len * sizeof(mtpPrime)).str()));
134 return {};
135 }
136 return gsl::make_span(answer + 5, answerLen);
137 }
138
preparePQFake(const MTPint128 & nonce) const139 mtpBuffer AbstractConnection::preparePQFake(const MTPint128 &nonce) const {
140 return prepareNotSecurePacket(
141 MTPReq_pq(nonce),
142 base::unixtime::mtproto_msg_id());
143 }
144
readPQFakeReply(const mtpBuffer & buffer) const145 std::optional<MTPResPQ> AbstractConnection::readPQFakeReply(
146 const mtpBuffer &buffer) const {
147 const auto answer = parseNotSecureResponse(buffer);
148 if (answer.empty()) {
149 return std::nullopt;
150 }
151 auto from = answer.data();
152 MTPResPQ response;
153 return response.read(from, from + answer.size())
154 ? std::make_optional(response)
155 : std::nullopt;
156 }
157
AbstractConnection(QThread * thread,const ProxyData & proxy)158 AbstractConnection::AbstractConnection(
159 QThread *thread,
160 const ProxyData &proxy)
161 : _proxy(proxy) {
162 moveToThread(thread);
163 }
164
Create(not_null<Instance * > instance,DcOptions::Variants::Protocol protocol,QThread * thread,const bytes::vector & secret,const ProxyData & proxy)165 ConnectionPointer AbstractConnection::Create(
166 not_null<Instance*> instance,
167 DcOptions::Variants::Protocol protocol,
168 QThread *thread,
169 const bytes::vector &secret,
170 const ProxyData &proxy) {
171 auto result = [&] {
172 if (protocol == DcOptions::Variants::Tcp) {
173 return ConnectionPointer::New<TcpConnection>(
174 instance,
175 thread,
176 proxy);
177 } else {
178 return ConnectionPointer::New<HttpConnection>(thread, proxy);
179 }
180 }();
181 if (proxy.tryCustomResolve()) {
182 return ConnectionPointer::New<ResolvingConnection>(
183 instance,
184 thread,
185 proxy,
186 std::move(result));
187 }
188 return result;
189 }
190
extendedNotSecurePadding() const191 uint32 AbstractConnection::extendedNotSecurePadding() const {
192 return uint32(base::RandomValue<uchar>() & 0x3F);
193 }
194
195 } // namespace details
196 } // namespace MTP
197