Skip to content

Commit

Permalink
feat(client): add vex client
Browse files Browse the repository at this point in the history
  • Loading branch information
jkuri committed Apr 16, 2018
1 parent 8b74748 commit ad6fe5d
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ OSARCH = "!darwin/arm !windows/arm"

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

clean:
rm -rf ${OUTPUT_DIR}
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Vex is a reverse HTTP proxy tunnel via secure SSH connections. It is compatible
<img src="https://user-images.githubusercontent.com/1796022/38793799-f23c981a-4152-11e8-9e6c-382ce6536c87.png">
</p>

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

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

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

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

### Establish tunnel with vexd server on bleenco.space (vex client)

```sh
$ vex -s bleenco.space -p 2200 -ls localhost -lp 7500
```

`vex` client options:

```
Usage: vex [options]
Options:
-s, SSH server remote host (default: bleenco.space)
-p, SSH server remote port (default: 2200)
-ls, Local HTTP server host (default: localhost)
-lp, Local HTTP server port (default: 7500)
```

### Run cross-compilation build

```sh
Expand Down
151 changes: 151 additions & 0 deletions cmd/vex/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package main

import (
"flag"
"fmt"
"io"
"log"
"math/rand"
"net"
"os"
"os/signal"
"time"

"golang.org/x/crypto/ssh"
)

type Endpoint struct {
Host string
Port int
}

func (endpoint *Endpoint) String() string {
return fmt.Sprintf("%s:%d", endpoint.Host, endpoint.Port)
}

var help = `
Usage: vex [options]
Options:
-s, SSH server remote host (default: bleenco.space)
-p, SSH server remote port (default: 2200)
-ls, Local HTTP server host (default: localhost)
-lp, Local HTTP server port (default: 7500)
Read more:
https:/bleenco/vex
`

var (
remoteServer = flag.String("s", "bleenco.space", "")
remotePort = flag.Int("p", 2200, "")
localServer = flag.String("ls", "localhost", "")
localPort = flag.Int("lp", 7500, "")
)

func main() {
flag.Usage = func() {
fmt.Print(help)
os.Exit(1)
}
flag.Parse()

// local service to be forwarded
var localEndpoint = Endpoint{
Host: *localServer,
Port: *localPort,
}

// remote SSH server
var serverEndpoint = Endpoint{
Host: *remoteServer,
Port: *remotePort,
}

// remote forwarding port (on remote SSH server network)
var remoteEndpoint = Endpoint{
Host: "localhost",
Port: randomPort(11000, 65000),
}

sshConfig := &ssh.ClientConfig{
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

// Connect to SSH remote server using serverEndpoint
serverConn, err := ssh.Dial("tcp", serverEndpoint.String(), sshConfig)
if err != nil {
log.Fatalln(fmt.Printf("Dial INTO remote server error: %s", err))
}

go func() {
session, err := serverConn.NewSession()
if err != nil {
log.Fatalln(fmt.Printf("Cannot create session error: %s", err))
}

stdout, err := session.StdoutPipe()
if err != nil {
log.Fatalln(fmt.Printf("Unable to setup stdout for session: %s", err))
}

go io.Copy(os.Stdout, stdout)
}()

// Listen on remote server port
listener, err := serverConn.Listen("tcp", remoteEndpoint.String())
if err != nil {
log.Fatalln(fmt.Printf("Listen open port ON remote server error: %s", err))
}
defer listener.Close()

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)

for {
// Open a (local) connection to localEndpoint whose content will be forwarded so serverEndpoint
local, err := net.Dial("tcp", localEndpoint.String())
if err != nil {
log.Fatalln(fmt.Printf("Dial INTO local service error: %s", err))
}

client, err := listener.Accept()
if err != nil {
log.Fatalln(err)
}

go handleClient(client, local)
}
}

func handleClient(client net.Conn, remote net.Conn) {
defer client.Close()
chDone := make(chan bool)

go func() {
_, err := io.Copy(client, remote)
if err != nil {
log.Println(fmt.Sprintf("error while copy remote->local: %s", err))
}
chDone <- true
}()

go func() {
_, err := io.Copy(remote, client)
if err != nil {
log.Println(fmt.Sprintf("error while copy local->remote: %s", err))
}
chDone <- true
}()

<-chDone
}

func randomPort(min, max int) int {
rand.Seed(time.Now().Unix())
return rand.Intn(max-min) + min
}

0 comments on commit ad6fe5d

Please sign in to comment.