Home >Backend Development >Golang >golang traffic https forwarding

golang traffic https forwarding

王林
王林Original
2023-05-10 09:17:06945browse

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn