• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

go语言写的端口转发工具win/linux通用

go 开心洋葱 2277次浏览 0个评论

go语言写的端口转发工具win/linux通用

forwardPort.go代码如下:

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"
)

var restApiServer = flag.String("restApi", "", "listen addr for restapi")
var auth = flag.String("auth", "yt123", "restApi Password")
var gLocalConn net.Listener

var clientSMap map[string]net.Conn

var forwardInfo string

func main() {

	clientSMap = make(map[string]net.Conn)

	//解析传入的参数
	flag.Parse()

	if *restApiServer == "" {
		*restApiServer = "0.0.0.0:8000"
	}

	go StartHttpServer(*restApiServer)

	log.Println("restApiServer:", *restApiServer)
	fmt.Println("------------启动成功------------")

	//开启线程同步锁
	var w sync.WaitGroup
	w.Add(2)

	//开一个并发线程,接收退出信号
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, syscall.SIGTERM)
		n := 0
		f := func() {
			<-c
			n++
			if n > 2 {
				log.Println("force shutdown")
				os.Exit(-1)
			}
			log.Println("received signal,shutdown")
			closeAllConn()
		}
		f()
		go func() {
			for {
				f()
			}
		}()
		//执行完成一次,Done() 等同于 Add(-1),计数不为0,则阻塞
		w.Done()
	}()

	loop := func() {
		w.Done()

	}
	loop()
	w.Wait()

	fmt.Println("------------程序执行完成------------")

}

func StartHttpServer(addr string) {

	http.HandleFunc("/ServerSummary", ServerSummary)
	http.HandleFunc("/ForwardWork", ForwardWork)

	//
	err := http.ListenAndServe(addr, http.DefaultServeMux)

	if err != nil {
		fmt.Println("ListenAndServe error: ", err.Error())
	}

}

func ServerSummary(rw http.ResponseWriter, req *http.Request) {
	log.Println("ServerSummary")
	obj := make(map[string]interface{})
	obj["runtime_NumGoroutine"] = runtime.NumGoroutine()
	obj["runtime_GOOS"] = runtime.GOOS
	obj["runtime_GOARCH"] = runtime.GOARCH
	obj["restApi_Addr"] = *restApiServer
	obj["server_Time"] = time.Now()
	obj["clients_Count"] = len(clientSMap)

	var clist []string
	for cId, _ := range clientSMap {
		clist = append(clist, cId)
	}
	obj["clients_List"] = clist
	obj["forwardInfo"] = forwardInfo

	res, err := json.Marshal(obj)
	if err != nil {
		log.Println("json marshal:", err)
		return
	}

	rw.Header().Add("Content-Type", "application/json;charset=utf-8")
	_, err = rw.Write(res)
	if err != nil {
		log.Println("write err:", err)
	}
	return
}

func ForwardWork(rw http.ResponseWriter, req *http.Request) {
	req.ParseForm()

	obj := make(map[string]interface{})
	obj["code"] = 0
	obj["msg"] = ""

	paramAuth, hasAuth := req.Form["auth"]
	if !hasAuth {
		log.Println("request no auth")
		obj["code"] = 1
		obj["msg"] = "request no auth"
		responseResult(obj, rw)
		return

	}

	if paramAuth[0] != *auth {
		log.Println("request auth failed")
		obj["code"] = 1
		obj["msg"] = "request auth failed"
		responseResult(obj, rw)

		return
	}

	paramStatus, hasStatus := req.Form["status"]
	if !hasStatus {
		return

	}

	log.Println("param_status:", paramStatus)

	if paramStatus[0] == "1" {
		//启动服务
		paramFromAddr, hasFromAddr := req.Form["fromAddr"]
		paramToAddr, hasToAddr := req.Form["toAddr"]
		if gLocalConn != nil {
			gLocalConn.Close()
		}

		if hasFromAddr && hasToAddr {
			go forwardPort(paramFromAddr[0], paramToAddr[0])
		}
	}

	if paramStatus[0] == "0" {
		//关闭服务
		closeAllConn()
		forwardInfo = ""
	}

	responseResult(obj, rw)

	return

}

