Home > Article > Backend Development > golang traffic https forwarding
With the increasing emphasis on Internet security, more and more websites are beginning to use HTTPS to protect users’ access communications. However, in some specific scenarios, we need to use a proxy to forward traffic to achieve certain specific requirements. This article will introduce how to use golang to write a proxy server that can forward HTTPS traffic.
1. HTTP proxy implementation
First, let’s introduce how golang implements an HTTP proxy.
Golang's standard library provides the net/http/httputil package, which encapsulates the tools and functions needed to implement HTTP proxy, such as ReverseProxy and DumpRequestOut. ReverseProxy represents a reverse proxy server that can forward received requests to another HTTP server. The DumpRequestOut function can encode and output the content of the request in a binary format before the request is sent. This will help us understand the process and interaction details of the redirected website.
We can use the following code to implement a simple HTTP proxy:
package main import ( "log" "net/http" "net/http/httputil" ) func main() { proxy := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: "http", Host: "localhost:8080"}) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { proxy.ServeHTTP(w, r) }) log.Fatal(http.ListenAndServe(":10080", nil)) }
In the above code, we create a reverse proxy server and forward the received request to http:// localhost:8080, and the server is monitored on port 10080. When we send an HTTP request to the proxy server, the proxy server will forward the request to the local port 8080 and output it on the console.
2. HTTPS proxy implementation
Next we will introduce how to use golang to implement an HTTPS proxy so that it can forward HTTPS traffic. First, we need to use a certificate for secure HTTPS communication.
1. Self-signed certificate generation
We can use openssl to generate a self-signed certificate for HTTPS communication in the test environment. The specific steps are as follows:
Step 1: Generate private key key.pem
openssl genrsa -out key.pem 2048
Step 2: Generate certificate request certificate csr.pem
openssl req -new -key key.pem -out csr.pem
After passing the above two steps, We have created a private key and certificate request file for creating a self-signed certificate.
Step 3: Generate certificate crt.pem
We can use csr.pem and key.pem to generate a self-signed certificate:
openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out crt.pem
In this step, we A time limit of 365 days was used and the certificate crt.pem was generated.
At this point, we have created a self-signed certificate and can use it for HTTPS communication.
2. Implement HTTPS proxy
First we need to parse the client's request and read its corresponding Headers to obtain the host address requested by the client. We can then create a TLS connection for the client and forward it to the target server after a successful handshake. It should be noted that in Windows and macOS systems, the minimum version of TLS needs to be specified as 1.1, otherwise the connection will be forcibly closed.
The following is a code example of an HTTPS proxy:
package main import ( "log" "net" "net/http" "net/http/httputil" "time" ) func main() { // 代理的目标 target := "http://localhost:8080" // 对HTTPS请求使用自签名证书 certFile, keyFile := "crt.pem", "key.pem" cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatal(err) } // 创建TLS配置 tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, MinVersion: tls.VersionTLS11, } // 创建反向代理 proxy := httputil.NewSingleHostReverseProxy(&url.URL{ Scheme: "http", Host: "localhost:8080", }) // 处理CONNECT请求 handleConnect := func(w http.ResponseWriter, r *http.Request) { // 解析主机地址 host, _, err := net.SplitHostPort(r.Host) if err != nil { http.Error(w, fmt.Sprintf("Invalid host: %s", err), http.StatusBadRequest) return } // 创建目标地址 targetHost := net.JoinHostPort(host, "443") // 设置超时时间为10s dialer := &net.Dialer{ Timeout: 10 * time.Second, } // 创建TLS连接 conn, err := tls.DialWithDialer(dialer, "tcp", targetHost, tlsConfig) if err != nil { http.Error(w, fmt.Sprintf("Unable to create TLS connection: %s", err), http.StatusServiceUnavailable) return } // 将握手成功的连接转发到目标服务器 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, err.Error(), http.StatusServiceUnavailable) return } // 向客户端发送连接成功的状态码 clientConn.Write([]byte("HTTP/1.1 200 Connection Established ")) // 进行双向数据拷贝 go func() { defer conn.Close() io.Copy(conn, clientConn) }() go func() { defer clientConn.Close() io.Copy(clientConn, conn) }() } // 设置HandlerFunc handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodConnect { handleConnect(w, r) return } proxy.ServeHTTP(w, r) }) // 监听 server := &http.Server{ Addr: ":10080", Handler: handlerFunc, TLSConfig: tlsConfig, TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0), } log.Fatal(server.ListenAndServeTLS("", "")) }
The above code implements a basic HTTPS proxy server and can forward received HTTPS requests to the target server. It should be noted that during actual use, we need to make corresponding adjustments according to actual needs, such as using certificates issued by CA to strengthen the security of HTTPS.
3. Summary
In this article, we introduced how to use golang to implement a proxy server and complete the traffic forwarding of HTTP and HTTPS protocols. For the need to forward network traffic, implementing a proxy server can help us achieve our goal well, and it also improves our understanding and application of network communication protocols.
The above is the detailed content of golang traffic https forwarding. For more information, please follow other related articles on the PHP Chinese website!