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