- stable gets the beta panel and server features (new design, presets, firewall, monthly traffic, router failover over all ports/addresses + TCP, altip, HR tab, Windows tab, update banner); ios/ macos/ windows/ sources stay out of stable - menu item "Update to N" under Settings when a new version is out - mobile: top menu no longer stretches to 200px - urllib User-Agent: Cloudflare in front of git.bobyrev.com returns 403 to Python-urllib - docs: GitHub adleibzon-rgb as source, password/uninstall/devices sections, new screenshots, PORTS.md TCP fallback and second IP Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""IPv6 -> local IPv4 UDP relay for the obfuscator (it speaks IPv4 only).
|
|
|
|
Usage: phobos-v6relay.py LISTEN_PORT [TARGET_PORT] [TARGET_HOST]
|
|
One upstream socket per IPv6 client, so the obfuscator sees a stable
|
|
client address for the whole session. Idle clients are dropped after 300 s.
|
|
"""
|
|
import selectors
|
|
import socket
|
|
import sys
|
|
import time
|
|
|
|
IDLE = 300
|
|
|
|
listen_port = int(sys.argv[1])
|
|
target = (sys.argv[3] if len(sys.argv) > 3 else "127.0.0.1",
|
|
int(sys.argv[2]) if len(sys.argv) > 2 else listen_port)
|
|
|
|
down = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
|
down.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
|
|
down.bind(("::", listen_port))
|
|
|
|
sel = selectors.DefaultSelector()
|
|
sel.register(down, selectors.EVENT_READ, None)
|
|
clients = {} # v6 addr -> [upstream socket, last seen]
|
|
|
|
while True:
|
|
for key, _ in sel.select(timeout=30):
|
|
if key.data is None:
|
|
data, addr = down.recvfrom(65535)
|
|
c = clients.get(addr)
|
|
if c is None:
|
|
up = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
up.connect(target)
|
|
sel.register(up, selectors.EVENT_READ, addr)
|
|
c = clients[addr] = [up, 0]
|
|
c[1] = time.monotonic()
|
|
try:
|
|
c[0].send(data)
|
|
except OSError:
|
|
pass
|
|
else:
|
|
addr = key.data
|
|
try:
|
|
down.sendto(key.fileobj.recv(65535), addr)
|
|
clients[addr][1] = time.monotonic()
|
|
except OSError:
|
|
pass
|
|
now = time.monotonic()
|
|
for addr, (up, seen) in list(clients.items()):
|
|
if now - seen > IDLE:
|
|
sel.unregister(up)
|
|
up.close()
|
|
del clients[addr]
|