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"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"fyne.io/fyne/v2/app"
|
"fyne.io/fyne/v2/app"
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
@@ -23,6 +24,8 @@ import (
|
|||||||
"fyne.io/fyne/v2/theme"
|
"fyne.io/fyne/v2/theme"
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config represents a VPN configuration
|
// Config represents a VPN configuration
|
||||||
@@ -405,6 +408,82 @@ func generateConfigFromVLESSURL(vlessURL, outputPath string) error {
|
|||||||
return nil
|
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() {
|
func main() {
|
||||||
myApp := app.New()
|
myApp := app.New()
|
||||||
myWindow := myApp.NewWindow("Hamy VPN Client")
|
myWindow := myApp.NewWindow("Hamy VPN Client")
|
||||||
@@ -469,7 +548,42 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Toggle connection state
|
// 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
|
// Update button text
|
||||||
updateConnectionButtonText(connectButton)
|
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.Color = color.RGBA{R: 128, G: 128, B: 128, A: 255} // Gray color for disconnected
|
||||||
}
|
}
|
||||||
statusLabel.Refresh()
|
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
|
connectButton.Importance = widget.HighImportance
|
||||||
if len(configs) == 0 {
|
if len(configs) == 0 {
|
||||||
@@ -646,6 +742,20 @@ func main() {
|
|||||||
// Create a top-level container
|
// Create a top-level container
|
||||||
mainContainer := container.NewStack(contentContainer)
|
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
|
// Set the content and show the window
|
||||||
myWindow.SetContent(mainContainer)
|
myWindow.SetContent(mainContainer)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user