From 2534bbe96ae22af9fc17c322b337aa37ae77f086 Mon Sep 17 00:00:00 2001 From: samosvalishe Date: Mon, 8 Jun 2026 08:34:45 +0300 Subject: [PATCH] =?UTF-8?q?fix(turndial):=20=D0=B4=D0=B5=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=20=D0=B1=D0=BB=D1=8D=D0=BA=D1=85=D0=BE=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=20ChannelBind,=20=D0=BD=D0=B5=20CreatePermission?= =?UTF-8?q?=20refresh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VK реджектит standalone CreatePermission refresh с 400 независимо от здоровья стрима, поэтому permWatch ложно рециклил здоровые аллокации каждые ~60s. Permission держится живым через ChannelBind refresh (RFC 8656 §11), стандартный для VK путь, потому отдельный CreatePermission refresh глушим (PermissionRefreshInterval 24h). Реальный блэкхол ловим по провалу ChannelBind refresh (data-path), сброс на успешном байнде. --- internal/proxy/udprelay/loop.go | 4 ++-- internal/transport/turndial/permwatch.go | 10 +++------- internal/transport/turndial/turndial.go | 10 ++++++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/internal/proxy/udprelay/loop.go b/internal/proxy/udprelay/loop.go index f5b1355..b3664fd 100644 --- a/internal/proxy/udprelay/loop.go +++ b/internal/proxy/udprelay/loop.go @@ -271,13 +271,13 @@ func oneTURN(ctx context.Context, deps *Deps, params *Params, peer *net.UDPAddr, const maxPayload = 1600 - // PermDead закрывается при блэкхоле permission (см. turndial/permwatch.go) — + // PermDead закрывается при блэкхоле data-path (см. turndial/permwatch.go) — // отменяем turnctx, TURNLoop делает свежий allocate. wg.Go(func() { select { case <-turnctx.Done(): case <-stream.PermDead: - deps.log().Warnf("[STREAM %d] TURN permission refresh умер — рецикл allocation", streamID) + deps.log().Warnf("[STREAM %d] TURN channel-bind умер — рецикл allocation", streamID) turncancel() } }) diff --git a/internal/transport/turndial/permwatch.go b/internal/transport/turndial/permwatch.go index 9497d97..08ca6a7 100644 --- a/internal/transport/turndial/permwatch.go +++ b/internal/transport/turndial/permwatch.go @@ -7,15 +7,11 @@ import ( "github.com/pion/logging" ) -// VK relay при дропе permission молча роняет пакеты к peer без ошибки записи. -// pion на каждый проваленный цикл refresh пишет permFailMarker (Warnf, scope -// "turnc"). Считаем провалы подряд — точный per-stream детект блэкхола вместо -// трафик-эвристики (обратный путь WG привязан к endpoint, не к стриму). const ( - permFailMarker = "Failed to refresh permissions" - permOKMarker = "Refresh permissions successful" + permFailMarker = "Failed to bind channel" + permOKMarker = "Channel binding successful" turncScope = "turnc" - // ~60s при PermissionRefreshInterval=30s, внутри 5-мин lifetime permission. + // ChannelBind refresh идёт ~раз в 5 мин (binding lifetime); 2 провала подряд. permFailThreshold = 2 ) diff --git a/internal/transport/turndial/turndial.go b/internal/transport/turndial/turndial.go index 0a886ea..613b401 100644 --- a/internal/transport/turndial/turndial.go +++ b/internal/transport/turndial/turndial.go @@ -37,8 +37,8 @@ type Stream struct { Relay net.PacketConn // ServerUDPAddr — резолвнутый UDP-адрес TURN-сервера (host:port). ServerUDPAddr *net.UDPAddr - // PermDead закрывается при стойком провале refresh permission (relay - // блэкхолит) — вызывающий рециклит allocation. См. permwatch.go. + // PermDead закрывается при стойком провале ChannelBind refresh (relay + // блэкхолит data-path) - вызывающий рециклит allocation. См. permwatch.go. PermDead <-chan struct{} close func() error } @@ -108,7 +108,9 @@ func Open(ctx context.Context, cfg Config, peer *net.UDPAddr, user, pass, rawAdd addrFamily = turn.RequestedAddressFamilyIPv6 } - // RefreshInterval 120s→30s: быстрее ловим блэкхол, внутри 5-мин lifetime. + // Standalone CreatePermission refresh VK реджектит 400 — глушим (24h). + // Permission держится живым через ChannelBind refresh (RFC 8656 §11); + // блэкхол ловим по провалу этого байнда (см. permwatch.go). permDead := make(chan struct{}) var permOnce sync.Once loggerFactory := &permWatchFactory{ @@ -124,7 +126,7 @@ func Open(ctx context.Context, cfg Config, peer *net.UDPAddr, user, pass, rawAdd Username: user, Password: pass, RequestedAddressFamily: addrFamily, - PermissionRefreshInterval: 30 * time.Second, + PermissionRefreshInterval: 24 * time.Hour, LoggerFactory: loggerFactory, }) if err != nil {