From f55ae68092b4f07e247baa18ad35b014380a9eeb Mon Sep 17 00:00:00 2001 From: Alexander Bersenev Date: Sat, 20 Apr 2019 15:02:13 +0500 Subject: [PATCH] even more protect against replay-based fingerprinting --- mtprotoproxy.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/mtprotoproxy.py b/mtprotoproxy.py index 18e87f1..29db673 100755 --- a/mtprotoproxy.py +++ b/mtprotoproxy.py @@ -46,6 +46,9 @@ SECURE_ONLY = config.get("SECURE_ONLY", False) # length of used handshake randoms for active fingerprinting protection REPLAY_CHECK_LEN = config.get("REPLAY_CHECK_LEN", 32768) +# block short first packets to even more protect against replay-based fingerprinting +BLOCK_SHORT_FIRST_PKT = config.get("BLOCK_SHORT_FIRST_PKT", True) + # delay in seconds between stats printing STATS_PRINT_PERIOD = config.get("STATS_PRINT_PERIOD", 600) @@ -135,6 +138,7 @@ MAX_MSG_LEN = 2 ** 24 my_ip_info = {"ipv4": None, "ipv6": None} used_handshakes = collections.OrderedDict() + def setup_files_limit(): try: import resource @@ -929,6 +933,7 @@ async def handle_client(reader_clt, writer_clt): set_ack_timeout(writer_clt.get_extra_info("socket"), CLIENT_ACK_TIMEOUT) set_bufsizes(writer_clt.get_extra_info("socket"), TO_TG_BUFSIZE, TO_CLT_BUFSIZE) + cl_ip, cl_port = writer_clt.get_extra_info('peername')[:2] try: clt_data = await asyncio.wait_for(handle_handshake(reader_clt, writer_clt), timeout=CLIENT_HANDSHAKE_TIMEOUT) @@ -948,7 +953,6 @@ async def handle_client(reader_clt, writer_clt): else: tg_data = await do_direct_handshake(proto_tag, dc_idx) else: - cl_ip, cl_port = writer_clt.upstream.get_extra_info('peername')[:2] tg_data = await do_middleproxy_handshake(proto_tag, dc_idx, cl_ip, cl_port) if not tg_data: @@ -981,7 +985,8 @@ async def handle_client(reader_clt, writer_clt): else: return - async def connect_reader_to_writer(rd, wr, user, rd_buf_size): + async def connect_reader_to_writer(rd, wr, user, rd_buf_size, block_short_first_pkt=False): + is_first_pkt = True try: while True: data = await rd.read(rd_buf_size) @@ -990,6 +995,19 @@ async def handle_client(reader_clt, writer_clt): else: extra = {} + if is_first_pkt: + # protection against replay-based fingerprinting + MIN_FIRST_PKT_SIZE = 12 + if block_short_first_pkt and 0 < len(data) < MIN_FIRST_PKT_SIZE: + print_err("Active fingerprinting detected from %s, dropping it" % cl_ip) + print_err("If this causes problems set BLOCK_SHORT_FIRST_PKT = False " + "in the config") + + wr.write_eof() + await wr.drain() + return + is_first_pkt = False + if not data: wr.write_eof() await wr.drain() @@ -1002,7 +1020,8 @@ async def handle_client(reader_clt, writer_clt): # print_err(e) pass - tg_to_clt = connect_reader_to_writer(reader_tg, writer_clt, user, TO_CLT_BUFSIZE) + tg_to_clt = connect_reader_to_writer(reader_tg, writer_clt, user, TO_CLT_BUFSIZE, + block_short_first_pkt=BLOCK_SHORT_FIRST_PKT) clt_to_tg = connect_reader_to_writer(reader_clt, writer_tg, user, TO_TG_BUFSIZE) task_tg_to_clt = asyncio.ensure_future(tg_to_clt) task_clt_to_tg = asyncio.ensure_future(clt_to_tg)