Skip to content

Commit

Permalink
Merge pull request TelegramMessenger#5 from TelegramMessenger/master
Browse files Browse the repository at this point in the history
u
  • Loading branch information
saturn99 authored Aug 12, 2018
2 parents 9e02810 + f9158e3 commit 2b0cfff
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 13 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ Also feel free to check out other options using `mtproto-proxy --help`.
7. Set received tag with arguments: `-P <proxy tag>`
8. Enjoy.

## Random padding
Due to some ISPs detecting MTProxy by packet sizes, random padding is
added to packets if such mode is enabled.

It's only enabled for clients which request it.

Add `dd` prefix to secret (`cafe...babe` => `ddcafe...babe`) to enable
this mode on client side.

## Systemd example configuration
1. Create systemd service file (it's standart path for the most Linux distros, but you should check it before):
```bash
Expand Down Expand Up @@ -97,3 +106,4 @@ systemctl enable MTProxy.service

## Docker image
Telegram is also providing [official Docker image](https://hub.docker.com/r/telegrammessenger/proxy/).
Note: the image is outdated.
43 changes: 35 additions & 8 deletions mtproto/mtproto-proxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,11 +789,38 @@ static int _notify_remote_closed (JOB_REF_ARG(C), long long out_conn_id) {
}

void push_rpc_confirmation (JOB_REF_ARG (C), int confirm) {
struct raw_message *msg = malloc (sizeof (struct raw_message));
rwm_create (msg, "\xdd", 1);
rwm_push_data (msg, &confirm, 4);
mpq_push_w (CONN_INFO(C)->out_queue, msg, 0);
job_signal (JOB_REF_PASS (C), JS_RUN);

if ((lrand48_j() & 1) || !(TCP_RPC_DATA(C)->flags & RPC_F_PAD)) {
struct raw_message *msg = malloc (sizeof (struct raw_message));
rwm_create (msg, "\xdd", 1);
rwm_push_data (msg, &confirm, 4);
mpq_push_w (CONN_INFO(C)->out_queue, msg, 0);
job_signal (JOB_REF_PASS (C), JS_RUN);
} else {
int x = -1;
struct raw_message m;
assert (rwm_create (&m, &x, 4) == 4);
assert (rwm_push_data (&m, &confirm, 4) == 4);

int z = lrand48_j() & 1;
while (z-- > 0) {
int t = lrand48_j();
assert (rwm_push_data (&m, &t, 4) == 4);
}

tcp_rpc_conn_send (JOB_REF_CREATE_PASS (C), &m, 0);

x = 0;
assert (rwm_create (&m, &x, 4) == 4);

z = lrand48_j() & 1;
while (z-- > 0) {
int t = lrand48_j();
assert (rwm_push_data (&m, &t, 4) == 4);
}

tcp_rpc_conn_send (JOB_REF_PASS (C), &m, 0);
}
}

struct client_packet_info {
Expand Down Expand Up @@ -1645,7 +1672,7 @@ conn_target_job_t choose_proxy_target (int target_dc) {
}

static int forward_mtproto_enc_packet (struct tl_in_state *tlio_in, connection_job_t C, long long auth_key_id, int len, int remote_ip_port[5], int rpc_flags) {
if (len < offsetof (struct encrypted_message, message) || (len & 15) != (offsetof (struct encrypted_message, server_salt) & 15)) {
if (len < offsetof (struct encrypted_message, message) /*|| (len & 15) != (offsetof (struct encrypted_message, server_salt) & 15)*/) {
return 0;
}
vkprintf (2, "received mtproto encrypted packet of %d bytes from connection %p (#%d~%d), key=%016llx\n", len, C, CONN_INFO(C)->fd, CONN_INFO(C)->generation, auth_key_id);
Expand All @@ -1670,11 +1697,11 @@ int forward_mtproto_packet (struct tl_in_state *tlio_in, connection_job_t C, int
}
vkprintf (2, "received mtproto packet of %d bytes\n", len);
int inner_len = header[4];
if (inner_len + 20 != len) {
if (inner_len + 20 > len) {
vkprintf (1, "received packet with bad inner length: %d (%d expected)\n", inner_len, len - 20);
return 0;
}
if (len < 40) {
if (inner_len < 20) {
//must have at least function id and nonce
return 0;
}
Expand Down
11 changes: 10 additions & 1 deletion net/net-tcp-rpc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,17 @@ int tcp_rpc_write_packet_compact (connection_job_t C, struct raw_message *raw) {
return tcp_rpc_write_packet (C, raw);
}

if (TCP_RPC_DATA(C)->flags & RPC_F_PAD) {
int x = lrand48_j();
int y = lrand48_j() & 3;
assert (rwm_push_data (raw, &x, y) == y);
}

int len = raw->total_bytes;
assert (!(len & 0xfc000003));
assert (!(len & 0xfc000000));
if (!(TCP_RPC_DATA(C)->flags & RPC_F_PAD)) {
assert (!(len & 3));
}
if (TCP_RPC_DATA(C)->flags & RPC_F_MEDIUM) {
rwm_push_data_front (raw, &len, 4);
} else if (len <= 0x7e * 4) {
Expand Down
1 change: 1 addition & 0 deletions net/net-tcp-rpc-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ int tcp_rpc_default_execute (connection_job_t C, int op, struct raw_message *raw
#define RPCF_USE_CRC32C 2048

/* for flags in struct tcp_rpc_data */
#define RPC_F_PAD 0x8000000
#define RPC_F_DROPPED 0x10000000
#define RPC_F_MEDIUM 0x20000000
#define RPC_F_COMPACT 0x40000000
Expand Down
21 changes: 17 additions & 4 deletions net/net-tcp-rpc-ext-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ int tcp_rpcs_compact_parse_execute (connection_job_t C) {
vkprintf (1, "Medium type\n");
continue;
}
if (packet_len == 0xdddddddd) {
D->flags |= RPC_F_MEDIUM | RPC_F_PAD;
assert (rwm_skip_data (&c->in, 4) == 4);
D->in_packet_num = 0;
vkprintf (1, "Medium type\n");
continue;
}

// http
if ((packet_len == *(int *)"HEAD" || packet_len == *(int *)"POST" || packet_len == *(int *)"GET " || packet_len == *(int *)"OPTI") && TCP_RPCS_FUNC(C)->http_fallback_type) {
Expand Down Expand Up @@ -216,7 +223,7 @@ int tcp_rpcs_compact_parse_execute (connection_job_t C) {
T->read_aeskey.type->ctr128_crypt (&T->read_aeskey, random_header, random_header, 64, T->read_iv, T->read_ebuf, &T->read_num);
unsigned tag = *(unsigned *)(random_header + 56);

if (tag == 0xeeeeeeee || tag == 0xefefefef) {
if (tag == 0xdddddddd || tag == 0xeeeeeeee || tag == 0xefefefef) {
assert (rwm_skip_data (&c->in, 64) == 64);
rwm_union (&c->in_u, &c->in);
rwm_init (&c->in, 0);
Expand All @@ -226,6 +233,9 @@ int tcp_rpcs_compact_parse_execute (connection_job_t C) {
case 0xeeeeeeee:
D->flags |= RPC_F_MEDIUM | RPC_F_EXTMODE2;
break;
case 0xdddddddd:
D->flags |= RPC_F_MEDIUM | RPC_F_EXTMODE2 | RPC_F_PAD;
break;
case 0xefefefef:
D->flags |= RPC_F_COMPACT | RPC_F_EXTMODE2;
break;
Expand Down Expand Up @@ -269,10 +279,10 @@ int tcp_rpcs_compact_parse_execute (connection_job_t C) {
int packet_len_bytes = 4;
if (D->flags & RPC_F_MEDIUM) {
// packet len in `medium` mode
if (D->crypto_flags & RPCF_QUICKACK) {
//if (D->crypto_flags & RPCF_QUICKACK) {
D->flags = (D->flags & ~RPC_F_QUICKACK) | (packet_len & RPC_F_QUICKACK);
packet_len &= ~RPC_F_QUICKACK;
}
//}
} else {
// packet len in `compact` mode
if (packet_len & 0x80) {
Expand All @@ -295,7 +305,7 @@ int tcp_rpcs_compact_parse_execute (connection_job_t C) {
packet_len <<= 2;
}

if (packet_len <= 0 || (packet_len & 0xc0000003)) {
if (packet_len <= 0 || (packet_len & 0xc0000000) || (!(D->flags & RPC_F_PAD) && (packet_len & 3))) {
vkprintf (1, "error while parsing packet: bad packet length %d\n", packet_len);
fail_connection (C, -1);
return 0;
Expand All @@ -317,6 +327,9 @@ int tcp_rpcs_compact_parse_execute (connection_job_t C) {
int packet_type;

rwm_split_head (&msg, &c->in, packet_len);
if (D->flags & RPC_F_PAD) {
rwm_trunc (&msg, packet_len & -4);
}

assert (rwm_fetch_lookup (&msg, &packet_type, 4) == 4);

Expand Down

0 comments on commit 2b0cfff

Please sign in to comment.