1/*
2 This file is part of Mtproto-proxy Library.
3
4 Mtproto-proxy Library is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 Mtproto-proxy Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>.
16
17 Copyright 2010-2013 Vkontakte Ltd
18 2010-2013 Nikolai Durov
19 2010-2013 Andrey Lopatin
20 2013 Vitaliy Valtman
21
22 Copyright 2014-2018 Telegram Messenger Inc
23 2015-2016 Vitaly Valtman
24 2016-2018 Nikolai Durov
25*/
26
27#define _FILE_OFFSET_BITS 64
28
29#include <assert.h>
30#include <string.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <time.h>
34#include <unistd.h>
35
36#include "crc32.h"
37#include "crc32c.h"
38#include "common/sha256.h"
39#include "net/net-events.h"
40#include "kprintf.h"
41#include "precise-time.h"
42#include "net/net-connections.h"
43#include "net/net-tcp-rpc-ext-server.h"
44#include "net/net-tcp-connections.h"
45#include "net/net-thread.h"
46
47#include "rpc-const.h"
48
49#include "net/net-crypto-aes.h"
50//#include "net/net-config.h"
51
52#include "vv/vv-io.h"
53/*
54 *
55 * EXTERNAL RPC SERVER INTERFACE
56 *
57 */
58
59int tcp_rpcs_compact_parse_execute (connection_job_t c);
60
61conn_type_t ct_tcp_rpc_ext_server = {
62 .magic = CONN_FUNC_MAGIC,
63 .flags = C_RAWMSG,
64 .title = "rpc_ext_server",
65 .init_accepted = tcp_rpcs_init_accepted_nohs,
66 .parse_execute = tcp_rpcs_compact_parse_execute,
67 .close = tcp_rpcs_close_connection,
68 .flush = tcp_rpc_flush,
69 .write_packet = tcp_rpc_write_packet_compact,
70 .connected = server_failed,
71 .wakeup = tcp_rpcs_wakeup,
72 .alarm = tcp_rpcs_alarm,
73 .crypto_init = aes_crypto_ctr128_init,
74 .crypto_free = aes_crypto_free,
75 .crypto_encrypt_output = cpu_tcp_aes_crypto_ctr128_encrypt_output,
76 .crypto_decrypt_input = cpu_tcp_aes_crypto_ctr128_decrypt_input,
77 .crypto_needed_output_bytes = cpu_tcp_aes_crypto_ctr128_needed_output_bytes,
78};
79
80int tcp_rpcs_default_execute (connection_job_t c, int op, struct raw_message *msg);
81
82static unsigned char ext_secret[16][16];
83static int ext_secret_cnt = 0;
84
85void tcp_rpcs_set_ext_secret(unsigned char secret[16]) {
86 assert (ext_secret_cnt < 16);
87 memcpy (ext_secret[ext_secret_cnt ++], secret, 16);
88}
89
90/*
91struct tcp_rpc_server_functions default_tcp_rpc_ext_server = {
92 .execute = tcp_rpcs_default_execute,
93 .check_ready = server_check_ready,
94 .flush_packet = tcp_rpc_flush_packet,
95 .rpc_wakeup = tcp_rpcs_do_wakeup,
96 .rpc_alarm = tcp_rpcs_do_wakeup,
97 .rpc_check_perm = tcp_rpcs_default_check_perm,
98 .rpc_init_crypto = tcp_rpcs_init_crypto,
99 .rpc_ready = server_noop,
100};
101*/
102
103int tcp_rpcs_compact_parse_execute (connection_job_t C) {
104 struct tcp_rpc_data *D = TCP_RPC_DATA (C);
105 if (D->crypto_flags & RPCF_COMPACT_OFF) {
106 return tcp_rpcs_parse_execute (C);
107 }
108
109 struct connection_info *c = CONN_INFO (C);
110 int len;
111
112 vkprintf (4, "%s. in_total_bytes = %d\n", __func__, c->in.total_bytes);
113
114 while (1) {
115 if (c->flags & C_ERROR) {
116 return NEED_MORE_BYTES;
117 }
118 if (c->flags & C_STOPPARSE) {
119 return NEED_MORE_BYTES;
120 }
121 len = c->in.total_bytes;
122 if (len <= 0) {
123 return NEED_MORE_BYTES;
124 }
125
126 int min_len = (D->flags & RPC_F_MEDIUM) ? 4 : 1;
127
128 if (len < min_len + 8) {
129 return min_len + 8 - len;
130 }
131
132 int packet_len = 0;
133 assert (rwm_fetch_lookup (&c->in, &packet_len, 4) == 4);
134
135 if (D->in_packet_num == -3) {
136 vkprintf (1, "trying to determine connection type\n");
137#if __ALLOW_UNOBFS__
138 if ((packet_len & 0xff) == 0xef) {
139 D->flags |= RPC_F_COMPACT;
140 assert (rwm_skip_data (&c->in, 1) == 1);
141 D->in_packet_num = 0;
142 vkprintf (1, "Short type\n");
143 continue;
144 }
145 if (packet_len == 0xeeeeeeee) {
146 D->flags |= RPC_F_MEDIUM;
147 assert (rwm_skip_data (&c->in, 4) == 4);
148 D->in_packet_num = 0;
149 vkprintf (1, "Medium type\n");
150 continue;
151 }
152
153 // http
154 if ((packet_len == *(int *)"HEAD" || packet_len == *(int *)"POST" || packet_len == *(int *)"GET " || packet_len == *(int *)"OPTI") && TCP_RPCS_FUNC(C)->http_fallback_type) {
155 D->crypto_flags |= RPCF_COMPACT_OFF;
156 vkprintf (1, "HTTP type\n");
157 return tcp_rpcs_parse_execute (C);
158 }
159
160 int tmp[2];
161 assert (rwm_fetch_lookup (&c->in, &tmp, 8) == 8);
162 if (!tmp[1]) {
163 D->crypto_flags |= RPCF_COMPACT_OFF;
164 vkprintf (1, "Long type\n");
165 return tcp_rpcs_parse_execute (C);
166 }
167#endif
168
169 if (len < 64) {
170#if __ALLOW_UNOBFS__
171 vkprintf (1, "random 64-byte header: first 0x%08x 0x%08x, need %d more bytes to distinguish\n", tmp[0], tmp[1], 64 - len);
172#else
173 vkprintf (1, "\"random\" 64-byte header: have %d bytes, need %d more bytes to distinguish\n", len, 64 - len);
174#endif
175 return 64 - len;
176 }
177
178 unsigned char random_header[64];
179 unsigned char k[48];
180 assert (rwm_fetch_lookup (&c->in, random_header, 64) == 64);
181
182 unsigned char random_header_sav[64];
183 memcpy (random_header_sav, random_header, 64);
184
185 struct aes_key_data key_data;
186
187 int ok = 0;
188 int secret_id;
189 for (secret_id = 0; secret_id < 1 || secret_id < ext_secret_cnt; secret_id++) {
190 if (ext_secret_cnt > 0) {
191 memcpy (k, random_header + 8, 32);
192 memcpy (k + 32, ext_secret[secret_id], 16);
193 sha256 (k, 48, key_data.read_key);
194 } else {
195 memcpy (key_data.read_key, random_header + 8, 32);
196 }
197 memcpy (key_data.read_iv, random_header + 40, 16);
198
199 int i;
200 for (i = 0; i < 32; i++) {
201 key_data.write_key[i] = random_header[55 - i];
202 }
203 for (i = 0; i < 16; i++) {
204 key_data.write_iv[i] = random_header[23 - i];
205 }
206
207 if (ext_secret_cnt > 0) {
208 memcpy (k, key_data.write_key, 32);
209 sha256 (k, 48, key_data.write_key);
210 }
211
212 aes_crypto_ctr128_init (C, &key_data, sizeof (key_data));
213 assert (c->crypto);
214 struct aes_crypto *T = c->crypto;
215
216 T->read_aeskey.type->ctr128_crypt (&T->read_aeskey, random_header, random_header, 64, T->read_iv, T->read_ebuf, &T->read_num);
217 unsigned tag = *(unsigned *)(random_header + 56);
218
219 if (tag == 0xeeeeeeee || tag == 0xefefefef) {
220 assert (rwm_skip_data (&c->in, 64) == 64);
221 rwm_union (&c->in_u, &c->in);
222 rwm_init (&c->in, 0);
223 // T->read_pos = 64;
224 D->in_packet_num = 0;
225 switch (tag) {
226 case 0xeeeeeeee:
227 D->flags |= RPC_F_MEDIUM | RPC_F_EXTMODE2;
228 break;
229 case 0xefefefef:
230 D->flags |= RPC_F_COMPACT | RPC_F_EXTMODE2;
231 break;
232 }
233 assert (c->type->crypto_decrypt_input (C) >= 0);
234
235 int target = *(short *)(random_header + 60);
236 D->extra_int4 = target;
237 vkprintf (1, "tcp opportunistic encryption mode detected, tag = %08x, target=%d\n", tag, target);
238 ok = 1;
239 break;
240 } else {
241 aes_crypto_free (C);
242 memcpy (random_header, random_header_sav, 64);
243 }
244 }
245
246 if (ok) {
247 continue;
248 }
249
250 if (ext_secret_cnt > 0) {
251 vkprintf (1, "invalid \"random\" 64-byte header, entering global skip mode\n");
252 return (-1 << 28);
253 }
254
255#if __ALLOW_UNOBFS__
256 vkprintf (1, "short type with 64-byte header: first 0x%08x 0x%08x\n", tmp[0], tmp[1]);
257 D->flags |= RPC_F_COMPACT | RPC_F_EXTMODE1;
258 D->in_packet_num = 0;
259
260 assert (len >= 64);
261 assert (rwm_skip_data (&c->in, 64) == 64);
262 continue;
263#else
264 vkprintf (1, "invalid \"random\" 64-byte header, entering global skip mode\n");
265 return (-1 << 28);
266#endif
267 }
268
269 int packet_len_bytes = 4;
270 if (D->flags & RPC_F_MEDIUM) {
271 // packet len in `medium` mode
272 if (D->crypto_flags & RPCF_QUICKACK) {
273 D->flags = (D->flags & ~RPC_F_QUICKACK) | (packet_len & RPC_F_QUICKACK);
274 packet_len &= ~RPC_F_QUICKACK;
275 }
276 } else {
277 // packet len in `compact` mode
278 if (packet_len & 0x80) {
279 D->flags |= RPC_F_QUICKACK;
280 packet_len &= ~0x80;
281 } else {
282 D->flags &= ~RPC_F_QUICKACK;
283 }
284 if ((packet_len & 0xff) == 0x7f) {
285 packet_len = ((unsigned) packet_len >> 8);
286 if (packet_len < 0x7f) {
287 vkprintf (1, "error while parsing compact packet: got length %d in overlong encoding\n", packet_len);
288 fail_connection (C, -1);
289 return 0;
290 }
291 } else {
292 packet_len &= 0x7f;
293 packet_len_bytes = 1;
294 }
295 packet_len <<= 2;
296 }
297
298 if (packet_len <= 0 || (packet_len & 0xc0000003)) {
299 vkprintf (1, "error while parsing packet: bad packet length %d\n", packet_len);
300 fail_connection (C, -1);
301 return 0;
302 }
303
304 if ((packet_len > TCP_RPCS_FUNC(C)->max_packet_len && TCP_RPCS_FUNC(C)->max_packet_len > 0)) {
305 vkprintf (1, "error while parsing packet: bad packet length %d\n", packet_len);
306 fail_connection (C, -1);
307 return 0;
308 }
309
310 if (len < packet_len + packet_len_bytes) {
311 return packet_len + packet_len_bytes - len;
312 }
313
314 assert (rwm_skip_data (&c->in, packet_len_bytes) == packet_len_bytes);
315
316 struct raw_message msg;
317 int packet_type;
318
319 rwm_split_head (&msg, &c->in, packet_len);
320
321 assert (rwm_fetch_lookup (&msg, &packet_type, 4) == 4);
322
323 if (D->in_packet_num < 0) {
324 assert (D->in_packet_num == -3);
325 D->in_packet_num = 0;
326 }
327
328 if (verbosity > 2) {
329 fprintf (stderr, "received packet from connection %d (length %d, num %d, type %08x)\n", c->fd, packet_len, D->in_packet_num, packet_type);
330 rwm_dump (&msg);
331 }
332
333 int res = -1;
334
335 /* main case */
336 c->last_response_time = precise_now;
337 if (packet_type == RPC_PING) {
338 res = tcp_rpcs_default_execute (C, packet_type, &msg);
339 } else {
340 res = TCP_RPCS_FUNC(C)->execute (C, packet_type, &msg);
341 }
342 if (res <= 0) {
343 rwm_free (&msg);
344 }
345
346 D->in_packet_num++;
347 }
348 return NEED_MORE_BYTES;
349}
350
351/*
352 *
353 * END (EXTERNAL RPC SERVER)
354 *
355 */
356