Total Pageviews

Sunday, 10 November 2019

一个简单的用Golang实现的HTTP Proxy

首先在linux vps上,安装go环境。
把以下蓝色的代码保存为http-proxy-by-flysnow.go,保存在linux vps上。


package main

import (
 "bytes"
 "fmt"
 "io"
 "log"
 "net"
 "net/url"
 "strings"
)

func main() {
 log.SetFlags(log.LstdFlags|log.Lshortfile)
 l, err := net.Listen("tcp", ":5082")
 if err != nil {
  log.Panic(err)
 }

 for {
  client, err := l.Accept()
  if err != nil {
   log.Panic(err)
  }

  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 {
  log.Println(err)
  return
 }
 var method, host, address string
 fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)
 hostPortURL, err := url.Parse(host)
 if err != nil {
  log.Println(err)
  return
 }

 if hostPortURL.Opaque == "443" { //https访问
  address = hostPortURL.Scheme + ":443"
 } else { //http访问
  if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端口, 默认80
   address = hostPortURL.Host + ":80"
  } else {
   address = hostPortURL.Host
  }
 }

 //获得了请求的host和port,就开始拨号吧
 server, err := net.Dial("tcp", address)
 if err != nil {
  log.Println(err)
  return
 }
 if method == "CONNECT" {
  fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n\r\n")
 } else {
  server.Write(b[:n])
 }
 //进行转发
 go io.Copy(server, client)
 io.Copy(client, server)
}
 
然后,运行go build http-proxy-by-flysnow.go
在当前目录下,就会生成可执行文件http-proxy-by-flysnow。
 
root@host ~]# ./http-proxy-by-flysnow & 
[1] 30974
[root@host ~]# 
[root@host ~]# lsof -i:5082
COMMAND     PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
http-prox 30974 root    3u  IPv6 1803120      0t0  TCP *:qcp (LISTEN)
[root@host ~]# 

这个http-proxy-by-flysnow可以用作各种tunnel程序的后端程序。