feat(amneziawg): add AmneziaWG as an outbound protocol (#6320)

* feat(amneziawg): add AmneziaWG as an outbound protocol

- AmneziaWG outbound protocol end-to-end: config schema, socks bridge, netstack, panel UI
- Route amneziawg outbounds to HTTP probe in TCP mode (backend + frontend classifiers) with pinning test
- Add 2-minute idle read deadline to pumpUDPEgress to reap idle egress sessions
- Require SOCKS5 username/password auth on the egress server (reject NO-AUTH with 0xFF) with test
- Bound the egress TCP tunnel dial with portForwardDialTimeout (10s), matching portfwd.go
- Resolve UDP domain targets off the association's reader loop via deliverUDPDatagram; race-safe getOrDial starts the reply pump at session creation; client passed by value into resolver goroutines (pinned by TestEgressUDPDatagramDomainInterleavedClients)
- Reconcile early-returns on an empty desired set and closes the egress listener; EgressBasePort (64900) is reserved against local inbound port conflicts like the internal API port, with pinning tests for both the port reservation (TestCheckPortConflict_EgressPortBlockedLocal) and the Reconcile empty-desired Close/Listen lifecycle (TestOutboundManagerReconcileEmptyDesiredClosesEgress)
- Eliminate acceptLoop shutdown race by validating listener != nil and registering to tracked under s.mu before wg.Add; bound pre-auth handshake with deadline (pinned by TestEgressServerCloseDuringConcurrentAccepts)
- Support AAAA and dual-stack domain resolution in tunnel DNS resolver with v6 default fallback (DefaultTunnelDNSServerV6); add DNS field to frontend protocol form; avoid unneeded cache flushes on unchanged SetStack ticks

* fix(amneziawg): resolve IPv6-only DNS default fallback and validate required keys

- Default to IPv6 tunnel DNS on IPv6-only outbounds with blank dns
- Require non-empty secretKey and peer publicKey in ValidateAmneziaWGOutbound
- Add end-to-end IPv6 tunnel domain resolution test and test empty key rejection
- Trim comment blocks exceeding 2 lines across modified files
- Fix Storybook test execution on environments with POSIX locale

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: rqzbeh <rqzbeh@users.noreply.github.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
Rouzbeh†
2026-09-10 16:20:48 +03:30
committed by GitHub
parent 876497db6e
commit d5ab84e8d5
50 changed files with 4169 additions and 33 deletions
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "يضيف بايتات عشوائية إلى نهاية كل حزمة. يتطلب AmneziaWG 3.1+ على الطرفين.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "عدم إرسال ردود الكوكي — يزيل بصمة DPI لكنه يضعف الحماية من الفيضانات."
"disableCookiesHint": "عدم إرسال ردود الكوكي — يزيل بصمة DPI لكنه يضعف الحماية من الفيضانات.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "مستوى المستخدم"
+4 -1
View File
@@ -1975,7 +1975,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Appends random bytes to every packet. Both ends need AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Never send cookie replies — removes a DPI fingerprint; weakens flood mitigation."
"disableCookiesHint": "Never send cookie replies — removes a DPI fingerprint; weakens flood mitigation.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "User Level"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Añade bytes aleatorios a cada paquete. Ambos extremos necesitan AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "No enviar cookie replies — elimina una huella para DPI, pero debilita la mitigación de inundaciones."
"disableCookiesHint": "No enviar cookie replies — elimina una huella para DPI, pero debilita la mitigación de inundaciones.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Nivel de Usuario"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "به انتهای هر بسته بایت‌های تصادفی می‌افزاید. هر دو طرف باید AmneziaWG 3.1+ باشند.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "هرگز پاسخ کوکی ارسال نشود — اثر انگشت DPI را حذف می‌کند اما دفاع در برابر سیل‌آسا را ضعیف می‌کند."
"disableCookiesHint": "هرگز پاسخ کوکی ارسال نشود — اثر انگشت DPI را حذف می‌کند اما دفاع در برابر سیل‌آسا را ضعیف می‌کند.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "سطح کاربر"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Menambahkan byte acak ke setiap paket. Kedua sisi butuh AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Tidak pernah mengirim cookie reply — menghapus sidik jari DPI, tetapi melemahkan mitigasi banjir."
"disableCookiesHint": "Tidak pernah mengirim cookie reply — menghapus sidik jari DPI, tetapi melemahkan mitigasi banjir.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Level Pengguna"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "各パケットにランダムなバイトを追加します。両端にAmneziaWG 3.1+が必要です。",
"disableCookies": "DisableCookies",
"disableCookiesHint": "cookie replyを送信しません。DPIの指紋を消しますが、フラッド緩和は弱まります。"
"disableCookiesHint": "cookie replyを送信しません。DPIの指紋を消しますが、フラッド緩和は弱まります。",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "ユーザーレベル"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Acrescenta bytes aleatórios a cada pacote. Ambos os lados precisam do AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Nunca enviar cookie replies — remove uma impressão digital de DPI, mas enfraquece a mitigação de inundações."
"disableCookiesHint": "Nunca enviar cookie replies — remove uma impressão digital de DPI, mas enfraquece a mitigação de inundações.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Nível do Usuário"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Добавляет случайные байты в конец каждого пакета. Обе стороны должны поддерживать AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Не отправлять cookie reply — убирает сигнатуру для DPI, но ослабляет защиту от флуда."
"disableCookiesHint": "Не отправлять cookie reply — убирает сигнатуру для DPI, но ослабляет защиту от флуда.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Уровень пользователя"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Her paketin sonuna rastgele baytlar ekler. Her iki uç da AmneziaWG 3.1+ gerektirir.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Cookie reply asla gönderilmez — bir DPI parmak izini kaldırır ancak taşma korumasını zayıflatır."
"disableCookiesHint": "Cookie reply asla gönderilmez — bir DPI parmak izini kaldırır ancak taşma korumasını zayıflatır.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Kullanıcı Seviyesi"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Додає випадкові байти в кінець кожного пакета. Обидві сторони мають підтримувати AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Ніколи не надсилати cookie reply — прибирає відбиток для DPI, але послаблює захист від флуду."
"disableCookiesHint": "Ніколи не надсилати cookie reply — прибирає відбиток для DPI, але послаблює захист від флуду.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Рівень користувача"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "Thêm các byte ngẫu nhiên vào cuối mỗi gói. Cả hai đầu cần AmneziaWG 3.1+.",
"disableCookies": "DisableCookies",
"disableCookiesHint": "Không bao giờ gửi cookie reply — xóa một dấu vết DPI nhưng làm yếu khả năng chống flood."
"disableCookiesHint": "Không bao giờ gửi cookie reply — xóa một dấu vết DPI nhưng làm yếu khả năng chống flood.",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "Mức Người Dùng"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "在每个数据包末尾追加随机字节。两端都需要 AmneziaWG 3.1+。",
"disableCookies": "DisableCookies",
"disableCookiesHint": "从不发送 cookie reply——消除一个 DPI 指纹,但会削弱抗洪泛能力。"
"disableCookiesHint": "从不发送 cookie reply——消除一个 DPI 指纹,但会削弱抗洪泛能力。",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "用户级别"
+4 -1
View File
@@ -1857,7 +1857,10 @@
"randomTrailers": "RandomTrailers",
"randomTrailersHint": "在每個封包結尾附加隨機位元組。兩端都需要 AmneziaWG 3.1+。",
"disableCookies": "DisableCookies",
"disableCookiesHint": "永不傳送 cookie reply——消除一個 DPI 指紋,但會削弱抗洪泛能力。"
"disableCookiesHint": "永不傳送 cookie reply——消除一個 DPI 指紋,但會削弱抗洪泛能力。",
"listenPort": "Listen Port (optional)",
"listenPortHint": "Fixed local UDP source port. Leave 0 to pick one automatically.",
"outboundObfuscationHint": "Must exactly match the server side parameters."
},
"tun": {
"userLevel": "用戶級別"