From 3c1896a9466ca16e8011bef1ad7adc0db895e229 Mon Sep 17 00:00:00 2001 From: huyinsong Date: Sat, 31 May 2025 10:43:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DHTTP=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=92=8CIP=E5=9C=B0=E5=9D=80=E8=B7=AF?= =?UTF-8?q?=E7=94=B1=E5=8C=B9=E9=85=8D=E9=97=AE=E9=A2=98=20-=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DHTTP=E4=BB=A3=E7=90=86=E8=AF=B7=E6=B1=82URL=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E8=BD=AC=E6=8D=A2=E9=97=AE=E9=A2=98=20-=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8DReadResponse=E8=B0=83=E7=94=A8=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=94=99=E8=AF=AF=20-=20=E4=BF=AE=E5=A4=8DIP=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E5=8C=B9=E9=85=8D=E5=BC=BA=E5=88=B6=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E8=A7=84=E5=88=99=E7=9A=84=E9=97=AE=E9=A2=98=20-=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0101.34.16.52=E5=88=B0=E5=BC=BA=E5=88=B6?= =?UTF-8?q?=E4=BB=A3=E7=90=86=E5=88=97=E8=A1=A8=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97=E4=BB=A5=E4=BE=BF=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E6=8E=92=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- configs/client.yaml | 5 ++- internal/client/client.go | 42 +++++++++++++++++++- internal/routing/matcher.go | 6 +-- test_proxy_force.go | 78 +++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 test_proxy_force.go diff --git a/configs/client.yaml b/configs/client.yaml index ca5140f..4eeda9d 100644 --- a/configs/client.yaml +++ b/configs/client.yaml @@ -172,6 +172,9 @@ globalProxy: - "*.twitch.tv" - "steam.community" - "*.steam.community" + + # 特定服务IP地址 + - "101.34.16.52" # Gitea 服务器 # 透明代理设置 (实验性功能) transparentProxy: @@ -247,7 +250,7 @@ monitoring: compress: true # 是否压缩旧日志 # 全局设置 -logLevel: info +logLevel: debug timeout: 30s # Web管理界面 (可选) diff --git a/internal/client/client.go b/internal/client/client.go index abb8f00..3d7498b 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -454,6 +454,8 @@ func (h *httpProxyHandler) handleDirectHTTPSProxy(w http.ResponseWriter, r *http // handleHTTPProxy 处理HTTP代理请求 func (h *httpProxyHandler) handleHTTPProxy(w http.ResponseWriter, r *http.Request) { + logger.Info("Processing HTTP proxy request: %s %s", r.Method, r.URL.String()) + // 确保URL包含Host if r.URL.Host == "" { r.URL.Host = r.Host @@ -474,6 +476,8 @@ func (h *httpProxyHandler) handleHTTPProxy(w http.ResponseWriter, r *http.Reques } } + logger.Info("Target host: %s, port: %s", host, port) + // 使用路由匹配器判断是否需要代理 if h.routeMatcher != nil { matchResult := h.routeMatcher.Match(host) @@ -504,8 +508,42 @@ func (h *httpProxyHandler) handleHTTPProxy(w http.ResponseWriter, r *http.Reques } defer destConn.Close() + // 创建新的请求用于转发到目标服务器 + // 需要将代理格式的URL转换为相对路径格式 + requestURL := r.URL.Path + if r.URL.RawQuery != "" { + requestURL += "?" + r.URL.RawQuery + } + if requestURL == "" { + requestURL = "/" + } + + logger.Info("Original URL: %s, Converted URL: %s", r.URL.String(), requestURL) + + newReq, err := http.NewRequest(r.Method, requestURL, r.Body) + if err != nil { + logger.Error("Failed to create request for SOCKS5 proxy: %v", err) + h.socks5Proxy.IncrementFailedRequests() + http.Error(w, "Bad Request", http.StatusBadRequest) + return + } + + // 复制请求头,但需要调整Host头 + for key, values := range r.Header { + if key == "Host" { + continue // 跳过Host头,使用目标服务器的Host + } + for _, value := range values { + newReq.Header.Add(key, value) + } + } + + // 设置正确的Host头 + newReq.Host = r.Host + newReq.Header.Set("Host", r.Host) + // 发送HTTP请求 - if err := r.Write(destConn); err != nil { + if err := newReq.Write(destConn); err != nil { logger.Error("Failed to write request to SOCKS5 connection: %v", err) h.socks5Proxy.IncrementFailedRequests() http.Error(w, "Bad Gateway", http.StatusBadGateway) @@ -513,7 +551,7 @@ func (h *httpProxyHandler) handleHTTPProxy(w http.ResponseWriter, r *http.Reques } // 读取并转发响应 - resp, err := http.ReadResponse(bufio.NewReader(destConn), r) + resp, err := http.ReadResponse(bufio.NewReader(destConn), newReq) if err != nil { logger.Error("Failed to read response from SOCKS5 connection: %v", err) h.socks5Proxy.IncrementFailedRequests() diff --git a/internal/routing/matcher.go b/internal/routing/matcher.go index 6235b55..1745554 100644 --- a/internal/routing/matcher.go +++ b/internal/routing/matcher.go @@ -58,19 +58,19 @@ func (rm *RouteMatcher) Match(host string) MatchResult { logger.Debug("Matching route for host: %s", host) - // 1. 检查强制代理域名 + // 1. 检查强制代理域名(包括IP地址) if rm.matchesForceDomains(host) { logger.Debug("Host %s matches force domains - using proxy", host) return MatchProxy } - // 2. 检查绕过域名 + // 2. 检查绕过域名(包括IP地址) if rm.matchesBypassDomains(host) { logger.Debug("Host %s matches bypass domains - using direct", host) return MatchBypass } - // 3. 检查是否为IP地址 + // 3. 检查是否为IP地址,进行IP特定的匹配 if ip := net.ParseIP(host); ip != nil { return rm.matchIP(ip) } diff --git a/test_proxy_force.go b/test_proxy_force.go new file mode 100644 index 0000000..cd5aa2b --- /dev/null +++ b/test_proxy_force.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "io" + "net/http" + "net/url" + "time" +) + +func testProxyAccess(targetURL, proxyURL string) { + fmt.Printf("Testing %s via proxy %s...\n", targetURL, proxyURL) + + // 创建代理 + proxy, err := url.Parse(proxyURL) + if err != nil { + fmt.Printf("❌ Invalid proxy URL: %v\n", err) + return + } + + // 创建带代理的HTTP客户端 + client := &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyURL(proxy), + }, + Timeout: 20 * time.Second, + } + + resp, err := client.Get(targetURL) + if err != nil { + fmt.Printf("❌ Failed: %v\n", err) + return + } + defer resp.Body.Close() + + // 读取响应 + body, err := io.ReadAll(resp.Body) + if err != nil { + fmt.Printf("❌ Failed to read response: %v\n", err) + return + } + + fmt.Printf("✅ Success: %s (Status: %d, Size: %d bytes)\n", targetURL, resp.StatusCode, len(body)) + + // 如果是IP查询,显示结果 + if targetURL == "https://httpbin.org/ip" || targetURL == "http://httpbin.org/ip" { + fmt.Printf(" IP Response: %s\n", string(body)) + } +} + +func main() { + fmt.Println("=== 强制代理测试 ===") + + proxyURL := "http://127.0.0.1:9090" + + // 测试目标 - 科学上网常用网站 + targets := []string{ + "https://httpbin.org/ip", + "https://www.google.com", + "https://github.com", + "https://www.youtube.com", + "https://twitter.com", + "https://facebook.com", + } + + fmt.Printf("通过代理 %s 强制访问以下网站:\n\n", proxyURL) + + for i, target := range targets { + fmt.Printf("%d. ", i+1) + testProxyAccess(target, proxyURL) + fmt.Println() + + // 避免请求过快 + time.Sleep(2 * time.Second) + } + + fmt.Println("=== 测试完成 ===") +}