基于Golang的Http(s)與Socks5代理服務(wù)器的代碼實(shí)現(xiàn)
背景
很多制作公司為了安全起見,大部分內(nèi)部設(shè)計(jì)人員的電腦是沒法聯(lián)網(wǎng)的,只有少數(shù)部分電腦可以連外網(wǎng)(比如制片人員的電腦)。但是在外包這種模式下,為了能夠讓設(shè)計(jì)人員方便的接包任務(wù),并回傳結(jié)果,需要設(shè)計(jì)人員的電腦能夠通過代理服務(wù)(部署在制片的電腦上)上指定的網(wǎng)站,這個(gè)時(shí)候就需要我們實(shí)現(xiàn)代理請(qǐng)求轉(zhuǎn)發(fā)的功能。
HTTP代理
在Go語言中,可以使用標(biāo)準(zhǔn)庫(kù)的 net/http 包來實(shí)現(xiàn)HTTP代理。
下面是一個(gè)簡(jiǎn)單的例子,實(shí)現(xiàn)了一個(gè)HTTP代理服務(wù)器,它可以代理客戶端的HTTP請(qǐng)求并返回請(qǐng)求的響應(yīng):
package main
import (
"net"
"net/http"
"net/http/httputil"
)
func handleHTTP(w http.ResponseWriter, req *http.Request) {
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
defer resp.Body.Close()
copyHeader(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
HTTPS代理
Golang可以輕松實(shí)現(xiàn)一個(gè)https代理,你需要執(zhí)行以下步驟:
- 獲取客戶端請(qǐng)求: 使用Golang的net包接收客戶端請(qǐng)求。
- 轉(zhuǎn)發(fā)請(qǐng)求: 使用Golang的http包將請(qǐng)求轉(zhuǎn)發(fā)到服務(wù)端。
- 獲取服務(wù)端響應(yīng): 從服務(wù)端接收響應(yīng)并將其返回給客戶端。
以下是一個(gè)示例代碼,實(shí)現(xiàn)了一個(gè)https代理:
package main
import (
"bufio"
"io"
"net"
"net/http"
"net/http/httputil"
)
func handleHttps(w http.ResponseWriter, r *http.Request) {
dest_conn, err := net.DialTimeout("tcp", r.Host, 10*time.Second)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
return
}
client_conn, _, err := hijacker.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
go transfer(dest_conn, client_conn)
go transfer(client_conn, dest_conn)
}
func transfer(destination io.WriteCloser, source io.ReadCloser) {
defer destination.Close()
defer source.Close()
io.Copy(destination, source)
}
func handleHTTP(w http.ResponseWriter, req *http.Request) {
resp, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
defer resp.Body.Close()
copyHeader(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
SOCKS代理
Socks5協(xié)議是一種靈活的代理協(xié)議,主要用于實(shí)現(xiàn)代理服務(wù)器的功能,允許客戶端通過代理服務(wù)器與其他網(wǎng)絡(luò)資源進(jìn)行通信。Socks5協(xié)議比Socks4協(xié)議更先進(jìn),具有更多的特性,如它支持用戶名/密碼驗(yàn)證,還支持TCP和UDP協(xié)議.下面實(shí)現(xiàn)的是Socks5代理協(xié)議
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
l, err := net.Listen("tcp", ":1080")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer l.Close()
for {
client, err := l.Accept()
if err != nil {
fmt.Println(err)
continue
}
go handleClientRequest(client)
}
}
func handleClientRequest(client net.Conn) {
if client == nil {
return
}
defer client.Close()
var b [1024]byte
n, err := client.Read(b[:])
if err != nil {
fmt.Println(err)
return
}
var host, port string
switch b[3] {
case 0x01: // IPv4
host = net.IPv4(b[4], b[5], b[6], b[7]).String()
port = fmt.Sprintf("%d", b[8]<<8|b[9])
case 0x03: // Domain name
host = string(b[5 : n-2])
port = fmt.Sprintf("%d", b[n-2]<<8|b[n-1])
case 0x04: // IPv6
host = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
port = fmt.Sprintf("%d", b[20]<<8|b[21])
}
server, err := net.Dial("tcp", host+":"+port)
if err != nil {
fmt.Println(err)
return
}
defer server.Close()
client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43})
go func() {
_, err := io.Copy(server, client)
if err != nil {
fmt.Println("io.Copy error:", err)
}
}()
_, err = io.Copy(client, server)
if err != nil {
fmt.Println("io.Copy error:", err)
}
}