mirror of
https://github.com/alexbers/mtprotoproxy.git
synced 2026-03-21 10:05:49 +00:00
multiaccounting
This commit is contained in:
11
config.py
11
config.py
@@ -1,5 +1,10 @@
|
|||||||
PORT = 3256
|
PORT = 3256
|
||||||
|
|
||||||
# use only these chars in SECRET: 0123456789abcdef
|
# name -> secret (32 hex chars)
|
||||||
# the length of secret should be 32
|
USERS = {
|
||||||
SECRET = '00000000000000000000000000000000'
|
"tg": "00000000000000000000000000000000",
|
||||||
|
"tg2": "0123456789abcdef0123456789abcdef"
|
||||||
|
}
|
||||||
|
|
||||||
|
# disables transit traffic reencryption, faster but less secure
|
||||||
|
FAST_MODE = False
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import random
|
|||||||
|
|
||||||
import pyaes
|
import pyaes
|
||||||
|
|
||||||
from config import PORT, SECRET
|
from config import PORT, USERS, FAST_MODE
|
||||||
|
|
||||||
TG_DATACENTERS = [
|
TG_DATACENTERS = [
|
||||||
"149.154.175.50", "149.154.167.51", "149.154.175.100",
|
"149.154.175.50", "149.154.167.51", "149.154.175.100",
|
||||||
@@ -30,48 +30,53 @@ IV_LEN = 16
|
|||||||
|
|
||||||
def init_stats():
|
def init_stats():
|
||||||
global stats
|
global stats
|
||||||
stats = collections.Counter()
|
stats = {user: collections.Counter() for user in USERS}
|
||||||
|
|
||||||
|
|
||||||
def update_stats(connects=0, curr_connects_x2=0, octets=0):
|
def update_stats(user, connects=0, curr_connects_x2=0, octets=0):
|
||||||
global stats
|
global stats
|
||||||
|
|
||||||
stats.update(connects=connects, curr_connects_x2=curr_connects_x2,
|
if user not in stats:
|
||||||
octets=octets)
|
stats[user] = collections.Counter()
|
||||||
|
|
||||||
|
stats[user].update(connects=connects, curr_connects_x2=curr_connects_x2,
|
||||||
|
octets=octets)
|
||||||
|
|
||||||
|
|
||||||
async def handle_handshake(reader, writer):
|
async def handle_handshake(reader, writer):
|
||||||
secret = bytes.fromhex(SECRET)
|
|
||||||
|
|
||||||
handshake = await reader.readexactly(64)
|
handshake = await reader.readexactly(64)
|
||||||
|
|
||||||
dec_prekey_and_iv = handshake[SKIP_LEN:SKIP_LEN+PREKEY_LEN+IV_LEN]
|
for user in USERS:
|
||||||
dec_prekey, dec_iv = dec_prekey_and_iv[:PREKEY_LEN], dec_prekey_and_iv[PREKEY_LEN:]
|
secret = bytes.fromhex(USERS[user])
|
||||||
dec_key = hashlib.sha256(dec_prekey + secret).digest()
|
|
||||||
dec_ctr = pyaes.Counter(int.from_bytes(dec_iv, "big"))
|
|
||||||
decryptor = pyaes.AESModeOfOperationCTR(dec_key, dec_ctr)
|
|
||||||
|
|
||||||
enc_prekey_and_iv = handshake[SKIP_LEN:SKIP_LEN+PREKEY_LEN+IV_LEN][::-1]
|
dec_prekey_and_iv = handshake[SKIP_LEN:SKIP_LEN+PREKEY_LEN+IV_LEN]
|
||||||
enc_prekey, enc_iv = enc_prekey_and_iv[:PREKEY_LEN], enc_prekey_and_iv[PREKEY_LEN:]
|
dec_prekey, dec_iv = dec_prekey_and_iv[:PREKEY_LEN], dec_prekey_and_iv[PREKEY_LEN:]
|
||||||
enc_key = hashlib.sha256(enc_prekey + secret).digest()
|
dec_key = hashlib.sha256(dec_prekey + secret).digest()
|
||||||
enc_ctr = pyaes.Counter(int.from_bytes(enc_iv, "big"))
|
dec_ctr = pyaes.Counter(int.from_bytes(dec_iv, "big"))
|
||||||
encryptor = pyaes.AESModeOfOperationCTR(enc_key, enc_ctr)
|
decryptor = pyaes.AESModeOfOperationCTR(dec_key, dec_ctr)
|
||||||
|
|
||||||
decrypted = decryptor.decrypt(handshake)
|
enc_prekey_and_iv = handshake[SKIP_LEN:SKIP_LEN+PREKEY_LEN+IV_LEN][::-1]
|
||||||
|
enc_prekey, enc_iv = enc_prekey_and_iv[:PREKEY_LEN], enc_prekey_and_iv[PREKEY_LEN:]
|
||||||
MAGIC_VAL = b'\xef\xef\xef\xef'
|
enc_key = hashlib.sha256(enc_prekey + secret).digest()
|
||||||
check_val = decrypted[56:60]
|
enc_ctr = pyaes.Counter(int.from_bytes(enc_iv, "big"))
|
||||||
if check_val != MAGIC_VAL:
|
encryptor = pyaes.AESModeOfOperationCTR(enc_key, enc_ctr)
|
||||||
return False
|
|
||||||
|
|
||||||
dc_idx = int.from_bytes(decrypted[60:62], "little") - 1
|
decrypted = decryptor.decrypt(handshake)
|
||||||
|
|
||||||
|
MAGIC_VAL = b'\xef\xef\xef\xef'
|
||||||
|
check_val = decrypted[56:60]
|
||||||
|
if check_val != MAGIC_VAL:
|
||||||
|
continue
|
||||||
|
|
||||||
if dc_idx < 0 or dc_idx >= len(TG_DATACENTERS):
|
dc_idx = int.from_bytes(decrypted[60:62], "little") - 1
|
||||||
return False
|
|
||||||
|
|
||||||
dc = TG_DATACENTERS[dc_idx]
|
if dc_idx < 0 or dc_idx >= len(TG_DATACENTERS):
|
||||||
|
continue
|
||||||
|
|
||||||
return encryptor, decryptor, dc
|
dc = TG_DATACENTERS[dc_idx]
|
||||||
|
|
||||||
|
return encryptor, decryptor, user, dc
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
async def do_handshake(dc):
|
async def do_handshake(dc):
|
||||||
@@ -116,9 +121,9 @@ async def handle_client(reader, writer):
|
|||||||
writer.close()
|
writer.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
clt_enc, clt_dec, dc = clt_data
|
clt_enc, clt_dec, user, dc = clt_data
|
||||||
|
|
||||||
update_stats(connects=1)
|
update_stats(user, connects=1)
|
||||||
|
|
||||||
tg_data = await do_handshake(dc)
|
tg_data = await do_handshake(dc)
|
||||||
if not tg_data:
|
if not tg_data:
|
||||||
@@ -127,8 +132,8 @@ async def handle_client(reader, writer):
|
|||||||
|
|
||||||
tg_enc, tg_dec, reader_tg, writer_tg = tg_data
|
tg_enc, tg_dec, reader_tg, writer_tg = tg_data
|
||||||
|
|
||||||
async def connect_reader_to_writer(rd, wr, rd_dec, wr_enc):
|
async def connect_reader_to_writer(rd, wr, rd_dec, wr_enc, user):
|
||||||
update_stats(curr_connects_x2=1)
|
update_stats(user, curr_connects_x2=1)
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
data = await rd.read(READ_BUF_SIZE)
|
data = await rd.read(READ_BUF_SIZE)
|
||||||
@@ -138,7 +143,7 @@ async def handle_client(reader, writer):
|
|||||||
wr.close()
|
wr.close()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
update_stats(octets=len(data))
|
update_stats(user, octets=len(data))
|
||||||
dec_data = rd_dec.decrypt(data)
|
dec_data = rd_dec.decrypt(data)
|
||||||
# print("PROXYING", len(dec_data), dec_data)
|
# print("PROXYING", len(dec_data), dec_data)
|
||||||
reenc_data = wr_enc.encrypt(dec_data)
|
reenc_data = wr_enc.encrypt(dec_data)
|
||||||
@@ -149,10 +154,10 @@ async def handle_client(reader, writer):
|
|||||||
wr.close()
|
wr.close()
|
||||||
# print(e)
|
# print(e)
|
||||||
finally:
|
finally:
|
||||||
update_stats(curr_connects_x2=-1)
|
update_stats(user, curr_connects_x2=-1)
|
||||||
|
|
||||||
asyncio.ensure_future(connect_reader_to_writer(reader_tg, writer, tg_dec, clt_enc))
|
asyncio.ensure_future(connect_reader_to_writer(reader_tg, writer, tg_dec, clt_enc, user))
|
||||||
asyncio.ensure_future(connect_reader_to_writer(reader, writer_tg, clt_dec, tg_enc))
|
asyncio.ensure_future(connect_reader_to_writer(reader, writer_tg, clt_dec, tg_enc, user))
|
||||||
|
|
||||||
|
|
||||||
async def handle_client_wrapper(reader, writer):
|
async def handle_client_wrapper(reader, writer):
|
||||||
@@ -168,9 +173,10 @@ async def stats_printer():
|
|||||||
await asyncio.sleep(STATS_PRINT_PERIOD)
|
await asyncio.sleep(STATS_PRINT_PERIOD)
|
||||||
|
|
||||||
print("Stats for", time.strftime("%d.%m.%Y %H:%M:%S"))
|
print("Stats for", time.strftime("%d.%m.%Y %H:%M:%S"))
|
||||||
print("%d connects (%d current), %.2f MB" % (
|
for user, stat in stats.items():
|
||||||
stats["connects"], stats["curr_connects_x2"] // 2,
|
print("%s: %d connects (%d current), %.2f MB" % (
|
||||||
stats["octets"] / 1000000))
|
user, stat["connects"], stat["curr_connects_x2"] // 2,
|
||||||
|
stat["octets"] / 1000000))
|
||||||
print(flush=True)
|
print(flush=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -187,10 +193,11 @@ def print_tg_info():
|
|||||||
if ip_is_local:
|
if ip_is_local:
|
||||||
my_ip = "YOUR_IP"
|
my_ip = "YOUR_IP"
|
||||||
|
|
||||||
params = {
|
for user, secret in USERS.items():
|
||||||
"server": my_ip, "port": PORT, "secret": SECRET
|
params = {
|
||||||
}
|
"server": my_ip, "port": PORT, "secret": secret
|
||||||
print("tg://proxy?" + urllib.parse.urlencode(params), flush=True)
|
}
|
||||||
|
print("tg://proxy?" + urllib.parse.urlencode(params), flush=True)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
Reference in New Issue
Block a user