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

先看反向代理库

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()
}

具体框架就是在这样,语法不一定对。 本质上是用我们自定义的拨号函数代替系统的拨号函数Dial,在我们自定义拨号函数中直接返回客户端主动连接服务端建立的连接,而不是服务端主动去连接(客户端在内网)

客户端代码(大概):

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")
}

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

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值