even more protect against replay-based fingerprinting

This commit is contained in:
Alexander Bersenev
2019-04-20 15:02:13 +05:00
parent 4cae6290b9
commit f55ae68092

View File

@@ -46,6 +46,9 @@ SECURE_ONLY = config.get("SECURE_ONLY", False)
# length of used handshake randoms for active fingerprinting protection # length of used handshake randoms for active fingerprinting protection
REPLAY_CHECK_LEN = config.get("REPLAY_CHECK_LEN", 32768) 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 # delay in seconds between stats printing
STATS_PRINT_PERIOD = config.get("STATS_PRINT_PERIOD", 600) 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} my_ip_info = {"ipv4": None, "ipv6": None}
used_handshakes = collections.OrderedDict() used_handshakes = collections.OrderedDict()
def setup_files_limit(): def setup_files_limit():
try: try:
import resource 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_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) 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: try:
clt_data = await asyncio.wait_for(handle_handshake(reader_clt, writer_clt), clt_data = await asyncio.wait_for(handle_handshake(reader_clt, writer_clt),
timeout=CLIENT_HANDSHAKE_TIMEOUT) timeout=CLIENT_HANDSHAKE_TIMEOUT)
@@ -948,7 +953,6 @@ async def handle_client(reader_clt, writer_clt):
else: else:
tg_data = await do_direct_handshake(proto_tag, dc_idx) tg_data = await do_direct_handshake(proto_tag, dc_idx)
else: 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) tg_data = await do_middleproxy_handshake(proto_tag, dc_idx, cl_ip, cl_port)
if not tg_data: if not tg_data:
@@ -981,7 +985,8 @@ async def handle_client(reader_clt, writer_clt):
else: else:
return 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: try:
while True: while True:
data = await rd.read(rd_buf_size) data = await rd.read(rd_buf_size)
@@ -990,6 +995,19 @@ async def handle_client(reader_clt, writer_clt):
else: else:
extra = {} 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: if not data:
wr.write_eof() wr.write_eof()
await wr.drain() await wr.drain()
@@ -1002,7 +1020,8 @@ async def handle_client(reader_clt, writer_clt):
# print_err(e) # print_err(e)
pass 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) 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_tg_to_clt = asyncio.ensure_future(tg_to_clt)
task_clt_to_tg = asyncio.ensure_future(clt_to_tg) task_clt_to_tg = asyncio.ensure_future(clt_to_tg)