package main
import (
"crypto/tls"
"fmt"
"io"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"time"
)
// 默认目标连接超时时间
const defaultTargetConnectTimeout = 10 * time.Second
// 上游代理服务器地址(如果为空,则不使用上游代理)
const upstreamProxy = "http://your-upstream-proxy:3128"
// 创建支持 HTTPS 的 ReverseProxy
func newHTTPSReverseProxy() *httputil.ReverseProxy {
// 解析上游代理地址(如果有)
var proxyFunc func(*http.Request) (*url.URL, error)
if upstreamProxy != "" {
proxyURL, err := url.Parse(upstreamProxy)
if err != nil {
log.Fatalf("Invalid upstream proxy URL: %v", err)
}
proxyFunc = http.ProxyURL(proxyURL)
} else {
proxyFunc = http.ProxyFromEnvironment
}
// 配置 ReverseProxy
return &httputil.ReverseProxy{
Director: func(req *http.Request) {
// 动态设置目标地址
req.URL.Scheme = "https"
req.URL.Host = req.Host
req.Header.Set("X-Forwarded-For", req.RemoteAddr)
},
Transport: &http.Transport{
Proxy: proxyFunc,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, // 如果需要跳过证书验证,可设置为 true
},
},
}
}
// 处理 HTTPS 隧道代理(CONNECT 方法)
func handleTunnel(w http.ResponseWriter, r *http.Request) {
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
return
}
clientConn, _, err := hijacker.Hijack()
if err != nil {
http.Error(w, "Failed to hijack connection", http.StatusInternalServerError)
return
}
defer clientConn.Close()
// 解析目标地址
destAddr := r.Host
if !strings.Contains(destAddr, ":") {
destAddr += ":443" // 默认使用 HTTPS 端口
}
// 如果使用上游代理,通过代理连接目标服务器
var destConn net.Conn
if upstreamProxy != "" {
destConn, err = dialViaUpstreamProxy(destAddr)
} else {
destConn, err = net.DialTimeout("tcp", destAddr, defaultTargetConnectTimeout)
}
if err != nil {
log.Printf("Failed to connect to destination: %v", err)
http.Error(w, "Failed to connect to destination", http.StatusServiceUnavailable)
return
}
defer destConn.Close()
// 通知客户端隧道建立成功
_, _ = clientConn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))
// 双向数据拷贝
go func() {
_, err := io.Copy(destConn, clientConn)
if err != nil {
log.Printf("Error copying from client to destination: %v", err)
}
}()
_, err = io.Copy(clientConn, destConn)
if err != nil {
log.Printf("Error copying from destination to client: %v", err)
}
}
// 通过上游代理建立连接
func dialViaUpstreamProxy(destAddr string) (net.Conn, error) {
// 解析上游代理地址
proxyURL, err := url.Parse(upstreamProxy)
if err != nil {
return nil, fmt.Errorf("invalid upstream proxy URL: %v", err)
}
// 连接到上游代理
conn, err := net.DialTimeout("tcp", proxyURL.Host, defaultTargetConnectTimeout)
if err != nil {
return nil, fmt.Errorf("failed to connect to upstream proxy: %v", err)
}
// 发送 CONNECT 请求到上游代理
connectReq := fmt.Sprintf("CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", destAddr, destAddr)
_, err = conn.Write([]byte(connectReq))
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to send CONNECT request to upstream proxy: %v", err)
}
// 读取响应
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to read response from upstream proxy: %v", err)
}
if n == 0 {
conn.Close()
return nil, fmt.Errorf("empty response from upstream proxy")
}
response := string(buf[:n])
// 检查响应状态码
if !strings.Contains(strings.ToLower(response), strings.ToLower("200 Connection Established")) {
conn.Close()
return nil, fmt.Errorf("upstream proxy refused the connection: %s", response)
}
return conn, nil
}
// 处理代理请求(包含 HTTP 和 HTTPS)
func handleProxy(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodConnect {
// 处理 HTTPS 隧道请求
handleTunnel(w, r)
} else {
// 处理普通 HTTP/HTTPS 请求
proxy := newHTTPSReverseProxy()
proxy.ServeHTTP(w, r)
}
}
func main() {
port := 8080
fmt.Printf("Starting HTTPS proxy server on :%d\n", port)
// 设置代理服务器处理函数
http.HandleFunc("/", handleProxy)
// 启动服务器
if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
版权归属:
管理员
许可协议:
本文使用《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》协议授权
评论区