4. Управление системным прокси (vibe-kanban d1a01027)

Чтобы интернет пошел через VPN, нужно менять настройки прокси в Windows. Напиши функции для изменения реестра Windows:

1. Путь: `HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings`.
2. Параметры: `ProxyEnable` (1 или 0) и `ProxyServer` ("127.0.0.1:1080").
Программа должна автоматически выключать прокси при выходе из приложения или при отключении vpn
This commit is contained in:
Vibe Kanban
2026-01-16 19:31:18 +03:00
parent 2704069be1
commit 0bc4f92e06
2 changed files with 129 additions and 19 deletions

BIN
hamy-vpn-client-proxy.exe Normal file

Binary file not shown.

148
main.go
View File

@@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"syscall"
"unsafe"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/canvas"
@@ -23,6 +24,8 @@ import (
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"fyne.io/fyne/v2"
"golang.org/x/sys/windows/registry"
)
// Config represents a VPN configuration
@@ -405,6 +408,82 @@ func generateConfigFromVLESSURL(vlessURL, outputPath string) error {
return nil
}
// setSystemProxy enables the system proxy with the specified server and port
func setSystemProxy(proxyServer string) error {
key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE)
if err != nil {
return fmt.Errorf("failed to open registry key: %v", err)
}
defer key.Close()
// Set ProxyEnable to 1 to enable proxy
err = key.SetDWordValue("ProxyEnable", 1)
if err != nil {
return fmt.Errorf("failed to set ProxyEnable: %v", err)
}
// Set ProxyServer to the specified server and port
err = key.SetStringValue("ProxyServer", proxyServer)
if err != nil {
return fmt.Errorf("failed to set ProxyServer: %v", err)
}
// Optionally, set ProxyOverride to bypass proxy for local addresses
err = key.SetStringValue("ProxyOverride", "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*")
if err != nil {
return fmt.Errorf("failed to set ProxyOverride: %v", err)
}
// Notify Windows that the proxy settings have changed
notifyProxyChange()
return nil
}
// disableSystemProxy disables the system proxy
func disableSystemProxy() error {
key, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Internet Settings`, registry.SET_VALUE)
if err != nil {
return fmt.Errorf("failed to open registry key: %v", err)
}
defer key.Close()
// Set ProxyEnable to 0 to disable proxy
err = key.SetDWordValue("ProxyEnable", 0)
if err != nil {
return fmt.Errorf("failed to set ProxyEnable: %v", err)
}
// Notify Windows that the proxy settings have changed
notifyProxyChange()
return nil
}
// notifyProxyChange notifies Windows that proxy settings have changed
func notifyProxyChange() {
// Use Windows API to notify about proxy change
// Call InternetSetOption to refresh proxy settings
procInternetSetOption := syscall.NewLazyDLL("wininet.dll").NewProc("InternetSetOptionW")
procInternetSetOption.Call(
0, // hInternet = NULL
39, // INTERNET_OPTION_SETTINGS_CHANGED
0, // lpBuffer = NULL
0, // dwBufferLength = 0
)
// Also send WM_SETTINGCHANGE to broadcast the change
procSendMessageTimeout := syscall.NewLazyDLL("user32.dll").NewProc("SendMessageTimeoutW")
procSendMessageTimeout.Call(
0xFFFF, // HWND_BROADCAST
0x001A, // WM_SETTINGCHANGE
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Proxy"))),
0,
0x0002, // SMTO_ABORTIFHUNG
5000, // timeout
)
}
func main() {
myApp := app.New()
myWindow := myApp.NewWindow("Hamy VPN Client")
@@ -469,7 +548,42 @@ func main() {
}
// Toggle connection state
isConnected = !isConnected
if !isConnected {
// Connect - generate config and run sing-box
err := generateAndRunSingBox(configs[activeConfig].URL)
if err != nil {
dialog.ShowError(fmt.Errorf("failed to start connection: %v", err), myWindow)
// Revert connection state on failure
isConnected = false
updateConnectionButtonText(connectButton)
statusLabel.Text = "Отключено"
statusLabel.Color = color.RGBA{R: 128, G: 128, B: 128, A: 255}
statusLabel.Refresh()
return
}
// Set proxy to route traffic through VPN
err = setSystemProxy("127.0.0.1:1080")
if err != nil {
log.Printf("Failed to set system proxy: %v", err)
dialog.ShowError(fmt.Errorf("failed to set system proxy: %v", err), myWindow)
}
// Update connection state after successful connection
isConnected = true
} else {
// Disconnect - kill the current process
killCurrentProcess()
// Disable proxy when disconnecting from VPN
err := disableSystemProxy()
if err != nil {
log.Printf("Failed to disable system proxy: %v", err)
}
// Update connection state after disconnection
isConnected = false
}
// Update button text
updateConnectionButtonText(connectButton)
@@ -483,24 +597,6 @@ func main() {
statusLabel.Color = color.RGBA{R: 128, G: 128, B: 128, A: 255} // Gray color for disconnected
}
statusLabel.Refresh()
if isConnected {
// Disconnect - kill the current process
killCurrentProcess()
} else {
// Connect - generate config and run sing-box
err := generateAndRunSingBox(configs[activeConfig].URL)
if err != nil {
dialog.ShowError(fmt.Errorf("failed to start connection: %v", err), myWindow)
// Revert connection state
isConnected = false
updateConnectionButtonText(connectButton)
statusLabel.Text = "Отключено"
statusLabel.Color = color.RGBA{R: 128, G: 128, B: 128, A: 255}
statusLabel.Refresh()
return
}
}
})
connectButton.Importance = widget.HighImportance
if len(configs) == 0 {
@@ -646,6 +742,20 @@ func main() {
// Create a top-level container
mainContainer := container.NewStack(contentContainer)
// Register an app lifecycle listener to handle cleanup when the app exits
myApp.Lifecycle().SetOnStopped(func() {
// Kill the current process if running
if currentProcess != nil && currentProcess.Process != nil {
currentProcess.Process.Kill()
}
// Disable proxy when the application exits
err := disableSystemProxy()
if err != nil {
log.Printf("Failed to disable system proxy on exit: %v", err)
}
})
// Set the content and show the window
myWindow.SetContent(mainContainer)