1
1
package chiselclient
2
2
3
3
import (
4
- "errors"
5
4
"fmt"
5
+ "io"
6
6
"net"
7
7
"net/url"
8
8
"regexp"
9
9
"strings"
10
10
"time"
11
11
12
- "github.com/hashicorp/yamux"
13
12
"github.com/jpillora/backoff"
14
13
"github.com/jpillora/chisel"
14
+ "golang.org/x/crypto/ssh"
15
15
"golang.org/x/net/websocket"
16
16
)
17
17
18
18
type Client struct {
19
19
* chisel.Logger
20
- config * chisel.Config
21
- encconfig string
22
- proxies []* Proxy
23
- session * yamux.Session
24
- running bool
25
- runningc chan error
20
+ config * chisel.Config
21
+ sshConfig * ssh.ClientConfig
22
+ proxies []* Proxy
23
+ sshConn ssh.Conn
24
+ fingerprint string
25
+ running bool
26
+ runningc chan error
26
27
}
27
28
28
29
func NewClient (auth , server string , remotes ... string ) (* Client , error ) {
@@ -63,18 +64,24 @@ func NewClient(auth, server string, remotes ...string) (*Client, error) {
63
64
config .Remotes = append (config .Remotes , r )
64
65
}
65
66
66
- encconfig , err := chisel .EncodeConfig (config )
67
- if err != nil {
68
- return nil , fmt .Errorf ("Failed to encode config: %s" , err )
67
+ c := & Client {
68
+ Logger : chisel .NewLogger ("client" ),
69
+ config : config ,
70
+ running : true ,
71
+ runningc : make (chan error , 1 ),
72
+ }
73
+
74
+ c .sshConfig = & ssh.ClientConfig {
75
+ ClientVersion : "chisel-client-" + chisel .ProtocolVersion ,
76
+ User : "jpillora" ,
77
+ Auth : []ssh.AuthMethod {ssh .Password ("t0ps3cr3t" )},
78
+ HostKeyCallback : func (hostname string , remote net.Addr , key ssh.PublicKey ) error {
79
+ c .fingerprint = chisel .FingerprintKey (key )
80
+ return nil
81
+ },
69
82
}
70
83
71
- return & Client {
72
- Logger : chisel .NewLogger ("client" ),
73
- config : config ,
74
- encconfig : encconfig ,
75
- running : true ,
76
- runningc : make (chan error , 1 ),
77
- }, nil
84
+ return c , nil
78
85
}
79
86
80
87
//Start then Wait
@@ -91,81 +98,54 @@ func (c *Client) Start() {
91
98
func (c * Client ) start () {
92
99
c .Infof ("Connecting to %s\n " , c .config .Server )
93
100
94
- //proxies all use this function
95
- openStream := func () (net.Conn , error ) {
96
- if c .session == nil || c .session .IsClosed () {
97
- return nil , c .Errorf ("no session available" )
98
- }
99
- stream , err := c .session .Open ()
100
- if err != nil {
101
- return nil , err
102
- }
103
- return stream , nil
104
- }
105
-
106
101
//prepare proxies
107
102
for id , r := range c .config .Remotes {
108
- proxy := NewProxy (c , id , r , openStream )
103
+ proxy := NewProxy (c , id , r )
109
104
go proxy .start ()
110
105
c .proxies = append (c .proxies , proxy )
111
106
}
112
107
108
+ //connection loop!
113
109
var connerr error
114
110
b := & backoff.Backoff {Max : 5 * time .Minute }
115
-
116
- //connection loop!
117
111
for {
118
112
if ! c .running {
119
113
break
120
114
}
121
115
if connerr != nil {
122
- connerr = nil
123
116
d := b .Duration ()
124
117
c .Infof ("Retrying in %s...\n " , d )
118
+ connerr = nil
125
119
time .Sleep (d )
126
120
}
127
121
128
- ws , err := websocket .Dial (c .config .Server , c . encconfig , "http:// localhost/ " )
122
+ ws , err := websocket .Dial (c .config .Server , chisel . ConfigPrefix , "localhost:80 " )
129
123
if err != nil {
130
124
connerr = err
131
125
continue
132
126
}
133
127
134
- buff := make ([]byte , 0xff )
135
- n , _ := ws .Read (buff )
136
- if msg := string (buff [:n ]); msg != "handshake-success" {
137
- //no point in retrying
138
- c .runningc <- errors .New (msg )
139
- ws .Close ()
140
- break
141
- }
142
-
143
- // Setup client side of yamux
144
- c .session , err = yamux .Client (ws , nil )
128
+ sshConn , chans , reqs , err := ssh .NewClientConn (ws , "" , c .sshConfig )
145
129
if err != nil {
146
130
connerr = err
131
+ c .Infof ("Handshake failed: %s" , err )
147
132
continue
148
133
}
134
+ c .Infof ("Connected (%s)" , c .fingerprint )
135
+ //connected
149
136
b .Reset ()
150
-
151
- //signal is connected
152
- connected := make (chan bool )
153
- c .Infof ("Connected\n " )
154
-
155
- //poll websocket state
156
- go func () {
157
- for {
158
- if c .session .IsClosed () {
159
- connerr = c .Errorf ("disconnected" )
160
- c .Infof ("Disconnected\n " )
161
- close (connected )
162
- break
163
- }
164
- time .Sleep (100 * time .Millisecond )
165
- }
166
- }()
167
- //block!
168
- <- connected
137
+ c .sshConn = sshConn
138
+ go ssh .DiscardRequests (reqs )
139
+ go chisel .RejectStreams (chans )
140
+ err = sshConn .Wait ()
141
+ //disconnected
142
+ c .sshConn = nil
143
+ if err != nil && err != io .EOF {
144
+ connerr = err
145
+ c .Infof ("Disconnection error: %s" , err )
146
+ continue
147
+ }
148
+ c .Infof ("Disconnected\n " )
169
149
}
170
150
close (c .runningc )
171
151
}
@@ -178,8 +158,8 @@ func (c *Client) Wait() error {
178
158
//Close manual stops the client
179
159
func (c * Client ) Close () error {
180
160
c .running = false
181
- if c .session == nil {
161
+ if c .sshConn == nil {
182
162
return nil
183
163
}
184
- return c .session .Close ()
164
+ return c .sshConn .Close ()
185
165
}
0 commit comments