From 7b2523630a80040d7cbf7c9e62e8dbec2c675360 Mon Sep 17 00:00:00 2001
From: Erik Brakkee <erik@brakkee.org>
Date: Thu, 18 Jul 2024 19:48:06 +0200
Subject: [PATCH] ssh client -> tcptows -> wstotcp -> sshserver  works.

---
 cmd/tcptows/tcptows.go | 74 ++++++++++++++++++++++++++++++++++++
 cmd/wstotcp/wstotcp.go | 86 ++++++++++++++++++++++++++++++++++++++++++
 go.mod                 |  1 +
 go.sum                 |  6 +++
 4 files changed, 167 insertions(+)
 create mode 100644 cmd/tcptows/tcptows.go
 create mode 100644 cmd/wstotcp/wstotcp.go

diff --git a/cmd/tcptows/tcptows.go b/cmd/tcptows/tcptows.go
new file mode 100644
index 0000000..28971cf
--- /dev/null
+++ b/cmd/tcptows/tcptows.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+	"io"
+	"log"
+	"net"
+
+	"github.com/gorilla/websocket"
+)
+
+func handleConnection(conn net.Conn, wsURL string) {
+	defer conn.Close()
+
+	wsConn, _, err := websocket.DefaultDialer.Dial(wsURL, nil)
+	if err != nil {
+		log.Println("WebSocket connection error:", err)
+		return
+	}
+	defer wsConn.Close()
+
+	go func() {
+		for {
+			_, message, err := wsConn.ReadMessage()
+			if err != nil {
+				log.Println("WebSocket read error:", err)
+				return
+			}
+			_, err = conn.Write(message)
+			if err != nil {
+				log.Println("TCP write error:", err)
+				return
+			}
+		}
+	}()
+
+	for {
+		buffer := make([]byte, 1024)
+		n, err := conn.Read(buffer)
+		if err != nil {
+			if err != io.EOF {
+				log.Println("TCP read error:", err)
+			}
+			return
+		}
+		err = wsConn.WriteMessage(websocket.BinaryMessage, buffer[:n])
+		if err != nil {
+			log.Println("WebSocket write error:", err)
+			return
+		}
+	}
+}
+
+func main() {
+	tcpPort := "7000"
+	wsURL := "ws://localhost:8000/ws" // Replace with your WebSocket server URL
+
+	listener, err := net.Listen("tcp", ":"+tcpPort)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer listener.Close()
+
+	log.Printf("TCP server listening on port %s", tcpPort)
+	log.Printf("Forwarding connections to WebSocket server at %s", wsURL)
+
+	for {
+		conn, err := listener.Accept()
+		if err != nil {
+			log.Println(err)
+			continue
+		}
+		go handleConnection(conn, wsURL)
+	}
+}
diff --git a/cmd/wstotcp/wstotcp.go b/cmd/wstotcp/wstotcp.go
new file mode 100644
index 0000000..15c3f43
--- /dev/null
+++ b/cmd/wstotcp/wstotcp.go
@@ -0,0 +1,86 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"net"
+	"net/http"
+
+	"github.com/gorilla/websocket"
+)
+
+var upgrader = websocket.Upgrader{
+	ReadBufferSize:  1024,
+	WriteBufferSize: 1024,
+}
+
+var tcpConn net.Conn
+
+func main() {
+	// Connect to TCP server
+	var err error
+	tcpConn, err = net.Dial("tcp", "localhost:2222") // Replace with your TCP server address
+	if err != nil {
+		log.Fatal("Error connecting to TCP server:", err)
+	}
+	defer tcpConn.Close()
+
+	// Set up WebSocket handler
+	http.HandleFunc("/ws", handleWebSocket)
+
+	// Start HTTP server
+	fmt.Println("WebSocket server listening on :8000")
+	log.Fatal(http.ListenAndServe(":8000", nil))
+}
+
+func handleWebSocket(w http.ResponseWriter, r *http.Request) {
+	conn, err := upgrader.Upgrade(w, r, nil)
+	if err != nil {
+		log.Println("Error upgrading to WebSocket:", err)
+		return
+	}
+	defer conn.Close()
+
+	waitChannel := make(chan bool)
+
+	// Read message from WebSocket
+	go func() {
+		defer func() {
+			waitChannel <- true
+		}()
+		for {
+			_, message, err := conn.ReadMessage()
+			if err != nil {
+				log.Println("Error reading WebSocket message:", err)
+				return
+			}
+			_, err = tcpConn.Write(message)
+			if err != nil {
+				log.Println("Error sending message to TCP server:", err)
+				return
+			}
+		}
+	}()
+
+	go func() {
+		defer func() {
+			waitChannel <- true
+		}()
+		for {
+			buffer := make([]byte, 1024)
+			n, err := tcpConn.Read(buffer)
+			if err != nil {
+				log.Println("Error reading from TCP server:", err)
+				return
+			}
+			err = conn.WriteMessage(websocket.TextMessage, buffer[:n])
+			if err != nil {
+				log.Println("Error writing WebSocket message:", err)
+				return
+			}
+		}
+	}()
+
+	<-waitChannel
+	log.Println("Connection closed")
+}
diff --git a/go.mod b/go.mod
index bb6174d..5c5eb1b 100755
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.18
 require (
 	github.com/creack/pty v1.1.21
 	github.com/gliderlabs/ssh v0.3.7
+	github.com/gorilla/websocket v1.5.3
 	github.com/pkg/sftp v1.13.6
 	golang.org/x/crypto v0.25.0
 	golang.org/x/term v0.22.0
diff --git a/go.sum b/go.sum
index 3b5301e..4762ea3 100755
--- a/go.sum
+++ b/go.sum
@@ -3,17 +3,22 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
 github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
 github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
 github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
+github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
+github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo=
 github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -51,4 +56,5 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=