Releases: PoriyaVali/V2bX
Release list
v1.4.3
What this changes
Takes the mdns core whose UDP path can actually carry a DNS answer
(android-multiuser-20260825).
Why v1.4.2 was not enough
v1.4.2 shipped the server half — falling back to the host's resolvers instead of
answering SERVFAIL. It could not help, because the client never delivered a
query to answer. That turned out to be two separate faults in the SOCKS5 UDP
path, and the second was hiding behind the first:
- The UDP ASSOCIATE reply was four bytes short.
To4()on a dual-stack
IPv6 bind returns nil, and appending nil appends nothing. The client read the
port's two bytes as the start of the address and was told to send its DNS to
174.146.0.0:0— so nothing ever arrived. - The datagram reply named its source as
0.0.0.0instead of the target the
client asked about. RFC 1928 §7 puts the source there so a client can match
reply to request; hev checks it, could not match, and dropped every
answer. The query arrived, was resolved, and was thrown away one hop from
the app.
Either alone stops every DNS lookup while leaving TCP untouched — exactly the
shape of the reports: browsers dead on the mdns core while Telegram and WhatsApp
were fine, because those dial fixed IPs and resolve nothing.
Evidence
On a phone against a live tunnel:
| relay endpoint | queries reaching the core | |
|---|---|---|
| before | 174.146.0.0:0 |
0 |
| after fix 1 | 127.0.0.1:56843 |
178 — apps still dead |
| after fix 2 | — | DNS works, confirmed on the device by the owner |
A DNS query sent through the TUN returned nothing while the identical query sent
straight to the core returned real records in 400ms. That differential is what
named the layer.
Notes
- V2bX consumes mdns as source, so this pin bump is the whole delivery.
go mod tidywas deliberately not run: it prunes six indirect
requirements that only exist under this project's build tags (quic-goamong
them, withwith_quicin the build). Only the replace line moved.- Verified with
-mod=readonly, so the build proves go.mod is complete rather
than quietly repairing it.go vetand the CI test scope pass.
v1.4.2
What this changes
Takes the mdns core that answers a DNS lookup instead of dropping it.
The bug
On the mdns core, browsers did not work while Telegram and WhatsApp did. Those
apps dial fixed IPs and resolve nothing; a browser needs ten to thirty names for
one page. Every one of those lookups went unanswered.
Two halves, both now in:
- Client -
ProcessDNSQuerywas fire-and-forget on a cache miss, so the
first lookup of every name got silence and the client had to time out and ask
again. Callers now park on the pending answer and are handed it when it lands,
each under its own transaction id. - Server (the half V2bX runs) - when every configured
DNS_UPSTREAM_SERVERSentry fails, fall back to the nameservers in
/etc/resolv.confbefore answering SERVFAIL. The default upstream is
1.1.1.1; a node that cannot reach it answered SERVFAIL to every tunnelled
lookup while resolving names perfectly well for its own SOCKS5 CONNECT path.
How it was measured
From a phone against a live tunnel, with a control: TCP through the same SOCKS5
returned http 200 in 1.8s while a DNS lookup returned nothing in 10s,
twice. The control is what rules out the tunnel and points at DNS.
The fallback itself was verified on a Linux host - with the configured upstream
pointed at TEST-NET-1: no fallback: err=invalid dns upstream len=0 (FAIL) vs
fallback answered 61 bytes (PASS).
Also
The "upstream failed" log line was Debugf, i.e. invisible at a production log
level - the one line that explained the outage. It is a warning now and names
the upstreams it could not reach. Two paths that dropped a query the client was
still waiting on now say so.
Notes
- V2bX consumes mdns as source, so this pin bump is the whole delivery.
go mod tidywas deliberately not run: it prunes six indirect
requirements that only exist under this project's build tags (quic-goamong
them, withwith_quicin the build). Only the replace line moved.- Verified with
-mod=readonly, so the build proves go.mod is complete rather
than quietly repairing it. - WARNING: not yet verified end to end on a deployed node - that needs this
server running where the tunnel domain is served.
v1.4.1
Fixes the TrustTunnel node dying on every start.
A node's users are synced the moment it appears, so V2bX sent SIGHUP within
milliseconds of spawning the endpoint - before it had installed its handler, when
that signal still terminates the process. The endpoint is now signalled only once
it answers on its metrics port; the credentials file is written first and read at
startup, so nothing is lost by waiting. TrustTunnel v1.0.41-dm.2 fixes the other
half by registering the handler before its runtime starts.
The installer also upgrades the endpoint now instead of installing it once: it
skipped whenever the binaries merely existed, so a node kept whatever endpoint it
first received - including one with a bug it needed fixed. v2bx update refreshes
it for nodes that use that core.
v1.4.0
Adds TrustTunnel as a fourth core.
core/trusttunnelruns the endpoint as a supervised child process: it generates
the config with the endpoint's own wizard, keeps the process alive, applies user
changes with SIGHUP so live connections are not dropped, and reads per-user
traffic back over the endpoint's metrics port.- The installer offers the core and fetches the endpoint binaries for it.
- Endpoint output goes to V2bX's own log at V2bX's own level, instead of a separate
unrotated file.
Note for anyone on v1.3.23: that build has no trusttunnel core, so selecting it in
the wizard produced unknown core type. Each core registers from an init() behind a
build tag, and the tag was missing from the release build; CI now builds with the
release tag set and checks every core name is present in the binary.
v1.3.23
wizard حالا نوع REALITY هر نود را از پنل میخواند
راهنمای ساخت تنظیمات (v2bx menu → ۹) میپرسید «این نود REALITY است؟» و جواب کاربر را منبع دوم حقیقت کنار tls پنل قرار میداد. این دو از هم دور میافتادند — در یک اجرا:
- جواب «نه» برای نودی که در پنل REALITY است → wizard دنبال گرفتن گواهی ACME میرفت برای فایلی که REALITY هرگز نمیخواند
- جواب «بله» برای نودی که TLS معمولی است → گواهیای که آن نود بدون آن استارت نمیشود skip میشد → نود بیصدا بالا نمیآمد
اکنون خود wizard از پنل میپرسد. endpoint config نود همان tls را برمیگرداند که نودِ در حال اجرا REALITY را از آن تشخیص میدهد (api/panel/node.go):
tls=2→ REALITY، مرحلهٔ گواهی رد میشودtls=0/1→ گواهی لازم است و درخواست میشود
پس wizard و نود دیگر نمیتوانند با هم اختلاف داشته باشند.
سؤال دستی بهعنوان fallback میماند برای وقتی پنل هنگام نصب در دسترس نیست — پنلِ دردسترسنبودن هرگز جلوی پیکربندی نود را نمیگیرد، و به کاربر میگوید این مسیر تأییدنشده است. بدون وابستگی اضافی (grep/sed، بدون jq).
dev_new/install.sh خوانده میشود، پس همین حالا فعال است. این release فقط برای هماهنگی v2bx update است.
نصب: v2bx update && v2bx restart
v1.3.22
🔴 رفع: xray v26 همهٔ کلاینتهای غیر-xray را از REALITY رد میکرد
بعد از ارتقا به v26، نود vless هیچکدام از دو هستهٔ اپ را نمیپذیرفت، در حالی که نود anytls روی همان باکس سالم کار میکرد.
هیچ خطی در لاگ نود نمیگفت چیزی رد شده، و یک پروب همچنان گواهی بینقص سایت قرضگرفته را میگرفت — یعنی نود از هر زاویهای که از بیرون قابل دیدن بود سالم به نظر میرسید.
علت: یک پیشفرض عوضشده
در v25، خالی بودن minClientVer یعنی «حداقلی نیست». v26 پُرش میکند:
config.MinClientVer = []byte{26, 3, 27}
"The default minimal client version is Xray-core v26.3.27,
other clients may be refused to connect"و کتابخانهٔ xtls/reality کل احراز هویت را پشت همین مقایسه گذاشته — همان خط hs.c.conn = conn که کلاینت را اصیل علامت میزند.
sing-box و mihomo اصلاً نسخهٔ Xray-core گزارش نمیکنند، پس هر کاربرشان رد میشود، سرور به سایت واقعی fallback میکند، و کلاینت reality verification failed میدهد.
چرا anytls سالم ماند
sing-box خودش REALITY را پیاده کرده و این پیشفرض را اصلاً نمیبیند. همان باکس، همان پروسه، همان کلیدها، همان SNI — تنها تفاوت هسته بود، و همین ایزولهاش کرد.
اصلاح
هر وقت پنل مقداری ندهد، صریحاً "0.0.0" فرستاده میشود — چون خالی بودن دقیقاً همان چیزی است که پیشفرض جدید را فعال میکند. اگر ادمین خودش مقداری بگذارد، همان اعمال میشود.
نصب: v2bx update && v2bx restart
v1.3.21
رفع شکست انتشار v1.3.20
v1.3.20 هیچ asset ای منتشر نکرد — یعنی v2bx update روی آن باینری پیدا نمیکرد. این نسخه همان محتوا را با انتشار سالم میآورد.
چه چیزی شکسته بود
همهٔ پلتفرمها ساخته شدند — windows، linux amd64/386/arm/arm64، darwin — و فقط یک job شکست:
link: github.com/wlynxg/anet: invalid reference to net.zoneCache
ترنسپورت جدید finalmask در xray v26 کتابخانهٔ pion/stun را میآورد، آن هم wlynxg/anet را، و anet با //go:linkname به net.zoneCache دست میزند که Go 1.26 لینک کردنش را رد میکند.
محلی با GOOS=android GOARCH=arm64 بازتولید شد، و -ldflags=-checklinkname=0 واقعاً رفعش میکند.
ولی آن flag را نگذاشتیم
install.sh هیچ حالت android ندارد — هر ماشینی را به یک asset linux-* نگاشت میکند. پس آن zip اصلاً توسط نصبکننده قابل دریافت نبود، و V2bX یک دیمن سمت سرور است که کسی روی گوشی اجرا نمیکند.
خاموش کردن یک بررسی ایمنی زمان لینک روی همهٔ build های آینده، برای نگه داشتن artifact ای که نصبشدنی نیست، معاملهٔ بدی است. دلیلش داخل خود workflow نوشته شد تا نفر بعدی دوباره اضافهاش نکند و به همان دیوار نخورد.
xray v26.7.28 سالم است
همهٔ هدفهای واقعی در همان run شکستخورده هم موفق شده بودند. مشکل هرگز در xray نبود.
تعداد asset از ۴۶ به ۴۴ رسید — zip اندروید و dgst اش رفتند، بقیه دستنخورده.
نصب: v2bx update && v2bx restart
برگشت: v2bx update v1.3.19
v1.3.20
هستهٔ xray به upstream v26.7.28 رسید
هشت ماه عقب بودن روی هستهٔ یک سرویس ضدسانسور خودش یک ریسک است. کتابخانهٔ لینکشده الان core.Version() = 26.7.28 گزارش میکند — این را از کد ساختهشده پرسیدم، نه از روی go.mod.
هیچ import ای عوض نشد — و این برخلاف چیزی بود که انتظار داشتم
xray تگ را به v26 برد ولی مسیر ماژول Go را بامپ نکرد. برای همین go get .../xray-core@v26.x به هر دو شکل شکست میخورد — و برای همین است که فورک ما همیشه v1.YYMMDD.N تگ خورده. خود فورک همان دور زدن است، پس major bump را رایگان جذب میکند.
چهار تغییر واقعی API
| چه چیزی | چه شد |
|---|---|
ExcludeForDomain sniffer |
از []string (تطبیق دستی + regexp:) به geodata.DomainMatcher با یک matcher جدید برای IP. به شکل upstream پورت شد، نه بازپیادهسازی — تا از رفتار واقعی matcher خودش جدا نیفتد |
SniffingConfig.DestOverride |
حالا مقدار است، نه اشارهگر |
IVCheck |
از ShadowsocksServerConfig کامل حذف شد، پس XrayOptions.DisableIVCheck دیگر هیچ کاری نمیکند. اعلانش را نگه داشتیم تا config های موجود پارس شوند، ولی بیاثر است و کد حالا همین را میگوید |
CipherType_NONE |
با shadowsocks بدون رمز حذف شد. none/plain حالا UNKNOWN میشود و inbound ساخته نمیشود — بهتر از اینکه inbound ای بالا بیاید که ترافیک را بدون رمز حمل کند. XCHACHA20_POLY1305 که در v26 جدید است اضافه شد |
⚠️ حذفهای upstream که باید بدانید
xray شش پکیج fake-header مربوط به mKCP را حذف کرده و فقط http و noop مانده. پنج تایی که ما برای ثبت import میکردیم برداشته شد.
نودی که از هدرهای srtp/utp/wechat/wireguard/tls روی mKCP استفاده میکند اصلاً روی v26 کار نمیکند — این حذف مال upstream است، نه تصمیم ما.
پچ فورک
فقط تغییر timestamp کنسول مانده. همراه قدیمیاش که هشدارهای deprecation را ساکت میکرد عمداً خاموش نشده: وقتی تازه هشت ماه پریدهای، هشدار منسوخشدن دقیقاً همان سیگنالی است که ارزش خواندن دارد.
نصب: v2bx update && v2bx restart
برگشت: v2bx update v1.3.19
v1.3.19
ساختهشده با Go 1.26.5 — تنها همین، عمداً
Xray v26 به Go 1.26 نیاز دارد و ما روی ۱.۲۵ بودیم. پس toolchain باید قبل از هسته حرکت کند — و تنها و اول حرکت میکند.
دلیلش: یک کامپایلر جدید همهٔ هستهها را از نو میسازد — sing-box، hysteria2، xray، mdns — با runtime، GC و کتابخانهٔ استاندارد جدید. یعنی سیستمیکترین تغییر ممکن، و آخرین چیزی که باید با چیز دیگری در یک نسخه بیاید.
اگر بعد از این نودی بدرفتاری کرد، دقیقاً یک مظنون وجود دارد.
هیچ چیز دیگری عوض نشده
همان وابستگیها، همان کد. build، go vet و کل مجموعه تست زیر زبان نسخهٔ 1.26.0 پاکاند.
نکتهای که موقع کار پیدا شد
سه جای CI نسخهٔ Go را تعیین میکنند و یکسان نیستند: test.yml و codeql-analysis.yml از go-version-file: go.mod میخوانند، پس دستورهای این فایل آنها را میبرد؛ ولی release.yml یک عدد ثابت دارد که باید دستی عوض شود — و همان یکی است که چیزی را میسازد که مردم نصب میکنند.
GOEXPERIMENT=jsonv2 هنوز لازم است؛ encoding/json/v2 در ۱.۲۶ هم فارغالتحصیل نشده. این را امتحان کردم نه فرض، چون اگر حذف میشد هر دستور build ما سادهتر میشد.
نصب: v2bx update && v2bx restart
برگشت: v2bx update v1.3.18
v1.3.18
هستهٔ hysteria2 به آخرین نسخهٔ رسمی رسید: v2.11.0
بامپ مستقیم وابستگی. برخلاف sing-box و Xray، اینجا نه فورکی داریم نه پچی — پس چیزی برای rebase نبود؛ فقط این سؤال که آیا چهار ماه تغییر upstream سطح API ای که V2bX استفاده میکند را شکسته یا نه.
آن سطح یک پکیج است: core/hy2 که ده پکیج hysteria را import میکند (server, correctnet, masq, obfs, outbounds, sniff, utils, acl, v2geo).
- ✅ همه کامپایل میشود
- ✅
go vetرویcore/hy2پاک است - ✅ کل مجموعه تست سبز
و تأیید شد که ماژول واقعاً جابهجا شد
github.com/apernet/hysteria/core/v2 v2.11.0
github.com/apernet/hysteria/extras/v2 v2.11.0
این مهم است: یک go get که شکست بخورد نسخهٔ قدیمی را سر جایش میگذارد و build بعدش سبز میشود. پس build سبز بهتنهایی هیچ ارزشی ندارد — نسخهٔ حلشده باید خوانده شود.
Xray عمداً در این نسخه نیست
v26 یک major bump گو است — مسیر ماژول به /v26 تغییر میکند — پس قبل از اینکه بشود حتی به چهار ماه تغییر API داخلیاش نگاه کرد، ۱۱۶ خط import در ۱۸ فایل باید عوض شود. هر نسخه یک هسته، تا اگر چیزی خراب شد یک مظنون بیشتر نداشته باشیم.
نصب: v2bx update && v2bx restart
برگشت: v2bx update v1.3.17