Skip to content

Commit 98cb623

Browse files
committed
working!
1 parent 0fdc693 commit 98cb623

File tree

11 files changed

+308
-217
lines changed

11 files changed

+308
-217
lines changed

README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# chisel
2+
3+
Chisel is TCP proxy tunnelled over HTTP and Websockets
4+
5+
### Install
6+
7+
Server
8+
9+
```
10+
$ go get -v github.com/jpillora/chisel/chiseld
11+
$ chiseld --help
12+
13+
Usage: chiseld [--host 0.0.0.0] [--port 8080] [--auth str]
14+
15+
host defines the HTTP listening host – the
16+
network interface (defaults to 0.0.0.0). You
17+
may also set the HOST environment variable.
18+
19+
port defines the HTTP listening port (defaults
20+
to 8080). You may also set the PORT environment
21+
variable.
22+
23+
auth specifies the exact authentication string
24+
the client must provide to attain access. You
25+
may also set the AUTH environment variable.
26+
```
27+
28+
Forwarder
29+
30+
```
31+
$ go get -v github.com/jpillora/chisel/chisel-forward
32+
$ chisel-forward --help
33+
34+
Usage: chisel-forward [--auth str] server remote [remote] [remote] ...
35+
36+
where 'server' is the URL to the chiseld server
37+
38+
where 'remote' is a remote connection via the server, in the form
39+
example.com:3000 (which means http://0.0.0.0:3000 => http://example.com:3000)
40+
3000:google.com:80 (which means http://0.0.0.0:3000 => http://google.com:80)
41+
```
42+
43+
### Usage
44+
45+
46+
### Performance
47+
48+
With crowbar, I was getting extremely slow transfer times
49+
50+
```
51+
#tab 1 (basic file server)
52+
$ serve -p 4000
53+
54+
#tab 2 (tunnel server)
55+
$ echo -ne "foo:bar" > userfile
56+
$ crowbard -listen="0.0.0.0:8080" -userfile=./userfile
57+
58+
#tab 3 (tunnel client)
59+
$ crowbar-forward -local=0.0.0.0:3000 -server http://localhost:8080 -remote localhost:4000 -username foo -password bar
60+
61+
#tab 4 (transfer test)
62+
$ time curl -s "127.0.0.1:3000/largefile.bin" > /dev/null
63+
74.74 real 2.37 user 6.74 sys
64+
```
65+
66+
Here, `largefile.bin` (~200MB) is transferred in 1m14s over localhost (also has high CPU utilisation).
67+
68+
Enter `chisel`, lets swap in `chiseld` and `chisel-forward`:
69+
70+
```
71+
#tab 2 (tunnel server)
72+
$ chiseld --auth foo
73+
74+
#tab 3 (tunnel client)
75+
$ chisel-forward --auth foo http://localhost:8080 3000:4000
76+
2015/02/27 16:13:43 Connected to http://localhost:8080
77+
2015/02/27 16:13:43 Proxy 0.0.0.0:3000 => 0.0.0.0:4000 enabled
78+
79+
#tab 4 (transfer test)
80+
$ time curl -s "127.0.0.1:3000/largefile.bin" > /dev/null
81+
0.60 real 0.05 user 0.14 sys
82+
```
83+
84+
Here, the same file was transferred in 0.6s
85+
86+
#### MIT License
87+
88+
Copyright © 2014 Jaime Pillora <[email protected]>
89+
90+
Permission is hereby granted, free of charge, to any person obtaining
91+
a copy of this software and associated documentation files (the
92+
'Software'), to deal in the Software without restriction, including
93+
without limitation the rights to use, copy, modify, merge, publish,
94+
distribute, sublicense, and/or sell copies of the Software, and to
95+
permit persons to whom the Software is furnished to do so, subject to
96+
the following conditions:
97+
98+
The above copyright notice and this permission notice shall be
99+
included in all copies or substantial portions of the Software.
100+
101+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
102+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
104+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
105+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
106+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

chisel-forward/client/client.go

Lines changed: 36 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package client
22

