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的端口上