Skip to content

Commit ad6fe5d

Browse files
committed
feat(client): add vex client
1 parent 8b74748 commit ad6fe5d

File tree

3 files changed

+175
-2
lines changed

3 files changed

+175
-2
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ OSARCH = "!darwin/arm !windows/arm"
55

66
build:
77
mkdir -p ${OUTPUT_DIR}
8-
GOARM=5 gox -os=${OS} -arch=${ARCH} -osarch=${OSARCH} -output "${OUTPUT_DIR}/{{.Dir}}_{{.OS}}_{{.Arch}}" ./cmd/vexd
8+
GOARM=5 gox -os=${OS} -arch=${ARCH} -osarch=${OSARCH} -output "${OUTPUT_DIR}/{{.Dir}}_{{.OS}}_{{.Arch}}" ./cmd/vexd ./cmd/vex
99

1010
clean:
1111
rm -rf ${OUTPUT_DIR}

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Vex is a reverse HTTP proxy tunnel via secure SSH connections. It is compatible
66
<img src="https://user-images.githubusercontent.com/1796022/38793799-f23c981a-4152-11e8-9e6c-382ce6536c87.png">
77
</p>
88

9-
### Establish tunnel via running vex server on bleenco.space
9+
### Establish tunnel with vexd server on bleenco.space (ssh client)
1010

1111
Let's say you are running HTTP server locally on port 6500, then command would be:
1212

@@ -27,6 +27,28 @@ $ ssh -R 10500:localhost:6500 bleenco.space -p 2200
2727

2828
Then open generated URL in the browser to check if works, then share the URL if needed.
2929

30+
### Establish tunnel with vexd server on bleenco.space (vex client)
31+
32+
```sh
33+
$ vex -s bleenco.space -p 2200 -ls localhost -lp 7500
34+
```
35+
36+
`vex` client options:
37+
38+
```
39+
Usage: vex [options]
40+
41+
Options:
42+
43+
-s, SSH server remote host (default: bleenco.space)
44+
45+
-p, SSH server remote port (default: 2200)
46+
47+
-ls, Local HTTP server host (default: localhost)
48+
49+
-lp, Local HTTP server port (default: 7500)
50+
```
51+
3052
### Run cross-compilation build
3153

3254
```sh

cmd/vex/main.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"io"
7+
"log"
8+
"math/rand"
9+
"net"
10+
"os"
11+
"os/signal"
12+
"time"
13+
14+
"golang.org/x/crypto/ssh"
15+
)
16+
17+
type Endpoint struct {
18+
Host string
19+
Port int
20+
}
21+
22+
func (endpoint *Endpoint) String() string {
23+
return fmt.Sprintf("%s:%d", endpoint.Host, endpoint.Port)
24+
}
25+
26+
var help = `
27+
Usage: vex [options]
28+
29+
Options:
30+
31+
-s, SSH server remote host (default: bleenco.space)
32+
33+
-p, SSH server remote port (default: 2200)
34+
35+
-ls, Local HTTP server host (default: localhost)
36+
37+
-lp, Local HTTP server port (default: 7500)
38+
39+
Read more:
40+
https://github.com/bleenco/vex
41+
`
42+
43+
var (
44+
remoteServer = flag.String("s", "bleenco.space", "")
45+
remotePort = flag.Int("p", 2200, "")
46+
localServer = flag.String("ls", "localhost", "")
47+
localPort = flag.Int("lp", 7500, "")
48+
)
49+
50+
func main() {
51+
flag.Usage = func() {
52+
fmt.Print(help)
53+
os.Exit(1)
54+
}
55+
flag.Parse()
56+
57+
// local service to be forwarded
58+
var localEndpoint = Endpoint{
59+
Host: *localServer,
60+
Port: *localPort,
61+
}
62+
63+
// remote SSH server
64+
var serverEndpoint = Endpoint{
65+
Host: *remoteServer,
66+
Port: *remotePort,
67+
}
68+
69+
// remote forwarding port (on remote SSH server network)
70+
var remoteEndpoint = Endpoint{
71+
Host: "localhost",
72+
Port: randomPort(11000, 65000),
73+
}
74+
75+
sshConfig := &ssh.ClientConfig{
76+
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
77+
}
78+
79+
// Connect to SSH remote server using serverEndpoint
80+
serverConn, err := ssh.Dial("tcp", serverEndpoint.String(), sshConfig)
81+
if err != nil {
82+
log.Fatalln(fmt.Printf("Dial INTO remote server error: %s", err))
83+
}
84+
85+
go func() {
86+
session, err := serverConn.NewSession()
87+
if err != nil {
88+
log.Fatalln(fmt.Printf("Cannot create session error: %s", err))
89+
}
90+
91+
stdout, err := session.StdoutPipe()
92+
if err != nil {
93+
log.Fatalln(fmt.Printf("Unable to setup stdout for session: %s", err))
94+
}
95+
96+
go io.Copy(os.Stdout, stdout)
97+
}()
98+
99+
// Listen on remote server port
100+
listener, err := serverConn.Listen("tcp", remoteEndpoint.String())
101+
if err != nil {
102+
log.Fatalln(fmt.Printf("Listen open port ON remote server error: %s", err))
103+
}
104+
defer listener.Close()
105+
106+
c := make(chan os.Signal, 1)
107+
signal.Notify(c, os.Interrupt)
108+
109+
for {
110+
// Open a (local) connection to localEndpoint whose content will be forwarded so serverEndpoint
111+
local, err := net.Dial("tcp", localEndpoint.String())
112+
if err != nil {
113+
log.Fatalln(fmt.Printf("Dial INTO local service error: %s", err))
114+
}
115+
116+
client, err := listener.Accept()
117+
if err != nil {
118+
log.Fatalln(err)
119+
}
120+
121+
go handleClient(client, local)
122+
}
123+
}
124+
125+
func handleClient(client net.Conn, remote net.Conn) {
126+
defer client.Close()
127+
chDone := make(chan bool)
128+
129+
go func() {
130+
_, err := io.Copy(client, remote)
131+
if err != nil {
132+
log.Println(fmt.Sprintf("error while copy remote->local: %s", err))
133+
}
134+
chDone <- true
135+
}()
136+
137+
go func() {
138+
_, err := io.Copy(remote, client)
139+
if err != nil {
140+
log.Println(fmt.Sprintf("error while copy local->remote: %s", err))
141+
}
142+
chDone <- true
143+
}()
144+
145+
<-chDone
146+
}
147+
148+
func randomPort(min, max int) int {
149+
rand.Seed(time.Now().Unix())
150+
return rand.Intn(max-min) + min
151+
}

0 commit comments

Comments
 (0)