op http client proxy

This commit is contained in:
beck-8
2025-06-19 22:52:51 +08:00
parent 2567652a7d
commit 8c127a795b
7 changed files with 396 additions and 426 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.idea
.vscode
.DS_Store
hubproxy*

View File

@@ -138,11 +138,17 @@ blackList = [
"baduser/*"
]
# SOCKS5代理配置,支持有用户名/密码认证和无认证模式
# 代理配置,支持有用户名/密码认证和无认证模式
# 无认证: socks5://127.0.0.1:1080
# 有认证: socks5://username:password@127.0.0.1:1080
# HTTP 代理示例
# http://username:password@127.0.0.1:7890
# SOCKS5 代理示例
# socks5://username:password@127.0.0.1:1080
# SOCKS5H 代理示例
# socks5h://username:password@127.0.0.1:1080
# 留空不使用代理
socks5 = ""
proxy = ""
[download]
# 批量下载离线镜像数量限制

View File

@@ -85,15 +85,15 @@ func (ac *AccessController) CheckDockerAccess(image string) (allowed bool, reaso
imageInfo := ac.ParseDockerImage(image)
// 检查白名单(如果配置了白名单,则只允许白名单中的镜像)
if len(cfg.Proxy.WhiteList) > 0 {
if !ac.matchImageInList(imageInfo, cfg.Proxy.WhiteList) {
if len(cfg.Access.WhiteList) > 0 {
if !ac.matchImageInList(imageInfo, cfg.Access.WhiteList) {
return false, "不在Docker镜像白名单内"
}
}
// 检查黑名单
if len(cfg.Proxy.BlackList) > 0 {
if ac.matchImageInList(imageInfo, cfg.Proxy.BlackList) {
if len(cfg.Access.BlackList) > 0 {
if ac.matchImageInList(imageInfo, cfg.Access.BlackList) {
return false, "Docker镜像在黑名单内"
}
}
@@ -110,12 +110,12 @@ func (ac *AccessController) CheckGitHubAccess(matches []string) (allowed bool, r
cfg := GetConfig()
// 检查白名单
if len(cfg.Proxy.WhiteList) > 0 && !ac.checkList(matches, cfg.Proxy.WhiteList) {
if len(cfg.Access.WhiteList) > 0 && !ac.checkList(matches, cfg.Access.WhiteList) {
return false, "不在GitHub仓库白名单内"
}
// 检查黑名单
if len(cfg.Proxy.BlackList) > 0 && ac.checkList(matches, cfg.Proxy.BlackList) {
if len(cfg.Access.BlackList) > 0 && ac.checkList(matches, cfg.Access.BlackList) {
return false, "GitHub仓库在黑名单内"
}
@@ -210,5 +210,3 @@ func (ac *AccessController) checkList(matches, list []string) bool {
}
return false
}

View File

@@ -37,10 +37,10 @@ type AppConfig struct {
BlackList []string `toml:"blackList"` // 黑名单IP/CIDR列表
} `toml:"security"`
Proxy struct {
Access struct {
WhiteList []string `toml:"whiteList"` // 代理白名单(仓库级别)
BlackList []string `toml:"blackList"` // 代理黑名单(仓库级别)
Socks5 string `toml:"socks5"` // SOCKS5代理地址: socks5://[user:pass@]host:port
Proxy string `toml:"proxy"` // 代理地址: 支持 http/https/socks5/socks5h
} `toml:"proxy"`
Download struct {
@@ -65,6 +65,7 @@ var (
configCacheMutex sync.RWMutex
)
// todo:Refactoring is needed
// DefaultConfig 返回默认配置
func DefaultConfig() *AppConfig {
return &AppConfig{
@@ -91,14 +92,14 @@ func DefaultConfig() *AppConfig {
WhiteList: []string{},
BlackList: []string{},
},
Proxy: struct {
Access: struct {
WhiteList []string `toml:"whiteList"`
BlackList []string `toml:"blackList"`
Socks5 string `toml:"socks5"`
Proxy string `toml:"proxy"`
}{
WhiteList: []string{},
BlackList: []string{},
Socks5: "", // 默认不使用代理
Proxy: "", // 默认不使用代理
},
Download: struct {
MaxImages int `toml:"maxImages"`
@@ -173,8 +174,8 @@ func GetConfig() *AppConfig {
configCopy := *appConfig
configCopy.Security.WhiteList = append([]string(nil), appConfig.Security.WhiteList...)
configCopy.Security.BlackList = append([]string(nil), appConfig.Security.BlackList...)
configCopy.Proxy.WhiteList = append([]string(nil), appConfig.Proxy.WhiteList...)
configCopy.Proxy.BlackList = append([]string(nil), appConfig.Proxy.BlackList...)
configCopy.Access.WhiteList = append([]string(nil), appConfig.Access.WhiteList...)
configCopy.Access.BlackList = append([]string(nil), appConfig.Access.BlackList...)
appConfigLock.RUnlock()
cachedConfig = &configCopy

View File

@@ -26,7 +26,7 @@ blackList = [
"192.168.100.0/24"
]
[proxy]
[access]
# 代理服务白名单支持GitHub仓库和Docker镜像支持通配符
# 只允许访问白名单中的仓库/镜像,为空时不限制
whiteList = []
@@ -39,11 +39,17 @@ blackList = [
"baduser/*"
]
# SOCKS5代理配置,支持有用户名/密码认证和无认证模式
# 代理配置,支持有用户名/密码认证和无认证模式
# 无认证: socks5://127.0.0.1:1080
# 有认证: socks5://username:password@127.0.0.1:1080
# HTTP 代理示例
# http://username:password@127.0.0.1:7890
# SOCKS5 代理示例
# socks5://username:password@127.0.0.1:1080
# SOCKS5H 代理示例
# socks5h://username:password@127.0.0.1:1080
# 留空不使用代理
socks5 = ""
proxy = ""
[download]
# 批量下载离线镜像数量限制

View File

@@ -6,7 +6,6 @@ require (
github.com/gin-gonic/gin v1.10.0
github.com/google/go-containerregistry v0.20.5
github.com/pelletier/go-toml/v2 v2.2.3
golang.org/x/net v0.33.0
golang.org/x/time v0.11.0
)
@@ -44,6 +43,7 @@ require (
github.com/vbatts/tar-split v0.12.1 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.21.0 // indirect

View File

@@ -1,14 +1,10 @@
package main
import (
"context"
"log"
"net"
"net/http"
"net/url"
"os"
"time"
"golang.org/x/net/proxy"
)
var (
@@ -22,63 +18,18 @@ var (
func initHTTPClients() {
cfg := GetConfig()
// 创建DialContext函数支持SOCKS5代理
createDialContext := func(timeout time.Duration) func(ctx context.Context, network, addr string) (net.Conn, error) {
if cfg.Proxy.Socks5 == "" {
// 没有配置代理,使用直连
dialer := &net.Dialer{
Timeout: timeout,
KeepAlive: 30 * time.Second,
}
return dialer.DialContext
}
// 解析SOCKS5代理URL
proxyURL, err := url.Parse(cfg.Proxy.Socks5)
if err != nil {
log.Printf("SOCKS5代理配置错误使用直连: %v", err)
dialer := &net.Dialer{
Timeout: timeout,
KeepAlive: 30 * time.Second,
}
return dialer.DialContext
}
// 创建基础dialer
baseDialer := &net.Dialer{
Timeout: timeout,
KeepAlive: 30 * time.Second,
}
// 创建SOCKS5代理dialer
var auth *proxy.Auth
if proxyURL.User != nil {
if password, ok := proxyURL.User.Password(); ok {
auth = &proxy.Auth{
User: proxyURL.User.Username(),
Password: password,
}
}
}
socks5Dialer, err := proxy.SOCKS5("tcp", proxyURL.Host, auth, baseDialer)
if err != nil {
log.Printf("创建SOCKS5代理失败使用直连: %v", err)
return baseDialer.DialContext
}
log.Printf("使用SOCKS5代理: %s", proxyURL.Host)
// 返回带上下文的dial函数
return func(ctx context.Context, network, addr string) (net.Conn, error) {
return socks5Dialer.Dial(network, addr)
}
if p := cfg.Access.Proxy; p != "" {
os.Setenv("HTTP_PROXY", p)
os.Setenv("HTTPS_PROXY", p)
}
// 代理客户端配置 - 适用于大文件传输
globalHTTPClient = &http.Client{
Transport: &http.Transport{
DialContext: createDialContext(30 * time.Second),
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 1000,
MaxIdleConnsPerHost: 1000,
IdleConnTimeout: 90 * time.Second,
@@ -92,7 +43,11 @@ func initHTTPClients() {
searchHTTPClient = &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
DialContext: createDialContext(5 * time.Second),
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,