mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

将Proxy.go的代理连接逻辑重构为完整的模块化系统, 提供更好的性能、可维护性和功能扩展。 主要变更: - Proxy.go: 从192行单体实现重构为简洁包装层 - 新增proxy模块包含5个核心文件:Types.go、Manager.go等 - 支持多种代理类型:HTTP、HTTPS、SOCKS5、直连 - 实现连接池、缓存机制和智能资源管理 - 添加详细的连接统计和性能监控 - 提供线程安全的配置管理和动态更新 - 完全保持API向后兼容性,无需修改调用代码 新增功能: - HTTP/HTTPS代理支持(原来仅支持SOCKS5) - 连接跟踪和统计分析 - 错误分类和详细上下文信息 - 配置验证和URL解析 - 全局代理管理实例 测试验证: - 编译无错误 ✓ - 基础连接功能正常 ✓ - 向后兼容性验证通过 ✓
112 lines
3.0 KiB
Go
112 lines
3.0 KiB
Go
package proxy
|
||
|
||
import (
|
||
"bufio"
|
||
"context"
|
||
"encoding/base64"
|
||
"fmt"
|
||
"net"
|
||
"net/http"
|
||
"sync/atomic"
|
||
"time"
|
||
)
|
||
|
||
// httpDialer HTTP代理拨号器
|
||
type httpDialer struct {
|
||
config *ProxyConfig
|
||
stats *ProxyStats
|
||
baseDial *net.Dialer
|
||
}
|
||
|
||
func (h *httpDialer) Dial(network, address string) (net.Conn, error) {
|
||
return h.DialContext(context.Background(), network, address)
|
||
}
|
||
|
||
func (h *httpDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||
start := time.Now()
|
||
atomic.AddInt64(&h.stats.TotalConnections, 1)
|
||
|
||
// 连接到HTTP代理服务器
|
||
proxyConn, err := h.baseDial.DialContext(ctx, "tcp", h.config.Address)
|
||
if err != nil {
|
||
atomic.AddInt64(&h.stats.FailedConnections, 1)
|
||
h.stats.LastError = err.Error()
|
||
return nil, NewProxyError(ErrTypeConnection, "连接HTTP代理服务器失败", 4001, err)
|
||
}
|
||
|
||
// 发送CONNECT请求
|
||
if err := h.sendConnectRequest(proxyConn, address); err != nil {
|
||
proxyConn.Close()
|
||
atomic.AddInt64(&h.stats.FailedConnections, 1)
|
||
h.stats.LastError = err.Error()
|
||
return nil, err
|
||
}
|
||
|
||
duration := time.Since(start)
|
||
h.stats.LastConnectTime = start
|
||
atomic.AddInt64(&h.stats.ActiveConnections, 1)
|
||
h.updateAverageConnectTime(duration)
|
||
|
||
return &trackedConn{
|
||
Conn: proxyConn,
|
||
stats: h.stats,
|
||
}, nil
|
||
}
|
||
|
||
// sendConnectRequest 发送HTTP CONNECT请求
|
||
func (h *httpDialer) sendConnectRequest(conn net.Conn, address string) error {
|
||
// 构建CONNECT请求
|
||
req := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\n", address, address)
|
||
|
||
// 添加认证头
|
||
if h.config.Username != "" {
|
||
auth := base64.StdEncoding.EncodeToString(
|
||
[]byte(h.config.Username + ":" + h.config.Password))
|
||
req += fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", auth)
|
||
}
|
||
|
||
req += "\r\n"
|
||
|
||
// 设置写超时
|
||
if err := conn.SetWriteDeadline(time.Now().Add(h.config.Timeout)); err != nil {
|
||
return NewProxyError(ErrTypeTimeout, "设置写超时失败", 4002, err)
|
||
}
|
||
|
||
// 发送请求
|
||
if _, err := conn.Write([]byte(req)); err != nil {
|
||
return NewProxyError(ErrTypeConnection, "发送CONNECT请求失败", 4003, err)
|
||
}
|
||
|
||
// 设置读超时
|
||
if err := conn.SetReadDeadline(time.Now().Add(h.config.Timeout)); err != nil {
|
||
return NewProxyError(ErrTypeTimeout, "设置读超时失败", 4004, err)
|
||
}
|
||
|
||
// 读取响应
|
||
resp, err := http.ReadResponse(bufio.NewReader(conn), nil)
|
||
if err != nil {
|
||
return NewProxyError(ErrTypeProtocol, "读取HTTP响应失败", 4005, err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
// 检查响应状态
|
||
if resp.StatusCode != 200 {
|
||
return NewProxyError(ErrTypeAuth,
|
||
fmt.Sprintf("HTTP代理连接失败,状态码: %d", resp.StatusCode), 4006, nil)
|
||
}
|
||
|
||
// 清除deadline
|
||
conn.SetDeadline(time.Time{})
|
||
|
||
return nil
|
||
}
|
||
|
||
// updateAverageConnectTime 更新平均连接时间
|
||
func (h *httpDialer) updateAverageConnectTime(duration time.Duration) {
|
||
// 简单的移动平均
|
||
if h.stats.AverageConnectTime == 0 {
|
||
h.stats.AverageConnectTime = duration
|
||
} else {
|
||
h.stats.AverageConnectTime = (h.stats.AverageConnectTime + duration) / 2
|
||
}
|
||
} |