From 644229719fc67079a079be37456550afe69840af Mon Sep 17 00:00:00 2001 From: Dr Jones Date: Tue, 14 Apr 2026 19:28:50 -0700 Subject: [PATCH] feat: fixed exit proxy (last hop only), optional pool-free single-hop mode, gitignore pycache Made-with: Cursor --- .gitignore | 9 ++ README.md | 4 +- .../__pycache__/__init__.cpython-311.pyc | Bin 272 -> 0 bytes .../__pycache__/app.cpython-311.pyc | Bin 53186 -> 0 bytes .../__pycache__/config.cpython-311.pyc | Bin 5818 -> 0 bytes .../__pycache__/fetcher.cpython-311.pyc | Bin 2459 -> 0 bytes .../__pycache__/firewall.cpython-311.pyc | Bin 9307 -> 0 bytes .../__pycache__/gost_util.cpython-311.pyc | Bin 6082 -> 0 bytes .../__pycache__/paths.cpython-311.pyc | Bin 1068 -> 0 bytes .../__pycache__/service.cpython-311.pyc | Bin 26237 -> 0 bytes .../__pycache__/sysproxy.cpython-311.pyc | Bin 4328 -> 0 bytes .../__pycache__/tray.cpython-311.pyc | Bin 4734 -> 0 bytes .../__pycache__/validator.cpython-311.pyc | Bin 8669 -> 0 bytes .../__pycache__/windows_task.cpython-311.pyc | Bin 4014 -> 0 bytes proxy_chain_manager/app.py | 50 +++++++++-- proxy_chain_manager/config.py | 15 ++++ proxy_chain_manager/service.py | 79 +++++++++++++++--- 17 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 .gitignore delete mode 100644 proxy_chain_manager/__pycache__/__init__.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/app.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/config.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/fetcher.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/firewall.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/gost_util.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/paths.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/service.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/sysproxy.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/tray.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/validator.cpython-311.pyc delete mode 100644 proxy_chain_manager/__pycache__/windows_task.cpython-311.pyc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46c4f10 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__/ +*.py[cod] +*.egg-info/ +.eggs/ +dist/ +build/ +*.spec.bak +.env +.venv/ diff --git a/README.md b/README.md index 10685b9..8b4cf72 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ YOU → NordVPN (OS tunnel) → Hop 1 → Hop 2 → Hop 3 → Internet - **Multi-hop GOST chains** — 2–8 hops, randomly picked from validated pool - **Obfuscation modes** — Auto, HTTP-only, SOCKS5-only, Random Mix - **Manual chain builder** — drag/reorder hops, pin your own IPs +- **Fixed exit (last hop)** — optional URL used only as the final hop; earlier hops still rotate randomly (ignored when a full manual chain is pinned) - **Exit IP verification** — checks real exit IP every health cycle, rotates if it matches your real IP - **Windows system proxy** — sets `HKCU` registry proxy so all WinINet apps use the chain - **Firewall kill-switch** — `netsh` rules that block all outbound except GOST + NordVPN when running as Admin @@ -73,7 +74,8 @@ Output: `dist\ProxyChainManager.exe` + copied to Desktop. ## Chain Builder Tab - **Obfuscation mode** — selects which protocols to include in chains -- **Hop count slider** — 2–8 hops +- **Hop count slider** — 1–8 total hops (top bar ± or slider) +- **Fixed exit (last hop only)** — optional field: your SOCKS/HTTP proxy is always the **last** hop before the internet; all **earlier** hops are still chosen at random from the validated pool. Leave empty for a fully automatic chain. Set hop count to `1` to use **only** your fixed exit (no pool). While **Pin & use this chain** is on, the full pinned list wins and fixed exit is ignored. - **Manual chain** — enter proxies manually, reorder with ↑↓, enable "Use this chain" to pin it - **Paste current** — copies the auto-selected chain into the editor - **Sources** — add/remove proxy list URLs (JSON format from Proxifly) diff --git a/proxy_chain_manager/__pycache__/__init__.cpython-311.pyc b/proxy_chain_manager/__pycache__/__init__.cpython-311.pyc deleted file mode 100644 index f43352da3f76aaf187b9b9d9ea8d89429085c12c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 272 zcmZ3^%ge<81m>^rW<~<(#~=<2FhUuh`GAb+3@Hpz3@MCJj44dP44TYU7D4$Xi6xnN z=?Vo!`4yE4$r*{6c?!9Sd5P(%MG9&8MGE1Wc`5nj#R?kk{=p#%Nr}nXsd*`ydR453 zdIow1ews|T*yH0<@{{A^Z*j-Rm!%dJXXfX{$FF4g46^u_le1M!XfaSUCZ#AVKQFa7 zCIDoSGsqrah&3@_tK-2|$3v}-iI30B%PfhH*DI*}#bJ}1pHiBWYFES#G!o>YVi6$m aftit!@dkt41qQnZe4-89AXvl-lmGw(0#HBz diff --git a/proxy_chain_manager/__pycache__/app.cpython-311.pyc b/proxy_chain_manager/__pycache__/app.cpython-311.pyc deleted file mode 100644 index b6bac95ec55ddedafe18e41166f68a1477b1eec6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53186 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 HdgT8Fzl(db diff --git a/proxy_chain_manager/__pycache__/fetcher.cpython-311.pyc b/proxy_chain_manager/__pycache__/fetcher.cpython-311.pyc deleted file mode 100644 index ab379273e9de1aaf5b902564751de4ac5619bebc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2459 zcmZ`*-ER{|5Z}EIf8-qEkS{(=i35n5R(uu-Pza3@3Q8bq3#cL_a<9INx%7Nz_RdKh zT_iu`!HF!zv`FD4lGO*GqE-9YhdzMRKOjbyuvS7ss!&z+B^9j{<)P~AIXJlx_Re!V zvopK1v-6wv!^Xx21nufyFSP%7gnnntn+7~<`1O}S7m^>Q|P>I{M6y#yIf(ejmT4UA*3E>hTRqTuqqP&3whjZyp=Ie* z?JY)^rXNLryk6davaTU{reAZEvJ{RSk5UIcd( zBKMQO2+P6q<>2{B@catm#a&ODtD(k)i}M$Y2j&I}19@Bx1fK`?JPYh82O^a~WH}J2 zHiZ`^<|pQ+3R8Ju#SccVrAz*1bNs`|hHSgu>gwut;(r4u)LvAU`pZ(ZB1Kma7I#*g zn)AV`8`+`_Q7lWRD!>V+tY+BAVoz_Be;O5f5BZVUKlwk`FQ_=o=Q{EwucKQDKlsdSzxN6uCv zXP-wdJd0c?M|vxf-X~u?i(GNFtD)9vsA=KS{H5Zhawt*>Me_KC)K-+2TFTPCinNbu zb(Ic1I#D{}cA56T{6O)};^a4zceD4hsel|B)7|ahcc5r_1KAsyY4CRMbt5Q>LkhH^2W0_lbVsF zK0BL+FJZY&I@nMUD(V#&RS6BmZ9pRn)cYeP5y-Irpie_GRz;5`}W^^U~LmOICax_XA~LwBn2A_!XZYf3$+O OA+1dqV*L){dig(}NGjU^ diff --git a/proxy_chain_manager/__pycache__/firewall.cpython-311.pyc b/proxy_chain_manager/__pycache__/firewall.cpython-311.pyc deleted file mode 100644 index b7795309ba4a4f18b53a90102b39bfb07ee60b84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9307 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 Vcn5!Ifir^!E598{uLzim{2$N$kx&2t diff --git a/proxy_chain_manager/__pycache__/gost_util.cpython-311.pyc b/proxy_chain_manager/__pycache__/gost_util.cpython-311.pyc deleted file mode 100644 index 8d9fb01195a52306f2eb0848877840d3bd2cd2d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6082 zcmbstZEO=qcGkOV@A^9*KoTHvpd6Twq!j2KAIFg@O=6=<(1J)h&*1P8}!W;YEn z&dDH7O;IGM)QYsFYEHUxv>=rq{lU-Usw;nOsD$`+?~P+SCaF%S z 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 diff --git a/proxy_chain_manager/__pycache__/tray.cpython-311.pyc b/proxy_chain_manager/__pycache__/tray.cpython-311.pyc deleted file mode 100644 index b7c95e24effe9a56e326597da7766f4362d2bf88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4734 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 II+&>b19Tbk2mk;8 diff --git a/proxy_chain_manager/__pycache__/validator.cpython-311.pyc b/proxy_chain_manager/__pycache__/validator.cpython-311.pyc deleted file mode 100644 index ac0ec86cddc68c3b8843dce3db32c387339d6517..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8669 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 J`VC-h=s$vxlal}d diff --git a/proxy_chain_manager/app.py b/proxy_chain_manager/app.py index 47fd1ef..91c7b23 100644 --- a/proxy_chain_manager/app.py +++ b/proxy_chain_manager/app.py @@ -18,6 +18,7 @@ from .config import ( OBFUSCATION_MODES, Settings, load_settings, + normalize_proxy_url, save_settings, ) from .firewall import ( @@ -176,6 +177,7 @@ def main() -> None: obfuscation_mode=cur.obfuscation_mode, use_pinned_chain=cur.use_pinned_chain, pinned_chain=cur.pinned_chain, + manual_exit_proxy=cur.manual_exit_proxy, health_check_seconds=cur.health_check_seconds, full_refresh_seconds=cur.full_refresh_seconds, validation_concurrency=cur.validation_concurrency, @@ -273,7 +275,9 @@ def main() -> None: d.configure(text_color=c) pulse_job["id"] = root.after(380, lambda s=step: _pulse(s + 1)) # type: ignore[arg-type] - def _render_chain(hops: list[str], status: str, exit_ip: str | None) -> None: + def _render_chain( + hops: list[str], status: str, exit_ip: str | None, fixed_last: bool = False + ) -> None: _cancel_pulse() for w in list(chain_canvas.winfo_children()): w.destroy() @@ -296,11 +300,15 @@ def main() -> None: _node("NORD", PURPLE, bold=True) _arr() + last_i = len(hops) - 1 for i, h in enumerate(hops): - dot = ctk.CTkLabel(chain_canvas, text="●", font=(FONT, 12), text_color=hop_c) + is_fixed = fixed_last and i == last_i and last_i >= 0 + lbl_c = ORANGE if is_fixed else hop_c + dot = ctk.CTkLabel(chain_canvas, text="●", font=(FONT, 12), text_color=lbl_c) dot.pack(side="left", padx=1) hop_dot_labels.append(dot) - ctk.CTkLabel(chain_canvas, text=_short(h), font=(FONT, 10), text_color=hop_c).pack(side="left", padx=1) + label = _short(h) + (" ★" if is_fixed else "") + ctk.CTkLabel(chain_canvas, text=label, font=(FONT, 10), text_color=lbl_c).pack(side="left", padx=1) if i < len(hops) - 1: _arr() @@ -448,7 +456,35 @@ def main() -> None: cb_left, text="Elite proxies only (slower but more anonymous)", variable=elite_var, font=(FONT, 11), fg_color=ACCENT2, hover_color=ACCENT, text_color=TEXT, - ).pack(anchor="w", padx=16, pady=(0, 12)) + ).pack(anchor="w", padx=16, pady=(0, 8)) + + exit_fix_frame = ctk.CTkFrame(cb_left, fg_color=PANEL, corner_radius=8) + exit_fix_frame.pack(fill="x", padx=12, pady=(0, 12)) + ctk.CTkLabel( + exit_fix_frame, + text="Fixed exit — last hop only", + font=(FONT, 11, "bold"), + text_color=ORANGE, + ).pack(anchor="w", padx=10, pady=(8, 2)) + exit_proxy_entry = ctk.CTkEntry( + exit_fix_frame, + placeholder_text="http://host:port or socks5://host:port (optional)", + font=("Consolas", 10), + fg_color=BG, + border_color=ACCENT, + height=28, + ) + exit_proxy_entry.pack(fill="x", padx=10, pady=(0, 4)) + if s.manual_exit_proxy: + exit_proxy_entry.insert(0, s.manual_exit_proxy) + ctk.CTkLabel( + exit_fix_frame, + text="Earlier hops still rotate randomly. Empty = fully automatic exit.\n" + "Ignored while “Pin & use this chain” is enabled.", + font=(FONT, 9), + text_color=TEXT2, + justify="left", + ).pack(anchor="w", padx=10, pady=(0, 8)) # Right — manual chain editor cb_right = ctk.CTkFrame(cb_split, fg_color=CARD, corner_radius=8, width=400) @@ -643,6 +679,7 @@ def main() -> None: obfuscation_mode=mode_var.get(), use_pinned_chain=bool(use_manual_var.get()), pinned_chain=list(manual_chain), + manual_exit_proxy=normalize_proxy_url(exit_proxy_entry.get()), health_check_seconds=max(10, int(entries["health"].get().strip())), full_refresh_seconds=max(60, int(entries["refresh"].get().strip())), validation_concurrency=max(1, int(entries["conc"].get().strip())), @@ -751,7 +788,9 @@ def main() -> None: hops = [str(x) for x in (m.get("hops") or [])] status = str(m.get("status", "connecting")) exit_ip = m.get("exit_ip") - _render_chain(hops, status, exit_ip) + fix = normalize_proxy_url(svc.settings.manual_exit_proxy) + fixed_last = bool(fix) and not svc.settings.use_pinned_chain + _render_chain(hops, status, exit_ip, fixed_last=fixed_last) _refresh_sysproxy() tray.set_state( {"healthy": "green", "dead": "red", "connecting": "yellow"}.get(status, "yellow") @@ -792,6 +831,7 @@ def main() -> None: _log(f"Log file: {LOG_PATH}") _log("Press START to fetch, validate and chain proxies.") _log("Use +/− in top bar to change hop count instantly.") + _log("Chain Builder → Fixed exit: set the last hop (optional); rest still rotates.") _log("─" * 60) _pump() root.mainloop() diff --git a/proxy_chain_manager/config.py b/proxy_chain_manager/config.py index 76ae7eb..ab5495a 100644 --- a/proxy_chain_manager/config.py +++ b/proxy_chain_manager/config.py @@ -10,6 +10,17 @@ from .paths import app_data_dir # do not affect 127.0.0.1; avoid storing LAN IPs or hostnames for the listener. LISTEN_HOST = "127.0.0.1" + +def normalize_proxy_url(raw: str) -> str: + """Strip, add http:// if missing. Empty input → empty string.""" + t = (raw or "").strip() + if not t: + return "" + if "://" not in t: + t = "http://" + t + return t.rstrip("/") + + OBFUSCATION_MODES = ["auto", "http_only", "socks5_only", "random_mix"] OBFUSCATION_LABELS = { "auto": "Auto (best available)", @@ -30,6 +41,8 @@ class Settings: obfuscation_mode: str = "auto" # see OBFUSCATION_MODES use_pinned_chain: bool = False # use manually ordered chain pinned_chain: list[str] = field(default_factory=list) # user-ordered hop list + # Fixed last hop only (ignored when use_pinned_chain is True — full manual chain wins) + manual_exit_proxy: str = "" # ── timing ──────────────────────────────────────────────────────────── health_check_seconds: int = 180 # how often to re-verify exit IP @@ -88,6 +101,8 @@ def load_settings() -> Settings: s.obfuscation_mode = "auto" if not isinstance(s.pinned_chain, list): s.pinned_chain = [] + if not hasattr(s, "manual_exit_proxy") or not isinstance(s.manual_exit_proxy, str): + s.manual_exit_proxy = "" s, changed = normalize_listen_host(s) if changed: try: diff --git a/proxy_chain_manager/service.py b/proxy_chain_manager/service.py index 95848d6..93f64e9 100644 --- a/proxy_chain_manager/service.py +++ b/proxy_chain_manager/service.py @@ -9,7 +9,7 @@ from collections.abc import Callable from concurrent.futures import ThreadPoolExecutor from typing import Any -from .config import Settings, load_settings, save_settings +from .config import Settings, load_settings, normalize_proxy_url, save_settings from .fetcher import fetch_proxy_json, normalize_entries from .firewall import disengage as fw_disengage, engage as fw_engage, is_admin from .gost_util import build_gost_cmd, ensure_gost, popen_no_window, terminate_process @@ -52,6 +52,10 @@ class ChainService: # Per-session blacklist: proxies that crashed GOST immediately self._blacklist: set[str] = set() + def _manual_exit_url(self) -> str | None: + u = normalize_proxy_url(self._settings.manual_exit_proxy) + return u if u else None + @property def settings(self) -> Settings: return self._settings @@ -176,6 +180,18 @@ class ChainService: break continue + # Fixed exit only: hop count = 1 → chain is only the manual exit (no pool) + mex = self._manual_exit_url() + if mex and not self._settings.use_pinned_chain and self._settings.chain_length == 1: + rotation_num += 1 + self._notify({"type": "rotation", "n": rotation_num}) + ok = await self._run_chain(gost, [mex], real_ip) + if not ok: + await self._sleep_interruptible(15) + if self._stop.is_set(): + break + continue + # ── Pool refresh ───────────────────────────────────────────────── if need_refresh: self._notify({"type": "phase", "phase": "fetch"}) @@ -240,8 +256,11 @@ class ChainService: await asyncio.sleep(2.0) if self._proc.poll() is not None: - # GOST died immediately — blacklist these proxies + # GOST died immediately — blacklist pool proxies (never blacklist user fixed exit) + fixed = self._manual_exit_url() for h in chain: + if fixed and h == fixed: + continue self._blacklist.add(h) self._available = [x for x in self._available if x != h] self._notify({"type": "hops", "hops": chain, "status": "dead", "exit_ip": None}) @@ -305,17 +324,38 @@ class ChainService: # ───────────────────────────────────────────────────────────────────────── def _pick_chain(self) -> list[str]: - """Pick chain_length proxies from _available (shuffle-and-drain). - Filters out blacklisted proxies. Marks picked ones as used.""" + """Pick chain_length hops: optional fixed last hop + random prefix from pool.""" s = self._settings k = max(1, s.chain_length) + manual = self._manual_exit_url() + if manual and not s.use_pinned_chain: + # Last hop is always manual; earlier hops come from pool (never duplicate manual) + mid_need = k - 1 + candidates = [ + u for u in self._available + if u not in self._blacklist and u != manual + ] + if s.obfuscation_mode == "http_only": + candidates = [u for u in candidates if u.startswith("http://")] + elif s.obfuscation_mode == "socks5_only": + candidates = [u for u in candidates if u.startswith("socks5://")] + elif s.obfuscation_mode == "random_mix": + random.shuffle(candidates) - # Apply mode filter and remove blacklisted entries - candidates = [ - u for u in self._available - if u not in self._blacklist - ] - # Apply obfuscation mode filter + if mid_need == 0: + return [manual] + if len(candidates) < mid_need: + return [] + + prefix = candidates[:mid_need] + pset = set(prefix) + self._available = [u for u in self._available if u not in pset] + self._used.update(prefix) + self._used.add(manual) + return prefix + [manual] + + # Default: all hops from rotating pool + candidates = [u for u in self._available if u not in self._blacklist] if s.obfuscation_mode == "http_only": candidates = [u for u in candidates if u.startswith("http://")] elif s.obfuscation_mode == "socks5_only": @@ -327,7 +367,6 @@ class ChainService: return [] picked = candidates[:k] - # Remove picked from available picked_set = set(picked) self._available = [u for u in self._available if u not in picked_set] self._used.update(picked) @@ -386,6 +425,24 @@ class ChainService: on_progress=on_prog, ) random.shuffle(good) + + mex = normalize_proxy_url(s.manual_exit_proxy) + if mex and not s.use_pinned_chain: + v = await validate_proxies( + [mex], + s.ip_check_url, + 1, + s.validation_timeout_seconds, + on_progress=None, + ) + if v: + self._notify({"type": "log", "text": "Fixed exit proxy: OK (reachable)."}) + else: + self._notify({ + "type": "log", + "text": "Fixed exit proxy: validation failed — will still attempt; check URL/credentials.", + }) + self._notify({"type": "log", "text": f"Valid proxies: {len(good)} / {len(unique)}"}) self._notify({"type": "phase", "phase": "running"}) return good