func responseResult(data map[string]interface{}, rw http.ResponseWriter) {
	res, err := json.Marshal(data)
	if err != nil {
		log.Println("json marshal:", err)
		return
	}

	rw.Header().Add("Content-Type", "application/json;charset=utf-8")
	_, err = rw.Write(res)
	if err != nil {
		log.Println("write err:", err)
	}
}

func closeAllConn() {
	for cId, conn := range clientSMap {
		log.Println("clientMap id:", cId)
		conn.Close()
		delete(clientSMap, cId)
	}

	if gLocalConn != nil {
		gLocalConn.Close()
		log.Println("Listener Close")
	} else {
		gLocalConn = nil
		log.Println("Listener set to nil", gLocalConn)
	}
}

func forwardPort(sourcePort string, targetPort string) {

	fmt.Println("sourcePort:", sourcePort, "targetPort:", targetPort)

	localConn, err := net.Listen("tcp", sourcePort)

	if err != nil {
		fmt.Println(err.Error())
		return
	}

	gLocalConn = localConn

	fmt.Println("服务启动成功,服务地址:", sourcePort)

	forwardInfo = fmt.Sprintf("%s - %s", sourcePort, targetPort)

	for {
		fmt.Println("Ready to Accept ...")
		sourceConn, err := gLocalConn.Accept()

		if err != nil {
			log.Println("server err:", err.Error())
			break
		}
		//log.Println("client", sc.id, "create session", sessionId)

		id := sourceConn.RemoteAddr().String()
		clientSMap[id] = sourceConn

		fmt.Println("conn.RemoteAddr().String() :", id)

		//targetPort := "172.16.128.83:22"
		targetConn, err := net.DialTimeout("tcp", targetPort, 30*time.Second)

		go func() {
			_, err = io.Copy(targetConn, sourceConn)
			if err != nil {
				//log.Fatalf("io.Copy 1 failed: %v", err)
				fmt.Println("io.Copy 1 failed:", err.Error())
			}
		}()

		go func() {
			_, err = io.Copy(sourceConn, targetConn)
			if err != nil {
				//log.Fatalf("io.Copy 2 failed: %v", err)
				fmt.Println("io.Copy 2 failed:", err.Error())
			}
		}()

	}

	//
	log.Println("forwardPort end.")

}

操作说明:

A服务器IP:10.10.1.100
B服务器IP:10.11.2.20

1、在A服务器上执行:
forwardPort.exe

(注:linux系统执行 ./forwardPort)

2、执行成功后,默认监听8000端口,这时打开浏览器,访问:http://10.10.1.100:8000/ServerSummary

会返回当前程序的统计信息,返回内容为JSON数据。

如果访问不了,请检查A服务器上防火墙是否开启8000端口的访问。

3、开启转发,将A机器上的8010端口转发到B服务器上的3389端口:

http://10.10.1.100:8000/ForwardWork?auth=yt123&status=1&fromAddr=:8010&toAddr=10.11.2.20:3389

4、开启后,您就可以通过 10.10.1.100:8010 端口连接了,此时你实际连接到的是 10.11.2.20 上的 3389

上面只是个例子,你可以随时启用任意端口与任意机器之间的端口映射。

当你使用完毕后,可以立即关闭端口转发,只需要执行如下请求即可:
http://10.10.1.100:8000/ForwardWork?auth=yt123&status=0

执行后,端口转发关闭,端口被释放。

本机转发 /ForwardWork?auth=yt123&status=1&fromAddr=:8010&toAddr=:22

表示把机器上的8010端口映射到本机的22端口.

参数说明:

auth:rest接口调用时的密码,启动时不带该参数,则默认为:yt123
restApi:rest接口监听的地址,启动时不带该参数,则默认为:0.0.0.0:8000

#REST接口参数说明:
/ForwardWork?auth=yt123&status=1&fromAddr=:8010&toAddr=10.11.2.20:3389
auth:密码
status:如果是开启转发,则为1,如果是关闭转发,则为0
fromAddr:要用来在A机器上监听的一个端口,用来给客户端连接
toAddr:把fromAddr端口的数据转发到哪个IP的端口上


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明go语言写的端口转发工具win/linux通用
喜欢 (0)

您必须 登录 才能发表评论!

加载中……