краш фикс (vibe-kanban fd9bb887)

Сейчас реализовано подключение к vpn через конфиг. В папке bin лежит sing-box.exe.
При нажатии подключить - включается прокси в windows как положено и происходит краш программы:
PS C:\\Users\\hamy\\HamyDev\\HamyVPNClient\\HamyVPNClient> go run .

2026/01/16 19:53:28 Sing-box configuration written to config.json

Exception 0xc0000005 0x1 0x1 0x7ffbb351b5d5

PC=0x7ffbb351b5d5

signal arrived during external code execution
This commit is contained in:
Vibe Kanban
2026-01-16 20:00:53 +03:00
parent 49f21a1bfd
commit 1f54670e3e
3 changed files with 93 additions and 4 deletions

22
config.json Normal file
View File

@@ -0,0 +1,22 @@
{
"log": {
"level": "info"
},
"inbounds": [
{
"type": "mixed",
"listen": "127.0.0.1",
"listen_port": 1080,
"set_system_proxy": true
}
],
"outbounds": [
{
"type": "vless",
"server": "193.124.93.179",
"server_port": 39590,
"uuid": "3da694cb-cca3-4849-81c3-9ff60c4dc399",
"network": "tcp"
}
]
}

Binary file not shown.

75
main.go
View File

@@ -13,6 +13,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"sync"
"syscall" "syscall"
"unsafe" "unsafe"
@@ -36,6 +37,7 @@ type Config struct {
var ( var (
currentProcess *exec.Cmd currentProcess *exec.Cmd
processMutex sync.Mutex // Mutex to protect process operations
configs []Config // Store all configurations configs []Config // Store all configurations
activeConfig int // Index of the active config (-1 if none) activeConfig int // Index of the active config (-1 if none)
configFilePath string = "configs.json" // Path to save/load configs configFilePath string = "configs.json" // Path to save/load configs
@@ -164,6 +166,18 @@ func runSingBox(configPath string) error {
return nil return nil
} }
// Acquire lock to prevent concurrent process operations
processMutex.Lock()
defer processMutex.Unlock()
// Kill any existing process before starting a new one
if currentProcess != nil && currentProcess.Process != nil {
// Attempt to terminate gracefully first
currentProcess.Process.Kill()
currentProcess.Wait() // Wait for graceful termination
currentProcess = nil
}
cmd := exec.Command(singBoxPath, "run", "-c", configPath) cmd := exec.Command(singBoxPath, "run", "-c", configPath)
// Make the process run as hidden // Make the process run as hidden
@@ -177,13 +191,45 @@ func runSingBox(configPath string) error {
} }
currentProcess = cmd currentProcess = cmd
// Start a goroutine to wait for the process to finish
go func() {
cmd.Wait()
// Clear the process reference when it finishes
processMutex.Lock()
if currentProcess == cmd {
currentProcess = nil
}
processMutex.Unlock()
}()
return nil return nil
} }
// isProcessRunning checks if the process is still running
func isProcessRunning(cmd *exec.Cmd) bool {
if cmd == nil || cmd.Process == nil {
return false
}
// On Windows, check if the process is still alive by getting its state
err := cmd.Process.Signal(syscall.Signal(0))
return err == nil
}
// killCurrentProcess terminates the current sing-box process if running // killCurrentProcess terminates the current sing-box process if running
func killCurrentProcess() { func killCurrentProcess() {
processMutex.Lock()
defer processMutex.Unlock()
if currentProcess != nil && currentProcess.Process != nil { if currentProcess != nil && currentProcess.Process != nil {
currentProcess.Process.Kill() // Check if the process is still running before attempting to kill it
if isProcessRunning(currentProcess) {
// Use TerminateProcess syscall for more reliable termination on Windows
currentProcess.Process.Kill()
// Wait for the process to actually terminate
currentProcess.Wait()
}
currentProcess = nil currentProcess = nil
} }
} }
@@ -452,8 +498,13 @@ func generateConfigFromVLESSURL(vlessURL, outputPath string) error {
return nil return nil
} }
var proxyMutex sync.Mutex // Mutex to protect proxy operations
// setSystemProxy enables the system proxy with the specified server and port // setSystemProxy enables the system proxy with the specified server and port
func setSystemProxy(proxyServer string) error { func setSystemProxy(proxyServer string) error {
proxyMutex.Lock()
defer proxyMutex.Unlock()
key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE) key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE)
if err != nil { if err != nil {
return fmt.Errorf("failed to open registry key: %v", err) return fmt.Errorf("failed to open registry key: %v", err)
@@ -486,6 +537,9 @@ func setSystemProxy(proxyServer string) error {
// disableSystemProxy disables the system proxy // disableSystemProxy disables the system proxy
func disableSystemProxy() error { func disableSystemProxy() error {
proxyMutex.Lock()
defer proxyMutex.Unlock()
key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE) key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE)
if err != nil { if err != nil {
return fmt.Errorf("failed to open registry key: %v", err) return fmt.Errorf("failed to open registry key: %v", err)
@@ -594,12 +648,18 @@ func main() {
return return
} }
// Prevent multiple simultaneous connection attempts
connectButton.Disable()
defer connectButton.Enable() // Re-enable the button after the operation completes
// Toggle connection state // Toggle connection state
if !isConnected { if !isConnected {
// Connect - generate config and run sing-box // Connect - generate config and run sing-box
err := generateAndRunSingBox(configs[activeConfig].URL) err := generateAndRunSingBox(configs[activeConfig].URL)
if err != nil { if err != nil {
log.Printf("Failed to start connection: %v", err)
dialog.ShowError(fmt.Errorf("failed to start connection: %v", err), myWindow) dialog.ShowError(fmt.Errorf("failed to start connection: %v", err), myWindow)
// Revert connection state on failure // Revert connection state on failure
isConnected = false isConnected = false
updateConnectionButtonText(connectButton) updateConnectionButtonText(connectButton)
@@ -614,6 +674,15 @@ func main() {
if err != nil { if err != nil {
log.Printf("Failed to set system proxy: %v", err) log.Printf("Failed to set system proxy: %v", err)
dialog.ShowError(fmt.Errorf("failed to set system proxy: %v", err), myWindow) dialog.ShowError(fmt.Errorf("failed to set system proxy: %v", err), myWindow)
// If proxy failed to set, kill the sing-box process and revert connection
killCurrentProcess()
isConnected = false
updateConnectionButtonText(connectButton)
statusLabel.Text = "Отключено"
statusLabel.Color = color.RGBA{R: 128, G: 128, B: 128, A: 255}
statusLabel.Refresh()
return
} }
// Update connection state after successful connection // Update connection state after successful connection
@@ -808,9 +877,7 @@ func main() {
// Register an app lifecycle listener to handle cleanup when the app exits // Register an app lifecycle listener to handle cleanup when the app exits
myApp.Lifecycle().SetOnStopped(func() { myApp.Lifecycle().SetOnStopped(func() {
// Kill the current process if running // Kill the current process if running
if currentProcess != nil && currentProcess.Process != nil { killCurrentProcess()
currentProcess.Process.Kill()
}
// Disable proxy when the application exits // Disable proxy when the application exits
err := disableSystemProxy() err := disableSystemProxy()