33
import (
4-
"fmt"
54
"log"
5+
"net"
66
"strings"
77

88
"github.com/hashicorp/yamux"
@@ -12,23 +12,21 @@ import (
1212

1313
type Client struct {
1414
config *chisel.Config
15-
proxies []*ProxyServer
16-
ws *websocket.Conn
17-
session *yamux.Session
15+
proxies []*Proxy
1816
}
1917

20-
func NewClient(auth, server string, args []string) *Client {
18+
func NewClient(auth, server string, remotes []string) *Client {
2119

2220
c := &chisel.Config{
2321
Version: chisel.Version,
2422
Auth: auth,
2523
Server: server,
2624
}
2725

28-
for _, a := range args {
29-
r, err := chisel.DecodeRemote(a)
26+
for _, s := range remotes {
27+
r, err := chisel.DecodeRemote(s)
3028
if err != nil {
31-
log.Fatalf("Remote decode failed: %s", err)
29+
log.Fatalf("Failed to decode remote '%s': %s", s, err)
3230
}
3331
c.Remotes = append(c.Remotes, r)
3432
}
@@ -37,70 +35,53 @@ func NewClient(auth, server string, args []string) *Client {
3735
}
3836

3937
func (c *Client) Start() {
40-
s, err := chisel.EncodeConfig(c.config)
38+
encconfig, err := chisel.EncodeConfig(c.config)
4139
if err != nil {
4240
log.Fatal(err)
4341
}
4442

4543
url := strings.Replace(c.config.Server, "http:", "ws:", 1)
46-
c.ws, err = websocket.Dial(url, s, "http://localhost/")
44+
ws, err := websocket.Dial(url, encconfig, "http://localhost/")
4745
if err != nil {
4846
log.Fatal(err)
4947
}
5048

49+
b := make([]byte, 0xff)
50+
n, _ := ws.Read(b)
51+
if msg := string(b[:n]); msg != "handshake-success" {
52+
log.Fatal(msg)
53+
}
54+
5155
// Setup client side of yamux
52-
c.session, err = yamux.Client(c.ws, nil)
56+
session, err := yamux.Client(ws, nil)
5357
if err != nil {
5458
log.Fatal(err)
5559
}
5660

57-
//prepare proxies
58-
for id, r := range c.config.Remotes {
59-
if err := c.setupProxy(id, r, c.session); err != nil {
60-
log.Fatal(err)
61-
}
62-
}
63-
64-
// ws.Write([]byte("hello!"))
65-
66-
fmt.Printf("Connected to %s\n", c.config.Server)
67-
c.handleData()
68-
fmt.Printf("Disconnected\n")
69-
}
70-
71-
func (c *Client) setupProxy(id int, r *chisel.Remote, session *yamux.Session) error {
72-
73-
addr := r.LocalHost + ":" + r.LocalPort
74-
75-
proxy := NewProxyServer(id, addr, session)
76-
//watch conn for writes
77-
// go func() {
78-
// for b := range conn.out {
79-
// //encode
80-
// c.ws.Write(b)
81-
// }
82-
// }()
83-
84-
go proxy.start()
85-
c.proxies = append(c.proxies, proxy)
86-
return nil
87-
}
88-
89-
func (c *Client) handleData() {
90-
91-
buff := make([]byte, 0xffff)
92-
for {
93-
n, err := c.ws.Read(buff)
61+
markClosed := make(chan bool)
62+
isClosed := false
9463

64+
//proxies all use this function
65+
openStream := func() (net.Conn, error) {
66+
stream, err := session.Open()
9567
if err != nil {
96-
break
68+
if !isClosed {
69+
close(markClosed)
70+
}
71+
return nil, err
9772
}
73+
return stream, nil
74+
}
9875

99-
b := buff[:n]
100-
101-
fmt.Printf("%s\n", b)
102-
103-
//decode
104-
//place on proxy's read queue
76+
//prepare proxies
77+
for id, r := range c.config.Remotes {
78+
proxy := NewProxy(id, r, openStream)
79+
go proxy.start()
80+
c.proxies = append(c.proxies, proxy)
10581
}
82+
83+
log.Printf("Connected to %s\n", c.config.Server)
84+
<-markClosed
85+
isClosed = true
86+
log.Printf("Disconnected\n")
10687
}

chisel-forward/client/proxy-server.go

Lines changed: 0 additions & 69 deletions
This file was deleted.

chisel-forward/client/proxy.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package client
2+
3+
import (
4+
"encoding/binary"
5+
"log"
6+
"net"
7+
8+
"github.com/jpillora/chisel"
9+
)
10+
11+
type Proxy struct {
12+
id int
13+
count int
14+
remote *chisel.Remote
15+
openStream func() (net.Conn, error)
16+
}
17+
18+
func NewProxy(id int, remote *chisel.Remote, openStream func() (net.Conn, error)) *Proxy {
19+
return &Proxy{
20+
id: id,
21+
remote: remote,
22+
openStream: openStream,
23+
}
24+
}
25+
26+
func (p *Proxy) start() {
27+
28+
l, err := net.Listen("tcp4", p.remote.LocalHost+":"+p.remote.LocalPort)
29+
if err != nil {
30+
log.Printf("Proxy %s failed: %s", p.remote, err)
31+
return
32+
}
33+
34+
log.Printf("Proxy %s enabled", p.remote)
35+
for {
36+
src, err := l.Accept()
37+
if err != nil {
38+
log.Println(err)
39+
return
40+
}
41+
go p.accept(src)
42+
}
43+
}
44+
45+
func (p *Proxy) accept(src net.Conn) {
46+
p.count++
47+
c := p.count
48+
49+
log.Printf("[#%d] accept conn %d", p.id, c)
50+
51+
dst, err := p.openStream()
52+
if err != nil {
53+
log.Println(err)
54+
return
55+
}
56+
57+
//write endpoint id
58+
b := make([]byte, 2)
59+
binary.BigEndian.PutUint16(b, uint16(p.id))
60+
dst.Write(b)
61+
62+
//then pipe
63+
chisel.Pipe(src, dst)
64+
65+
log.Printf("[#%d] close conn %d", p.id, c)
66+
}

0 commit comments

Comments
 (0)