@@ -7,36 +7,33 @@ import (
7
7
"io"
8
8
"log/slog"
9
9
"net/netip"
10
- "os"
11
10
"time"
12
11
13
12
"github.com/charmbracelet/huh"
14
- "github.com/mattn/go-isatty"
15
- "golang.org/x/crypto/ssh"
16
- "golang.org/x/term"
17
- "golang.org/x/xerrors"
18
13
"tailscale.com/client/tailscale"
19
14
"tailscale.com/net/netns"
20
15
"tailscale.com/tailcfg"
21
16
22
- "github.com/coder/coder/v2/pty"
23
17
"github.com/coder/serpent"
24
18
"github.com/coder/wush/cliui"
25
19
"github.com/coder/wush/overlay"
26
20
"github.com/coder/wush/tsserver"
27
21
xssh "github.com/coder/wush/xssh"
28
22
)
29
23
30
- func sendCmd () * serpent.Command {
24
+ func sshCmd () * serpent.Command {
31
25
var (
32
26
authID string
33
27
waitP2P bool
34
28
overlayTransport string
35
29
stunAddrOverride string
36
30
stunAddrOverrideIP netip.Addr
31
+ sshStdio bool
37
32
)
38
33
return & serpent.Command {
39
- Use : "send" ,
34
+ Use : "wush" ,
35
+ Long : "Opens an SSH connection to a " + cliui .Code ("wush" ) + " peer. " +
36
+ "Use " + cliui .Code ("wush receive" ) + " on the computer you would like to connect to." ,
40
37
Handler : func (inv * serpent.Invocation ) error {
41
38
ctx := inv .Context ()
42
39
logger := slog .New (slog .NewTextHandler (io .Discard , nil ))
@@ -71,19 +68,21 @@ func sendCmd() *serpent.Command {
71
68
return fmt .Errorf ("parse auth key: %w" , err )
72
69
}
73
70
74
- fmt .Println ("Auth information:" )
75
- stunStr := send .Auth .ReceiverStunAddr .String ()
76
- if ! send .Auth .ReceiverStunAddr .IsValid () {
77
- stunStr = "Disabled"
78
- }
79
- fmt .Println ("\t > Server overlay STUN address:" , cliui .Code (stunStr ))
80
- derpStr := "Disabled"
81
- if send .Auth .ReceiverDERPRegionID > 0 {
82
- derpStr = dm .Regions [int (send .Auth .ReceiverDERPRegionID )].RegionName
71
+ if ! sshStdio {
72
+ fmt .Println ("Auth information:" )
73
+ stunStr := send .Auth .ReceiverStunAddr .String ()
74
+ if ! send .Auth .ReceiverStunAddr .IsValid () {
75
+ stunStr = "Disabled"
76
+ }
77
+ fmt .Println ("\t > Server overlay STUN address:" , cliui .Code (stunStr ))
78
+ derpStr := "Disabled"
79
+ if send .Auth .ReceiverDERPRegionID > 0 {
80
+ derpStr = dm .Regions [int (send .Auth .ReceiverDERPRegionID )].RegionName
81
+ }
82
+ fmt .Println ("\t > Server overlay DERP home: " , cliui .Code (derpStr ))
83
+ fmt .Println ("\t > Server overlay public key: " , cliui .Code (send .Auth .ReceiverPublicKey .ShortString ()))
84
+ fmt .Println ("\t > Server overlay auth key: " , cliui .Code (send .Auth .OverlayPrivateKey .Public ().ShortString ()))
83
85
}
84
- fmt .Println ("\t > Server overlay DERP home: " , cliui .Code (derpStr ))
85
- fmt .Println ("\t > Server overlay public key: " , cliui .Code (send .Auth .ReceiverPublicKey .ShortString ()))
86
- fmt .Println ("\t > Server overlay auth key: " , cliui .Code (send .Auth .OverlayPrivateKey .Public ().ShortString ()))
87
86
88
87
s , err := tsserver .NewServer (ctx , logger , send )
89
88
if err != nil {
@@ -112,9 +111,9 @@ func sendCmd() *serpent.Command {
112
111
ts .Logf = func (string , ... any ) {}
113
112
ts .UserLogf = func (string , ... any ) {}
114
113
115
- fmt .Println ("Bringing Wireguard up.." )
114
+ // fmt.Println("Bringing Wireguard up..")
116
115
ts .Up (ctx )
117
- fmt .Println ("Wireguard is ready!" )
116
+ // fmt.Println("Wireguard is ready!")
118
117
119
118
lc , err := ts .LocalClient ()
120
119
if err != nil {
@@ -133,87 +132,13 @@ func sendCmd() *serpent.Command {
133
132
}
134
133
}
135
134
136
- conn , err := ts .Dial (ctx , "tcp" , ip .String ()+ ":3" )
137
- if err != nil {
138
- return err
139
- }
140
-
141
- sshConn , channels , requests , err := ssh .NewClientConn (conn , "localhost:22" , & ssh.ClientConfig {
142
- HostKeyCallback : ssh .InsecureIgnoreHostKey (),
143
- })
144
- if err != nil {
145
- return err
146
- }
147
-
148
- sshClient := ssh .NewClient (sshConn , channels , requests )
149
- sshSession , err := sshClient .NewSession ()
150
- if err != nil {
151
- return err
152
- }
153
-
154
- stdinFile , validIn := inv .Stdin .(* os.File )
155
- stdoutFile , validOut := inv .Stdout .(* os.File )
156
- if validIn && validOut && isatty .IsTerminal (stdinFile .Fd ()) && isatty .IsTerminal (stdoutFile .Fd ()) {
157
- inState , err := pty .MakeInputRaw (stdinFile .Fd ())
158
- if err != nil {
159
- return err
160
- }
161
- defer func () {
162
- _ = pty .RestoreTerminal (stdinFile .Fd (), inState )
163
- }()
164
- outState , err := pty .MakeOutputRaw (stdoutFile .Fd ())
165
- if err != nil {
166
- return err
167
- }
168
- defer func () {
169
- _ = pty .RestoreTerminal (stdoutFile .Fd (), outState )
170
- }()
171
-
172
- windowChange := xssh .ListenWindowSize (ctx )
173
- go func () {
174
- for {
175
- select {
176
- case <- ctx .Done ():
177
- return
178
- case <- windowChange :
179
- }
180
- width , height , err := term .GetSize (int (stdoutFile .Fd ()))
181
- if err != nil {
182
- continue
183
- }
184
- _ = sshSession .WindowChange (height , width )
185
- }
186
- }()
187
- }
188
-
189
- err = sshSession .RequestPty ("xterm-256color" , 128 , 128 , ssh.TerminalModes {})
190
- if err != nil {
191
- return xerrors .Errorf ("request pty: %w" , err )
192
- }
193
-
194
- sshSession .Stdin = inv .Stdin
195
- sshSession .Stdout = inv .Stdout
196
- sshSession .Stderr = inv .Stderr
197
-
198
- err = sshSession .Shell ()
199
- if err != nil {
200
- return xerrors .Errorf ("start shell: %w" , err )
201
- }
202
-
203
- if validOut {
204
- // Set initial window size.
205
- width , height , err := term .GetSize (int (stdoutFile .Fd ()))
206
- if err == nil {
207
- _ = sshSession .WindowChange (height , width )
208
- }
209
- }
210
-
211
- return sshSession .Wait ()
135
+ return xssh .TailnetSSH (ctx , inv , ts , ip .String ()+ ":3" , sshStdio )
212
136
},
213
137
Options : []serpent.Option {
214
138
{
215
139
Flag : "auth-id" ,
216
- Description : "The auth id returned by `wush receive`. If not provided, it will be asked for on startup." ,
140
+ Env : "WUSH_AUTH_ID" ,
141
+ Description : "The auth id returned by " + cliui .Code ("wush receive" ) + ". If not provided, it will be asked for on startup." ,
217
142
Default : "" ,
218
143
Value : serpent .StringOf (& authID ),
219
144
},
@@ -228,6 +153,12 @@ func sendCmd() *serpent.Command {
228
153
Default : "" ,
229
154
Value : serpent .StringOf (& stunAddrOverride ),
230
155
},
156
+ {
157
+ Flag : "stdio" ,
158
+ Description : "Run SSH over stdin/stdout. This allows wush to be used as a transport for other programs, like rsync or regular ssh." ,
159
+ Default : "false" ,
160
+ Value : serpent .BoolOf (& sshStdio ),
161
+ },
231
162
},
232
163
}
233
164
}
@@ -248,11 +179,11 @@ func waitUntilHasPeerHasIP(ctx context.Context, lc *tailscale.LocalClient) (neti
248
179
249
180
peers := stat .Peers ()
250
181
if len (peers ) == 0 {
251
- fmt .Println ("No peer yet" )
182
+ // fmt.Println("No peer yet")
252
183
continue
253
184
}
254
185
255
- fmt .Println ("Received peer" )
186
+ // fmt.Println("Received peer")
256
187
257
188
peer , ok := stat .Peer [peers [0 ]]
258
189
if ! ok {
@@ -265,7 +196,7 @@ func waitUntilHasPeerHasIP(ctx context.Context, lc *tailscale.LocalClient) (neti
265
196
continue
266
197
}
267
198
268
- fmt .Println ("Peer active with relay" , cliui .Code (peer .Relay ))
199
+ // fmt.Println("Peer active with relay", cliui.Code(peer.Relay))
269
200
270
201
if len (peer .TailscaleIPs ) == 0 {
271
202
fmt .Println ("peer has no ips (developer error)" )
@@ -302,7 +233,7 @@ func waitUntilHasP2P(ctx context.Context, lc *tailscale.LocalClient) error {
302
233
continue
303
234
}
304
235
305
- fmt .Println ("Peer active with relay" , cliui .Code (peer .Relay ))
236
+ // fmt.Println("Peer active with relay", cliui.Code(peer.Relay))
306
237
307
238
if len (peer .TailscaleIPs ) == 0 {
308
239
fmt .Println ("peer has no ips (developer error)" )
@@ -322,7 +253,7 @@ func waitUntilHasP2P(ctx context.Context, lc *tailscale.LocalClient) error {
322
253
continue
323
254
}
324
255
325
- fmt .Println ("Peer active over p2p" , cliui .Code (pong .Endpoint ))
256
+ // fmt.Println("Peer active over p2p", cliui.Code(pong.Endpoint))
326
257
return nil
327
258
}
328
259
}
0 commit comments