Xây dựng 1 proxy với Go và net/http

July 15, 2019
Golang proxy net/http

Khái niệm proxy thì chắc hẳn ai cũng biết tuy nhiên mình vẫn muốn nhắc lại. Proxies là các hành động nằm trung gian ở giữa client và server. Chúng có thể can thiệp các tiến trình hoặc gì đơn giản là forward các request.

Có rất nhiều phương thức proxies như

Tuy nhiên phổ biến nhất thì vẫn là http proxies vì đa số người dùng bình thường sử dụng http request.

Diagram

Http_proxy=https://your-ip:1234

+--------------+           +----------------+         +----------------+
|              |           |                |         |                |
|   client     +----------^+ forward proxy  +--------^+    Server      |
|              |           |                |         |                |
+--------------+           +----------------+         +----^-----------+
                                                            |
                                                            |
+---------------+                                           |
|               |                                           |
|   client      +-------------------------------------------+
|               |
+---------------+
Không sử dụng proxy

Nhìn vào sơ đồ trên thì có thể thấy forward proxy sẽ là lớp trung gian để forward các request tới server. Lợi ích nó mang lại là gì thì mọi người đều có thể thấy rõ. Ví dụ đơn giản nhất nếu request từ client tới server không có gì nằm giữa thì bạn sẽ ko thể controll được các request. Giả xử rằng Server A ko thích bạn và họ block ip client của bạn. Vậy làm thế nào bạn có thể truy cập. đó là truy cập qua 1 proxy, proxy bạn có thể đặt ở 1 server khác. Khi bạn connect tới Server A và sử dụng forward proxy nó sẽ chuyển hướng các request của bạn tới server A và nặc danh IP là từ server forward proxy.

Tạo forward Proxy với Go

Để khởi tạo 1 proxy forward bạn cần tìm hiểu tài liệu về package http trong go import "net/http" https://golang.org/pkg/net/http/.

type Proxy struct {
}

func NewProxy() *Proxy { return &Proxy{} }

Trước tiên khởi 1 struct và 1 method NewProxy, method này sẽ có nhiệm vụ khởi tạo đối tượng Proxy.

Để lắng nghe được các request từ client bạn cần phải mở 1 port và sử dụng method ListenAndServe từ package http.


func main() {
    proxy := NewProxy()
    err := http.ListenAndServe(":1234", proxy)
}

vậy là OK rồi bây giờ cần phải xử lý proxy với methods ServeHTTP các bạn có thể viết như sau

func (p *Proxy) ServeHTTP(wr http.ResponseWriter, r *http.Request) {
    var resp *http.Response
    var err error
    var req *http.Request
    client := &http.Client{}

    req, err = http.NewRequest(r.Method, r.RequestURI, r.Body)
    for name, value := range r.Header {
        req.Header.Set(name, value[0])
    }
    resp, err = client.Do(req)
    r.Body.Close()

    if err != nil {
        http.Error(wr, err.Error(), http.StatusInternalServerError)
        return
    }

    for k, v := range resp.Header {
        wr.Header().Set(k, v[0])
    }

    wr.WriteHeader(resp.StatusCode)
    io.Copy(wr, resp.Body)
    resp.Body.Close()
}

Vậy là xong bạn có thể sử dụng luôn với proxy này.

nếu bạn sử dụng curl để test thử thì có thể chạy với command như sau

curl -x 127.0.0.1:1234 http://example.com

Nếu bạn sử dụng trình duyệt thì có thể tham khảo hướng dẫn thay đổi proxy của trình duyệt thì có thể tham khảo 1 vài hướng dẫn https://customers.trustedproxies.com/knowledgebase.php?action=displayarticle&id=10

Một lưu ý nhỏ bài viết này chỉ hướng dẫn bạn khởi tạo 1 proxy đơn giản và chỉ có thể truy cập được các trang web mà không sử dụng SSL. Tuy nhiên bài viết sau mình sẽ hướng dẫn làm 1 web proxy hoàn chỉnh hơn và có thể truy cập tất các các trang với SSL.

Hi vọng bài viết có thể mang lại 1 chút kiến thức cho các bạn.