Skip to content

Releases: PoriyaVali/V2bX

v1.4.3

Choose a tag to compare

@PoriyaVali PoriyaVali released this 25 Aug 16:06

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:

  1. 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.
  2. The datagram reply named its source as 0.0.0.0 instead 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 tidy was deliberately not run: it prunes six indirect
    requirements that only exist under this project's build tags (quic-go among
    them, with with_quic in 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 vet and the CI test scope pass.

v1.4.2

Choose a tag to compare

@PoriyaVali PoriyaVali released this 25 Aug 06:52

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 - ProcessDNSQuery was 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_SERVERS entry fails, fall back to the nameservers in
    /etc/resolv.conf before 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 tidy was deliberately not run: it prunes six indirect
    requirements that only exist under this project's build tags (quic-go among
    them, with with_quic in 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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 17 Aug 08:09

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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 17 Aug 07:47

Adds TrustTunnel as a fourth core.

  • core/trusttunnel runs 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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 02 Aug 13:25

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).

⚠️ این فقط wizard است — باینری تغییری نکرده. wizard زنده از dev_new/install.sh خوانده می‌شود، پس همین حالا فعال است. این release فقط برای هماهنگی v2bx update است.

نصب: v2bx update && v2bx restart

v1.3.22

Choose a tag to compare

@PoriyaVali PoriyaVali released this 01 Aug 16:30

🔴 رفع: 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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 01 Aug 16:06

رفع شکست انتشار 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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 01 Aug 15: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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 01 Aug 15:04

ساخته‌شده با 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

Choose a tag to compare

@PoriyaVali PoriyaVali released this 01 Aug 14:30

هستهٔ 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