mirror of
https://github.com/alexbers/mtprotoproxy.git
synced 2026-03-13 23:03:09 +00:00
update middle proxy addrs and secret every 24 hours
This commit is contained in:
126
mtprotoproxy.py
126
mtprotoproxy.py
@@ -10,6 +10,7 @@ import hashlib
|
|||||||
import random
|
import random
|
||||||
import binascii
|
import binascii
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -68,6 +69,7 @@ PREFER_IPV6 = getattr(config, "PREFER_IPV6", socket.has_ipv6)
|
|||||||
# disables tg->client trafic reencryption, faster but less secure
|
# disables tg->client trafic reencryption, faster but less secure
|
||||||
FAST_MODE = getattr(config, "FAST_MODE", True)
|
FAST_MODE = getattr(config, "FAST_MODE", True)
|
||||||
STATS_PRINT_PERIOD = getattr(config, "STATS_PRINT_PERIOD", 600)
|
STATS_PRINT_PERIOD = getattr(config, "STATS_PRINT_PERIOD", 600)
|
||||||
|
PROXY_INFO_UPDATE_PERIOD = getattr(config, "PROXY_INFO_UPDATE_PERIOD", 60*60*24)
|
||||||
READ_BUF_SIZE = getattr(config, "READ_BUF_SIZE", 4096)
|
READ_BUF_SIZE = getattr(config, "READ_BUF_SIZE", 4096)
|
||||||
AD_TAG = bytes.fromhex(getattr(config, "AD_TAG", ""))
|
AD_TAG = bytes.fromhex(getattr(config, "AD_TAG", ""))
|
||||||
|
|
||||||
@@ -83,18 +85,22 @@ TG_DATACENTERS_V6 = [
|
|||||||
"2001:67c:04e8:f004::a", "2001:b28:f23f:f005::a"
|
"2001:67c:04e8:f004::a", "2001:b28:f23f:f005::a"
|
||||||
]
|
]
|
||||||
|
|
||||||
TG_MIDDLE_PROXIES_V4 = [
|
# This list will be updated in the runtime
|
||||||
("149.154.175.50", 8888), ("149.154.162.38", 80), ("149.154.175.100", 8888),
|
TG_MIDDLE_PROXIES_V4 = {
|
||||||
("91.108.4.136", 8888), ("91.108.56.181", 8888)
|
1: [("149.154.175.50", 8888)], -1: [("149.154.175.50", 8888)],
|
||||||
]
|
2: [("149.154.162.38", 80)], -2: [("149.154.162.38", 80)],
|
||||||
|
3: [("149.154.175.100", 8888)], -3: [("149.154.175.100", 8888)],
|
||||||
|
4: [("91.108.4.136", 8888)], -4: [("91.108.4.136", 8888)],
|
||||||
|
5: [("91.108.56.181", 8888)], -5: [("91.108.56.181", 8888)]
|
||||||
|
}
|
||||||
|
|
||||||
TG_MIDDLE_PROXIES_V6 = [
|
TG_MIDDLE_PROXIES_V6 = {
|
||||||
("2001:0b28:f23d:f001:0000:0000:0000:000d", 8888),
|
1: [("2001:b28:f23d:f001::d", 8888)], -1: [("2001:b28:f23d:f001::d", 8888)],
|
||||||
("2001:067c:04e8:f002:0000:0000:0000:000d", 80),
|
2: [("2001:67c:04e8:f002::d", 80)], -2: [("2001:67c:04e8:f002::d", 80)],
|
||||||
("2001:0b28:f23d:f003:0000:0000:0000:000d", 8888),
|
3: [("2001:b28:f23d:f003::d", 8888)], -3: [("2001:b28:f23d:f003::d", 8888)],
|
||||||
("2001:067c:04e8:f004:0000:0000:0000:000d", 8888),
|
4: [("2001:67c:04e8:f004::d", 8888)], -4: [("2001:67c:04e8:f004::d", 8888)],
|
||||||
("2001:0b28:f23f:f005:0000:0000:0000:000d", 8888)
|
5: [("2001:b28:f23f:f005::d", 8888)], -5: [("2001:67c:04e8:f004::d", 8888)]
|
||||||
]
|
}
|
||||||
|
|
||||||
|
|
||||||
USE_MIDDLE_PROXY = (len(AD_TAG) == 16)
|
USE_MIDDLE_PROXY = (len(AD_TAG) == 16)
|
||||||
@@ -112,6 +118,7 @@ KEY_LEN = 32
|
|||||||
IV_LEN = 16
|
IV_LEN = 16
|
||||||
HANDSHAKE_LEN = 64
|
HANDSHAKE_LEN = 64
|
||||||
MAGIC_VAL_POS = 56
|
MAGIC_VAL_POS = 56
|
||||||
|
DC_IDX_POS = 60
|
||||||
|
|
||||||
MAGIC_VAL_TO_CHECK = b'\xef\xef\xef\xef'
|
MAGIC_VAL_TO_CHECK = b'\xef\xef\xef\xef'
|
||||||
|
|
||||||
@@ -410,9 +417,7 @@ async def handle_handshake(reader, writer):
|
|||||||
if check_val != MAGIC_VAL_TO_CHECK:
|
if check_val != MAGIC_VAL_TO_CHECK:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
dc_idx = abs(int.from_bytes(decrypted[60:62], "little", signed=True)) - 1
|
dc_idx = int.from_bytes(decrypted[DC_IDX_POS:DC_IDX_POS+2], "little", signed=True)
|
||||||
if dc_idx == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
reader = CryptoWrappedStreamReader(reader, decryptor)
|
reader = CryptoWrappedStreamReader(reader, decryptor)
|
||||||
writer = CryptoWrappedStreamWriter(writer, encryptor)
|
writer = CryptoWrappedStreamWriter(writer, encryptor)
|
||||||
@@ -426,6 +431,8 @@ async def do_direct_handshake(dc_idx, dec_key_and_iv=None):
|
|||||||
b"\x47\x45\x54\x20", b"\xee\xee\xee\xee"]
|
b"\x47\x45\x54\x20", b"\xee\xee\xee\xee"]
|
||||||
RESERVED_NONCE_CONTINUES = [b"\x00\x00\x00\x00"]
|
RESERVED_NONCE_CONTINUES = [b"\x00\x00\x00\x00"]
|
||||||
|
|
||||||
|
dc_idx = abs(dc_idx) - 1
|
||||||
|
|
||||||
if PREFER_IPV6:
|
if PREFER_IPV6:
|
||||||
if not 0 <= dc_idx < len(TG_DATACENTERS_V6):
|
if not 0 <= dc_idx < len(TG_DATACENTERS_V6):
|
||||||
return False
|
return False
|
||||||
@@ -534,13 +541,13 @@ async def do_middleproxy_handshake(dc_idx, cl_ip, cl_port):
|
|||||||
use_ipv6_clt = (":" in cl_ip)
|
use_ipv6_clt = (":" in cl_ip)
|
||||||
|
|
||||||
if use_ipv6_tg:
|
if use_ipv6_tg:
|
||||||
if not 0 <= dc_idx < len(TG_MIDDLE_PROXIES_V6):
|
if dc_idx not in TG_MIDDLE_PROXIES_V6:
|
||||||
return False
|
return False
|
||||||
addr, port = TG_MIDDLE_PROXIES_V6[dc_idx]
|
addr, port = random.choice(TG_MIDDLE_PROXIES_V6[dc_idx])
|
||||||
else:
|
else:
|
||||||
if not 0 <= dc_idx < len(TG_MIDDLE_PROXIES_V4):
|
if dc_idx not in TG_MIDDLE_PROXIES_V4:
|
||||||
return False
|
return False
|
||||||
addr, port = TG_MIDDLE_PROXIES_V4[dc_idx]
|
addr, port = random.choice(TG_MIDDLE_PROXIES_V4[dc_idx])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
reader_tgt, writer_tgt = await asyncio.open_connection(addr, port)
|
reader_tgt, writer_tgt = await asyncio.open_connection(addr, port)
|
||||||
@@ -732,6 +739,85 @@ async def stats_printer():
|
|||||||
print(flush=True)
|
print(flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
async def update_middle_proxy_info():
|
||||||
|
async def make_https_req(url):
|
||||||
|
# returns resp body
|
||||||
|
SSL_PORT = 443
|
||||||
|
url_data = urllib.parse.urlparse(url)
|
||||||
|
|
||||||
|
HTTP_REQ_TEMPLATE = "\r\n".join(["GET %s HTTP/1.1", "Host: core.telegram.org",
|
||||||
|
"Connection: close"]) + "\r\n\r\n"
|
||||||
|
try:
|
||||||
|
reader, writer = await asyncio.open_connection(url_data.netloc, SSL_PORT, ssl=True)
|
||||||
|
req = HTTP_REQ_TEMPLATE % urllib.parse.quote(url_data.path)
|
||||||
|
writer.write(req.encode("utf8"))
|
||||||
|
data = await reader.read()
|
||||||
|
writer.close()
|
||||||
|
|
||||||
|
headers, body = data.split(b"\r\n\r\n", 1)
|
||||||
|
return body
|
||||||
|
except Exception:
|
||||||
|
return b""
|
||||||
|
|
||||||
|
async def get_new_proxies(url):
|
||||||
|
PROXY_REGEXP = re.compile(r"proxy_for\s+(-?\d+)\s+(.+):(\d+)\s*;")
|
||||||
|
|
||||||
|
ans = {}
|
||||||
|
try:
|
||||||
|
body = await make_https_req(url)
|
||||||
|
except Exception:
|
||||||
|
return ans
|
||||||
|
|
||||||
|
fields = PROXY_REGEXP.findall(body.decode("utf8"))
|
||||||
|
if fields:
|
||||||
|
for dc_idx, host, port in fields:
|
||||||
|
if host.startswith("[") and host.endswith("]"):
|
||||||
|
host = host[1:-1]
|
||||||
|
dc_idx, port = int(dc_idx), int(port)
|
||||||
|
if dc_idx not in ans:
|
||||||
|
ans[dc_idx] = [(host, port)]
|
||||||
|
else:
|
||||||
|
ans[dc_idx].append((host, port))
|
||||||
|
return ans
|
||||||
|
|
||||||
|
PROXY_INFO_ADDR = "https://core.telegram.org/getProxyConfig"
|
||||||
|
PROXY_INFO_ADDR_V6 = "https://core.telegram.org/getProxyConfigV6"
|
||||||
|
PROXY_SECRET_ADDR = "https://core.telegram.org/getProxySecret"
|
||||||
|
|
||||||
|
global TG_MIDDLE_PROXIES_V4
|
||||||
|
global TG_MIDDLE_PROXIES_V6
|
||||||
|
global PROXY_SECRET
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
v4_proxies = await get_new_proxies(PROXY_INFO_ADDR)
|
||||||
|
if not v4_proxies:
|
||||||
|
raise Exception("no proxy data")
|
||||||
|
TG_MIDDLE_PROXIES_V4 = v4_proxies
|
||||||
|
except Exception:
|
||||||
|
print_err("Error updating middle proxy list")
|
||||||
|
|
||||||
|
try:
|
||||||
|
v6_proxies = await get_new_proxies(PROXY_INFO_ADDR_V6)
|
||||||
|
if not v6_proxies:
|
||||||
|
raise Exception("no proxy data (ipv6)")
|
||||||
|
TG_MIDDLE_PROXIES_V6 = v6_proxies
|
||||||
|
except Exception:
|
||||||
|
print_err("Error updating middle proxy list for IPv6")
|
||||||
|
|
||||||
|
try:
|
||||||
|
secret = await make_https_req(PROXY_SECRET_ADDR)
|
||||||
|
if not secret:
|
||||||
|
raise Exception("no secret")
|
||||||
|
if secret != PROXY_SECRET:
|
||||||
|
PROXY_SECRET = secret
|
||||||
|
print_err("Middle proxy secret updated")
|
||||||
|
except Exception:
|
||||||
|
print_err("Error updating middle proxy secret, using old")
|
||||||
|
|
||||||
|
await asyncio.sleep(PROXY_INFO_UPDATE_PERIOD)
|
||||||
|
|
||||||
|
|
||||||
def init_ip_info():
|
def init_ip_info():
|
||||||
global USE_MIDDLE_PROXY
|
global USE_MIDDLE_PROXY
|
||||||
global PREFER_IPV6
|
global PREFER_IPV6
|
||||||
@@ -810,6 +896,10 @@ def main():
|
|||||||
stats_printer_task = asyncio.Task(stats_printer())
|
stats_printer_task = asyncio.Task(stats_printer())
|
||||||
asyncio.ensure_future(stats_printer_task)
|
asyncio.ensure_future(stats_printer_task)
|
||||||
|
|
||||||
|
if USE_MIDDLE_PROXY:
|
||||||
|
middle_proxy_updater_task = asyncio.Task(update_middle_proxy_info())
|
||||||
|
asyncio.ensure_future(middle_proxy_updater_task)
|
||||||
|
|
||||||
task_v4 = asyncio.start_server(handle_client_wrapper,
|
task_v4 = asyncio.start_server(handle_client_wrapper,
|
||||||
'0.0.0.0', PORT, loop=loop)
|
'0.0.0.0', PORT, loop=loop)
|
||||||
server_v4 = loop.run_until_complete(task_v4)
|
server_v4 = loop.run_until_complete(task_v4)
|
||||||
|
|||||||
Reference in New Issue
Block a user