go库中自带的反向代理功能和内网代理

organicgoose 发布于2年前 阅读14769次
0 条评论

先看反向代理库

type ReverseProxy struct {
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	Director func(*http.Request)

	// The transport used to perform proxy requests.
	// If nil, http.DefaultTransport is used.
	Transport http.RoundTripper

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger

	// BufferPool optionally specifies a buffer pool to
	// get byte slices for use by io.CopyBuffer when
	// copying HTTP response bodies.
	BufferPool BufferPool
}
接着我们看一个例子(网上拷的)

package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
)

type handle struct {
	host string
	port string
}

func (this *handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	remote, err := url.Parse("http://" + this.host + ":" + this.port)
	if err != nil {
		panic(err)
	}
	proxy := httputil.NewSingleHostReverseProxy(remote)
	proxy.ServeHTTP(w, r)
}

func startServer() {
	//被代理的服务器host和port
	h := &handle{host: "127.0.0.1", port: "80"}
	err := http.ListenAndServe(":8888", h)
	if err != nil {
		log.Fatalln("ListenAndServe: ", err)
	}
}

func main() {
	startServer()
}

使用起来很简单。但是我有时有一种特殊需求。如内网代理(想访问的目标服务器在内网),那该如何办呢?一般方向代理是代理服务器可以主动访问目标服务器的,现在目标服务器在内网,代理服务器不能主动去访问目标服务器。通常我们的代理服务器在公网(对于客户和目标服务器),我们让内网的目标服务器先主动与代理服务器建立一个连接,当客户需要经过代理服务器访问目标内网服务器时,再将请求经过内网服务器与代理服务器预先建立的连接发送到内网服务器。

我们有两个服务程序,一个运行在代理服务器,一个运行在内网服务器。

将上面代码稍微改造就成为运行在代理服务器的程序:

package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
)
var conn
type handle struct {

}

func (this *handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
		remote, err := url.Parse("http://127.0.0.1:443")
		if err != nil {
			panic(err)
		}
		proxy := httputil.NewSingleHostReverseProxy(remote)
		var pTransport http.RoundTripper = &http.Transport{
			Proxy:                 http.ProxyFromEnvironment,
			Dial:                  Dial,
			TLSHandshakeTimeout:   10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
		}
		proxy.Transport = pTransport

		proxy.ServeHTTP(w,r)
}

func startServer() {
//接受内网服务器主动连接8088端口
l, err := net.Listen("tcp", "0.0.0.0:8088")
	if err != nil {
	
		return 
	}

	go func() {
		
		for {
			conn, err = l.Accept() //循环接受客户端和设备的连接请求
			if err != nil {
				beego.Error("Can't Accept: ", err)
				return
			}
		
		}

	}()


	//接受客户端的连接
	h := &handle{}
	err := http.ListenAndServe(":8888", h)
	if err != nil {
		log.Fatalln("ListenAndServe: ", err)
	}
}
func Dial(network, address string) (net.Conn, error) {
	return conn, nil
}
func main() {
	startServer()
}

具体框架就是在这样,语法不一定对。

客户端代码(大概):

func proxy(local, remote string) {
	conf := &tls.Config{
		InsecureSkipVerify: true,
	}
	rp, err := tls.Dial("tcp", remote, conf)
	if err != nil {
		beego.Error("Can't' connect:", remote, " err:", err)
		return
	}
	defer util.CloseConn(rp)

	
	config := &tls.Config{InsecureSkipVerify: true} //不做证书校验

	lp, err := tls.Dial("tcp", local, config)
	if err != nil {
		beego.Error("Can't' connect:", other, " err:", err)
		rp.Close()
		return
	}
	defer util.CloseConn(lp)
	//buf = make([]byte, 1024*1024)

	rp.SetReadDeadline(time.Time{})
	lp.SetReadDeadline(time.Time{})
	flag := make(chan error)
	go Transfer(rp, lp, flag)
	

}

func Transfer(a, b net.Conn, flag chan error) {

	cp := func(r, w net.Conn) {
		n, err := io.Copy(r, w)
		r.Close()
		w.Close()
		beego.Debug("Transfer", n, " bytes between ", a.RemoteAddr(), " and ", b.RemoteAddr())
		flag <- err
	}
	go cp(a, b)
	go cp(b, a)

}

main(){
//本地服务地址和代理服务器接受内网服务器连接的地址
 proxy("127.0.0.1:443","192.168.16.110:8088")
}

以上仅是大概框架,以供参考

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。