A Python port of the Invisible Internet Project (I2P)
at main 57 lines 1.9 kB view raw
1"""IRC server tunnel — exposes local IRC server as I2P destination. 2 3Extends ServerTunnelTask with USER command mangling to replace 4the connecting user's identity with an I2P-derived cloak, 5preventing real hostname/IP leakage. 6 7Ported from net.i2p.i2ptunnel.I2PTunnelIRCServer. 8""" 9 10from __future__ import annotations 11 12import hashlib 13import logging 14 15from i2p_apps.i2ptunnel.config import TunnelDefinition, TunnelType 16from i2p_apps.i2ptunnel.tasks import ServerTunnelTask 17 18logger = logging.getLogger(__name__) 19 20 21class IRCServerTask(ServerTunnelTask): 22 """IRC server tunnel with USER command mangling. 23 24 Accepts I2P connections and forwards to a local IRC server, 25 replacing the USER command's username/hostname with an I2P-derived 26 cloak so the real identity is never exposed. 27 """ 28 29 def __init__(self, config: TunnelDefinition, session) -> None: 30 super().__init__(config, session) 31 32 def _compute_cloak(self, remote_dest: str) -> str: 33 """Compute a deterministic .b32.i2p cloak from a destination. 34 35 Uses SHA-256 of the destination to produce a stable, 36 privacy-preserving identifier. 37 """ 38 h = hashlib.sha256(remote_dest.encode("utf-8")).hexdigest()[:16] 39 return f"{h}.b32.i2p" 40 41 def _mangle_user(self, line: str, remote_dest: str) -> str: 42 """Mangle a USER command, replacing the username with a cloak. 43 44 If the line is not a USER command, returns it unchanged. 45 Format: USER <username> <mode> <unused> :<realname> 46 """ 47 if not line.upper().startswith("USER "): 48 return line 49 50 parts = line.split(" ", 4) 51 if len(parts) < 5: 52 return line 53 54 cloak = self._compute_cloak(remote_dest) 55 # Replace username (parts[1]) with cloak, preserve realname 56 parts[1] = cloak 57 return " ".join(parts)