The val.town founder asked us not to promote using their service. This commit removes every val.town reference from the codebase and rewrites the exit-node guides to be platform-agnostic. Changes: - Renamed assets/exit_node/valtown.ts → assets/exit_node/exit_node.ts. TypeScript itself is unchanged — same web-standard Request/Response/ fetch API that runs on any serverless runtime. - Rewrote assets/exit_node/README.md and README.fa.md to recommend Deno Deploy as the primary host for users who want a free serverless TS endpoint, with fly.io and your-own-VPS as alternatives. CF Workers is explicitly called out as not-helpful (CF outbound is still on CF's flagged IP space). - Updated all val.town mentions in source comments (src/config.rs, src/domain_fronter.rs, src/bin/ui.rs) to neutral wording. - Updated config.exit-node.example.json `_comment` strings and the example URL. - Updated main README.md FAQ entries (Persian + English) and docs/guide.md / docs/guide.fa.md. - Old changelog files (v1.9.4 / v1.9.5 / v1.9.9) had val.town mentions retroactively replaced too — same redaction principle. - Bumped to v1.9.10 with a changelog noting the rename + Telegram channel brief format from earlier today. Users who already have an exit node deployed (on whichever host they picked) don't need to change anything — the wire protocol is identical and the renamed script is byte-identical to the old one. Tests: 179 lib + 35 tunnel-node green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.6 KiB
• Fix v1.9.8 Android: کرش جدید ~۲ ثانیه بعد از Disconnect (#700 از @ilok67 با root cause + fix کامل): علیرغم fix v1.9.8 برای race lifecycle (#666)، crash جداگانه در MhrvVpnService.teardown() باقی مانده بود. ترتیب قبلی: tun2proxy.stop → tun.close → join → Native.stopProxy. مشکل: tun2proxy worker thread در native code blocked روی socket read از SOCKS5 proxy است. وقتی Tun2proxy.stop کالد میشه + 2s timeout میگذره + 4s join timeout میگذره (worker هنوز alive)، Native.stopProxy runtime Rust رو shutdown میکنه شامل listener socket — worker thread که در native blocking read از همان socket است → use-after-free → SIGSEGV. comment کد قدیمی ادعا میکرد "runtime shutdown will knock the rest of the world over" که اشتباه بود — Native.stopProxy نمیتونه force-terminate یک thread native دیگه. ترتیب جدید: Native.stopProxy اول (socket رو میبنده → blocking read worker با error برمیگرده → worker پاک exit میکنه از error path)، بعد Tun2proxy.stop (cooperative، redundant ولی ارزان) → tun.close → join (تقریباً همیشه فوری چون worker از قبل تموم شده). تشکر بیشتر از @ilok67 برای triage دقیق دومین crash.
• Fix tunnel-node batch drain correctness + lock contention (PR #695 از @dazzling-no-more): چهار باگ، دو correctness، دو latency.
- Cleanup race tail-bytes drop میکرد: session با buffer > ۱۶ MiB + EOF —
drain_nowصحیحeof=falseبرمیگردوند تا tail tail رو در poll بعدی drain کنه، ولی cleanup loop همان atomic رو میخوند،trueمیدید + session رو حذف میکرد +reader_taskرو abort + tail هدر میرفت. حالا cleanup از مقدار returndrain_nowپیروی میکنه — session فقط بعد از shipped شدن drain کهeof=trueمیفرسته، حذف میشه. data loss silent در 1Gbps+ VPS که buffer بین pollها پر میشد، fix شد. - Sessions-map lock روی upstream await نگه میداشت: phase-1
dataop global sessions map رو نگه میداشت رویlast_active.lock،writer.lock،write_all، وflush— head-of-line-block برای هر batch + connect/close op دیگه. حالا (مثلudp_dataکه قبلاً درست بود) Arc از under map clone میشه، lock drop، بعد write/flush. - TCP+UDP batch deadline UDP رو میپرداخت:
tokio::join!(wait_tcp, wait_udp)conjunctive هست — TCP-ready burst هنوز LONGPOLL_DEADLINE 15 ثانیهای UDP رو میپرداخت قبل از پاسخ. comment میگفت "either side"، code "both sides" انجام میداد. تغییر بهselect!. test جدیدbatch_tcp_ready_does_not_pay_udp_longpoll_deadlineاین رد رو حفظ میکنه. - Watcher tasks تحت
select!cancellation leak میکرد:wait_for_any_drainableفقط در trailing loop watcherها رو abort میکرد — past همه cancel pointها. با تبدیل phase-2 wait بهselect!، loser arm's future drop میشه و watcherهاش detach میشن (drop کردنJoinHandleabort نمیکنه). هر orphan یکArc<...Inner>نگه میداشت + میتوانستnotify_one()permit از batch بعدی بدزده. fix:AbortOnDropnewtype روی همهJoinHandlewatcher. ۲ test جدید + 35/35 pass. • Example config exit-node باaistudio.google.comوai.google.dev— درخواست از #701. AI Studio روی Iran IP sanction میخوره (نه Apps Script طرف ما). مقصد IP exit node رو میبینه که نه Iran است نه Google datacenter. • Example config fronting-groups با Reddit / Fastly / Pinterest / CNN / BuzzFeed family domains اضافه شد (PR #696 از @Shjpr9). همه روی Fastly Anycast 151.101.x.x — کاربران میتونن از example بیشتر دامنه برداشت کنن، اونی که در شبکهشان کار میکنه نگه دارن. • تست: ۱۷۹ lib + ۳۵ tunnel-node test همه pass.
• Fix Android ~2-second-delayed crash on Disconnect from v1.9.8 (#700 by @ilok67 with full root cause + fix): despite the v1.9.8 fix for the lifecycle race (#666), a separate crash inside MhrvVpnService.teardown() remained. Old order was tun2proxy.stop → tun.close → join → Native.stopProxy. Problem: tun2proxy's worker thread is blocked in native code on a socket read from the proxy's SOCKS5 port. After Tun2proxy.stop()'s 2s timeout and the 4s thread join both expire (worker still alive), Native.stopProxy() shuts down the Rust runtime — including the listener socket — and the worker, still reading from that socket in native code, hits use-after-free → SIGSEGV. The old code comment claimed "the runtime shutdown will knock the rest of the world over," which was wrong: Native.stopProxy cannot forcibly terminate a separate native thread. New order: Native.stopProxy FIRST (closes the socket → worker's blocking read returns with EOF/error → worker exits cleanly through its error path), then Tun2proxy.stop (cooperative, mostly redundant but cheap), tun.close, then join (almost always immediate now). Thanks @ilok67 again for the precise root-cause work on the second crash.
• Fix tunnel-node batch drain correctness + lock contention (PR #695 from @dazzling-no-more): four bugs, two correctness + two latency.
- Cleanup race dropped tail bytes: when a session's read buffer > 16 MiB and upstream signaled EOF,
drain_nowcorrectly returnedeof=falseand left the tail for the next poll, but the cleanup loop read the raw atomic, sawtrue, removed the session, abortedreader_task, dropped the tail. Cleanup now tracks eof'd sids fromdrain_now's return value — the session is only removed once the drain that returnedeof=truehas shipped to the client. Silent data loss on 1Gbps+ VPS that filled the buffer between polls — fixed. - Sessions-map lock held across upstream awaits: phase-1
dataop held the global sessions map acrosslast_active.lock,writer.lock,write_all, andflush— head-of-line-blocking every other batch and connect/close op. Now (mirroringudp_data's already-correct shape) it clones theArcunder the map lock, drops the lock, then awaits. - Mixed TCP+UDP batch paid the slower side's deadline:
tokio::join!(wait_tcp, wait_udp)is conjunctive — a TCP-ready burst still paid the UDPLONGPOLL_DEADLINE(15 s) before responding. Comment said "either side", code did "both sides". Switched totokio::select!. New testbatch_tcp_ready_does_not_pay_udp_longpoll_deadlinelocks down the regression. - Watcher tasks leaked under
select!cancellation:wait_for_any_drainableonly aborted its watcher tasks in a trailing loop, past every cancellation point. With phase-2 wait flipped toselect!, the loser arm's future drops and detaches its watchers (dropping aJoinHandledoesn't abort). Each orphan held anArc<...Inner>and could steal anotify_one()permit from a future batch. Fix:AbortOnDropnewtype wraps every watcherJoinHandle. 2 new tests + 35/35 pass. • Example config exit-node now listsaistudio.google.comandai.google.dev— requested in #701. AI Studio sanctions Iran IPs (independently of any Apps Script issue on our side). Routing it through the exit-node makes the destination see the exit node's IP, which is neither Iran nor a Google datacenter. • Example config fronting-groups gained Reddit / Fastly / Pinterest / CNN / BuzzFeed family domains (PR #696 from @Shjpr9). All on the Fastly Anycast151.101.x.xedge — gives users a richer starter list to trim down based on what works in their network. • Tests: 179 lib + 35 tunnel-node tests all passing.