Release 2.6.2: disconnect AWG without freezing the UI.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Navis
2026-07-29 15:50:14 +03:00
co-authored by Cursor
parent 4ecfb9bed7
commit 6255a0d39b
22 changed files with 109 additions and 55 deletions
+3
View File
@@ -243,6 +243,9 @@ https://evilfox.win/
Некоторые AV (Bkav, Microsoft Wacapew/Wacatac, Ikarus Trojan.WinGo.Agent, Google, Trapmine) часто помечают **любые** неподписанные Go-бинарники с сетью и сменой системного прокси.
В 2.6.2:
- быстрое отключение AWG: принудительно закрываются прокси-соединения, UI больше не зависает.
В 2.6.1:
- AmneziaWG: перед подключением Endpoint-хост резолвится в IP (предпочтительно IPv4) — обход сбоя IpcSet на Windows («No such host is known»).
+3 -3
View File
@@ -28,11 +28,11 @@ if errorlevel 1 exit /b 1
go build -o "tools\packmac\packmac.exe" .\tools\packmac
if errorlevel 1 exit /b 1
tools\packmac\packmac.exe -bin "dist\navis-release\darwin-arm64\Navis" -out "dist\navis-release\darwin-arm64" -version 2.6.1 -arch arm64
tools\packmac\packmac.exe -bin "dist\navis-release\darwin-arm64\Navis" -out "dist\navis-release\darwin-arm64" -version 2.6.2 -arch arm64
if errorlevel 1 exit /b 1
tools\packmac\packmac.exe -bin "dist\navis-release\darwin-amd64\Navis" -out "dist\navis-release\darwin-amd64" -version 2.6.1 -arch amd64
tools\packmac\packmac.exe -bin "dist\navis-release\darwin-amd64\Navis" -out "dist\navis-release\darwin-amd64" -version 2.6.2 -arch amd64
if errorlevel 1 exit /b 1
tools\packmac\packmac.exe -bin "dist\navis-release\darwin-universal\Navis" -out "dist\navis-release\darwin-universal" -version 2.6.1 -arch universal
tools\packmac\packmac.exe -bin "dist\navis-release\darwin-universal\Navis" -out "dist\navis-release\darwin-universal" -version 2.6.2 -arch universal
if errorlevel 1 exit /b 1
echo Built:
+1 -2
View File
@@ -296,8 +296,7 @@ func (a *app) connectProfile(name string) error {
}
func (a *app) disconnect() error {
a.mu.Lock()
defer a.mu.Unlock()
// Do not hold a.mu across engine teardown — getState polling would freeze the UI.
return a.mgr.Disconnect()
}
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7 -7
View File
@@ -1,22 +1,22 @@
{
"version": "2.6.1",
"notes": "AWG: любой hostname Endpoint резолвится в IP до подключения (фикс No such host is known)",
"version": "2.6.2",
"notes": "Быстрое отключение AWG без зависания UI («приложение не отвечает»)",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "08f001a3850ca5bd4f73b7ba4d21e8664ee9fc8120a87877f35d8f20a5ed6993",
"sha256": "14fe9afb7978433a811662175ed21e9f65e66420c105ef943ca6f11aeeada072",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "08f001a3850ca5bd4f73b7ba4d21e8664ee9fc8120a87877f35d8f20a5ed6993",
"sha256": "14fe9afb7978433a811662175ed21e9f65e66420c105ef943ca6f11aeeada072",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "b67e8b3fb5db8b97f85dba4c0d307c137c67fb6b56b36f8b2a7adf327ff226d4",
"sha256": "497cdf66b74e28061622debbbc6fa922ae64ae532e867dec876188af15e85278",
"os": "darwin",
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
@@ -24,7 +24,7 @@
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "37385c52cb397f60acc699adecb0ffc1843106d50288b1304393daf63083b4b7",
"sha256": "95ccb649116bd15cbcdddccdd57df77651bf5f41ec19a4c6a0e91f8139621df7",
"os": "darwin",
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
@@ -32,7 +32,7 @@
},
"darwin-universal": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis",
"sha256": "ce250733cc7f5ed50b42f5cc106be9872b057966e7a73bcee78974d85748c2fb",
"sha256": "abdb4d5807145dfab7afa1fc9fd4d0382a4f5d9b4ce7621128b2b393c7f0c928",
"os": "darwin",
"arch": "universal",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg",
+7 -7
View File
@@ -1,22 +1,22 @@
{
"version": "2.6.1",
"notes": "AWG: любой hostname Endpoint резолвится в IP до подключения (фикс No such host is known)",
"version": "2.6.2",
"notes": "Быстрое отключение AWG без зависания UI («приложение не отвечает»)",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "08f001a3850ca5bd4f73b7ba4d21e8664ee9fc8120a87877f35d8f20a5ed6993",
"sha256": "14fe9afb7978433a811662175ed21e9f65e66420c105ef943ca6f11aeeada072",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "08f001a3850ca5bd4f73b7ba4d21e8664ee9fc8120a87877f35d8f20a5ed6993",
"sha256": "14fe9afb7978433a811662175ed21e9f65e66420c105ef943ca6f11aeeada072",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "b67e8b3fb5db8b97f85dba4c0d307c137c67fb6b56b36f8b2a7adf327ff226d4",
"sha256": "497cdf66b74e28061622debbbc6fa922ae64ae532e867dec876188af15e85278",
"os": "darwin",
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
@@ -24,7 +24,7 @@
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "37385c52cb397f60acc699adecb0ffc1843106d50288b1304393daf63083b4b7",
"sha256": "95ccb649116bd15cbcdddccdd57df77651bf5f41ec19a4c6a0e91f8139621df7",
"os": "darwin",
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
@@ -32,7 +32,7 @@
},
"darwin-universal": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis",
"sha256": "ce250733cc7f5ed50b42f5cc106be9872b057966e7a73bcee78974d85748c2fb",
"sha256": "abdb4d5807145dfab7afa1fc9fd4d0382a4f5d9b4ce7621128b2b393c7f0c928",
"os": "darwin",
"arch": "universal",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg",
+1 -1
View File
@@ -725,7 +725,7 @@
<div class="brand-wrap">
<div class="brand-row">
<h1 class="brand">Navis</h1>
<span class="badge-ver">2.6.1</span>
<span class="badge-ver">2.6.2</span>
</div>
<p class="tagline">Быстрый клиент · Naive · Hy2 · AWG · Xray</p>
</div>
+19 -7
View File
@@ -100,21 +100,33 @@ func (m *Manager) Connect(ctx context.Context, profileName string) error {
func (m *Manager) Disconnect() error {
m.mu.Lock()
defer m.mu.Unlock()
sys := m.sys
engine := m.engine
m.engine = nil
m.profile = nil
m.mu.Unlock()
var first error
if m.sys.Enabled() {
if err := m.sys.Disable(); err != nil && first == nil {
if sys != nil && sys.Enabled() {
if err := sys.Disable(); err != nil && first == nil {
first = err
}
}
if m.engine != nil {
if err := m.engine.Stop(); err != nil && first == nil {
if engine != nil {
done := make(chan error, 1)
go func() { done <- engine.Stop() }()
select {
case err := <-done:
if err != nil && first == nil {
first = err
}
m.engine = nil
case <-time.After(3 * time.Second):
// Engine Stop can block on userspace relays; don't freeze the UI.
if first == nil {
first = fmt.Errorf("отключение заняло слишком много времени")
}
}
}
m.profile = nil
return first
}
+5 -4
View File
@@ -120,15 +120,16 @@ func (e *Engine) stopLocked() error {
if !e.running {
return nil
}
if e.proxies != nil {
_ = e.proxies.Close()
e.proxies = nil
}
// Close device first so tun/netstack dials fail and relays exit promptly.
if e.dev != nil {
e.dev.Close()
e.dev = nil
}
e.tnet = nil
if e.proxies != nil {
_ = e.proxies.Close()
e.proxies = nil
}
e.running = false
return nil
}
+43 -4
View File
@@ -25,10 +25,14 @@ type proxyServer struct {
closed bool
socksAddr string
httpAddr string
conns map[net.Conn]struct{}
}
func startProxies(socksHostPort, httpHostPort string, dial DialFunc) (*proxyServer, error) {
s := &proxyServer{dial: dial}
s := &proxyServer{
dial: dial,
conns: make(map[net.Conn]struct{}),
}
if socksHostPort != "" {
ln, err := net.Listen("tcp", socksHostPort)
if err != nil {
@@ -53,6 +57,22 @@ func startProxies(socksHostPort, httpHostPort string, dial DialFunc) (*proxyServ
return s, nil
}
func (s *proxyServer) track(c net.Conn) {
s.mu.Lock()
defer s.mu.Unlock()
if s.closed {
_ = c.Close()
return
}
s.conns[c] = struct{}{}
}
func (s *proxyServer) untrack(c net.Conn) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.conns, c)
}
func (s *proxyServer) Close() error {
s.mu.Lock()
if s.closed {
@@ -66,8 +86,23 @@ func (s *proxyServer) Close() error {
if s.httpLn != nil {
_ = s.httpLn.Close()
}
// Force-close active relays so io.Copy / dial wake up immediately.
for c := range s.conns {
_ = c.Close()
}
s.conns = nil
s.mu.Unlock()
done := make(chan struct{})
go func() {
s.wg.Wait()
close(done)
}()
select {
case <-done:
case <-time.After(1500 * time.Millisecond):
// Don't hang UI / Disconnect on stuck netstack copies.
}
return nil
}
@@ -81,6 +116,8 @@ func (s *proxyServer) serveSOCKS() {
s.wg.Add(1)
go func(conn net.Conn) {
defer s.wg.Done()
s.track(conn)
defer s.untrack(conn)
_ = handleSOCKS(conn, s.dial)
}(c)
}
@@ -96,6 +133,8 @@ func (s *proxyServer) serveHTTP() {
s.wg.Add(1)
go func(conn net.Conn) {
defer s.wg.Done()
s.track(conn)
defer s.untrack(conn)
_ = handleHTTPProxy(conn, s.dial)
}(c)
}
@@ -156,7 +195,7 @@ func handleSOCKS(client net.Conn, dial DialFunc) error {
port := binary.BigEndian.Uint16(buf[:2])
_ = client.SetDeadline(time.Time{})
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
remote, err := dial(ctx, "tcp", net.JoinHostPort(host, fmt.Sprintf("%d", port)))
if err != nil {
@@ -185,7 +224,7 @@ func handleHTTPProxy(client net.Conn, dial DialFunc) error {
if !strings.Contains(host, ":") {
host += ":443"
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
remote, err := dial(ctx, "tcp", host)
if err != nil {
@@ -212,7 +251,7 @@ func handleHTTPProxy(client net.Conn, dial DialFunc) error {
if !strings.Contains(host, ":") {
host += ":80"
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
remote, err := dial(ctx, "tcp", host)
if err != nil {
+1 -1
View File
@@ -17,7 +17,7 @@ import (
)
// CurrentVersion is the shipped client version.
const CurrentVersion = "2.6.1"
const CurrentVersion = "2.6.2"
// DefaultManifestURL is the update feed (hosted in the project git repo).
const DefaultManifestURL = "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/update.json"
+7 -7
View File
@@ -1,22 +1,22 @@
{
"version": "2.6.1",
"notes": "AWG: любой hostname Endpoint резолвится в IP до подключения (фикс No such host is known)",
"version": "2.6.2",
"notes": "Быстрое отключение AWG без зависания UI («приложение не отвечает»)",
"platform": "windows-amd64",
"os": "windows",
"arch": "amd64",
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "08f001a3850ca5bd4f73b7ba4d21e8664ee9fc8120a87877f35d8f20a5ed6993",
"sha256": "14fe9afb7978433a811662175ed21e9f65e66420c105ef943ca6f11aeeada072",
"mandatory": false,
"platforms": {
"windows-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/Navis.exe",
"sha256": "08f001a3850ca5bd4f73b7ba4d21e8664ee9fc8120a87877f35d8f20a5ed6993",
"sha256": "14fe9afb7978433a811662175ed21e9f65e66420c105ef943ca6f11aeeada072",
"os": "windows",
"arch": "amd64"
},
"darwin-arm64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis",
"sha256": "b67e8b3fb5db8b97f85dba4c0d307c137c67fb6b56b36f8b2a7adf327ff226d4",
"sha256": "497cdf66b74e28061622debbbc6fa922ae64ae532e867dec876188af15e85278",
"os": "darwin",
"arch": "arm64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg",
@@ -24,7 +24,7 @@
},
"darwin-amd64": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis",
"sha256": "37385c52cb397f60acc699adecb0ffc1843106d50288b1304393daf63083b4b7",
"sha256": "95ccb649116bd15cbcdddccdd57df77651bf5f41ec19a4c6a0e91f8139621df7",
"os": "darwin",
"arch": "amd64",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-amd64/Navis.dmg",
@@ -32,7 +32,7 @@
},
"darwin-universal": {
"url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis",
"sha256": "ce250733cc7f5ed50b42f5cc106be9872b057966e7a73bcee78974d85748c2fb",
"sha256": "abdb4d5807145dfab7afa1fc9fd4d0382a4f5d9b4ce7621128b2b393c7f0c928",
"os": "darwin",
"arch": "universal",
"dmg_url": "https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-universal/Navis.dmg",
+4 -4
View File
@@ -1,7 +1,7 @@
{
"FixedFileInfo": {
"FileVersion": { "Major": 2, "Minor": 6, "Patch": 1, "Build": 0 },
"ProductVersion": { "Major": 2, "Minor": 6, "Patch": 1, "Build": 0 },
"FileVersion": { "Major": 2, "Minor": 6, "Patch": 2, "Build": 0 },
"ProductVersion": { "Major": 2, "Minor": 6, "Patch": 2, "Build": 0 },
"FileFlagsMask": "3f",
"FileFlags": "00",
"FileOS": "40004",
@@ -11,12 +11,12 @@
"StringFileInfo": {
"CompanyName": "EvilFox",
"FileDescription": "Navis 2 — VPN client (Naive / Hy2 / AWG / VLESS / VMess / Trojan)",
"FileVersion": "2.6.1.0",
"FileVersion": "2.6.2.0",
"InternalName": "Navis",
"LegalCopyright": "Copyright (c) EvilFox",
"OriginalFilename": "Navis.exe",
"ProductName": "Navis",
"ProductVersion": "2.6.1.0",
"ProductVersion": "2.6.2.0",
"Comments": "Open-source VPN/proxy client. https://evilfox.win/"
},
"VarFileInfo": {