新增本机代理获取方法
This commit is contained in:
173
internal/proxy.go
Normal file
173
internal/proxy.go
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProxyInfo 保存当前系统代理信息
|
||||||
|
type ProxyInfo struct {
|
||||||
|
// 是否启用了系统代理
|
||||||
|
Enabled bool
|
||||||
|
// 系统代理服务器地址 (例如 127.0.0.1:7890)
|
||||||
|
Server string
|
||||||
|
// 代理协议 (http, https, socks5)
|
||||||
|
Protocol string
|
||||||
|
// HTTP_PROXY 环境变量
|
||||||
|
HTTPProxy string
|
||||||
|
// HTTPS_PROXY 环境变量
|
||||||
|
HTTPSProxy string
|
||||||
|
// 代理绕过列表
|
||||||
|
Bypass string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentProxy 获取本机当前的代理设置
|
||||||
|
// 优先读取 Windows 系统代理(注册表),同时也读取环境变量中的代理配置
|
||||||
|
// 支持检测 Clash、V2Ray 等常见代理工具的配置
|
||||||
|
func GetCurrentProxy() (*ProxyInfo, error) {
|
||||||
|
info := &ProxyInfo{}
|
||||||
|
|
||||||
|
// 1. 从环境变量读取代理
|
||||||
|
info.HTTPProxy = getEnvProxy("HTTP_PROXY", "http_proxy")
|
||||||
|
info.HTTPSProxy = getEnvProxy("HTTPS_PROXY", "https_proxy")
|
||||||
|
|
||||||
|
// 2. 从 Windows 注册表读取系统代理设置
|
||||||
|
if err := readWindowsSystemProxy(info); err != nil {
|
||||||
|
// 注册表读取失败不算致命错误,环境变量中可能仍有代理信息
|
||||||
|
fmt.Printf("读取系统代理设置时出错: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 如果系统代理未启用,尝试从环境变量推断
|
||||||
|
if !info.Enabled && (info.HTTPProxy != "" || info.HTTPSProxy != "") {
|
||||||
|
info.Enabled = true
|
||||||
|
proxy := info.HTTPProxy
|
||||||
|
if proxy == "" {
|
||||||
|
proxy = info.HTTPSProxy
|
||||||
|
}
|
||||||
|
info.Server = extractServerFromURL(proxy)
|
||||||
|
info.Protocol = extractProtocolFromURL(proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readWindowsSystemProxy 从 Windows 注册表读取系统代理设置
|
||||||
|
func readWindowsSystemProxy(info *ProxyInfo) error {
|
||||||
|
key, err := registry.OpenKey(
|
||||||
|
registry.CURRENT_USER,
|
||||||
|
`Software\Microsoft\Windows\CurrentVersion\Internet Settings`,
|
||||||
|
registry.QUERY_VALUE,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("无法打开注册表键: %w", err)
|
||||||
|
}
|
||||||
|
defer key.Close()
|
||||||
|
|
||||||
|
// 读取代理是否启用 (ProxyEnable: 0=关闭, 1=开启)
|
||||||
|
proxyEnable, _, err := key.GetIntegerValue("ProxyEnable")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("无法读取 ProxyEnable: %w", err)
|
||||||
|
}
|
||||||
|
info.Enabled = proxyEnable == 1
|
||||||
|
|
||||||
|
// 读取代理服务器地址
|
||||||
|
proxyServer, _, err := key.GetStringValue("ProxyServer")
|
||||||
|
if err == nil && proxyServer != "" {
|
||||||
|
info.Server = proxyServer
|
||||||
|
// 根据端口推断代理协议
|
||||||
|
info.Protocol = guessProtocol(proxyServer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取代理绕过列表
|
||||||
|
bypass, _, err := key.GetStringValue("ProxyOverride")
|
||||||
|
if err == nil {
|
||||||
|
info.Bypass = bypass
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEnvProxy 依次检查多个环境变量名,返回第一个非空值
|
||||||
|
func getEnvProxy(names ...string) string {
|
||||||
|
for _, name := range names {
|
||||||
|
if v := os.Getenv(name); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractServerFromURL 从代理 URL 中提取 host:port 部分
|
||||||
|
// 例如 "http://127.0.0.1:7890" -> "127.0.0.1:7890"
|
||||||
|
func extractServerFromURL(proxyURL string) string {
|
||||||
|
s := proxyURL
|
||||||
|
// 去掉协议前缀
|
||||||
|
if idx := strings.Index(s, "://"); idx != -1 {
|
||||||
|
s = s[idx+3:]
|
||||||
|
}
|
||||||
|
// 去掉尾部斜杠
|
||||||
|
s = strings.TrimRight(s, "/")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractProtocolFromURL 从代理 URL 中提取协议
|
||||||
|
// 例如 "socks5://127.0.0.1:7891" -> "socks5"
|
||||||
|
func extractProtocolFromURL(proxyURL string) string {
|
||||||
|
if idx := strings.Index(proxyURL, "://"); idx != -1 {
|
||||||
|
return proxyURL[:idx]
|
||||||
|
}
|
||||||
|
return "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
// guessProtocol 根据代理服务器地址猜测代理协议
|
||||||
|
// Clash 默认: 7890(http), 7891(socks5)
|
||||||
|
// V2Ray 默认: 10808(socks5), 10809(http)
|
||||||
|
func guessProtocol(server string) string {
|
||||||
|
knownPorts := map[string]string{
|
||||||
|
"7890": "http", // Clash HTTP
|
||||||
|
"7891": "socks5", // Clash SOCKS5
|
||||||
|
"7892": "http", // Clash mixed
|
||||||
|
"10808": "socks5", // V2Ray SOCKS5
|
||||||
|
"10809": "http", // V2Ray HTTP
|
||||||
|
"1080": "socks5", // 通用 SOCKS5
|
||||||
|
"1081": "http", // 通用 HTTP
|
||||||
|
"8080": "http", // 通用 HTTP
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(server, ":")
|
||||||
|
if len(parts) >= 2 {
|
||||||
|
port := parts[len(parts)-1]
|
||||||
|
if protocol, ok := knownPorts[port]; ok {
|
||||||
|
return protocol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "http"
|
||||||
|
}
|
||||||
|
|
||||||
|
// String 返回代理信息的可读字符串
|
||||||
|
func (p *ProxyInfo) String() string {
|
||||||
|
if !p.Enabled {
|
||||||
|
return "当前未检测到系统代理"
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("当前系统代理信息:\n")
|
||||||
|
sb.WriteString(" 状态: 已启用\n")
|
||||||
|
fmt.Fprintf(&sb, " 服务器: %s\n", p.Server)
|
||||||
|
fmt.Fprintf(&sb, " 协议: %s\n", p.Protocol)
|
||||||
|
|
||||||
|
if p.Bypass != "" {
|
||||||
|
fmt.Fprintf(&sb, " 绕过: %s\n", p.Bypass)
|
||||||
|
}
|
||||||
|
if p.HTTPProxy != "" {
|
||||||
|
fmt.Fprintf(&sb, " HTTP_PROXY: %s\n", p.HTTPProxy)
|
||||||
|
}
|
||||||
|
if p.HTTPSProxy != "" {
|
||||||
|
fmt.Fprintf(&sb, " HTTPS_PROXY: %s\n", p.HTTPSProxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user