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:
BIN
hamy-vpn-client-proxy.exe
Normal file
BIN
hamy-vpn-client-proxy.exe
Normal file
Binary file not shown.
148
main.go
148
main.go
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user