a geicko-2 based round robin ranking system designed to test c++ battleship submissions
battleship.dunkirk.sh
1package ssh
2
3import (
4 "context"
5 "encoding/base64"
6 "errors"
7 "fmt"
8 "net"
9 "sync"
10 "time"
11
12 gossh "golang.org/x/crypto/ssh"
13)
14
15// ErrServerClosed is returned by the Server's Serve, ListenAndServe,
16// and ListenAndServeTLS methods after a call to Shutdown or Close.
17var ErrServerClosed = errors.New("ssh: Server closed")
18
19type SubsystemHandler func(s Session)
20
21var DefaultSubsystemHandlers = map[string]SubsystemHandler{}
22
23type RequestHandler func(ctx Context, srv *Server, req *gossh.Request) (ok bool, payload []byte)
24
25var DefaultRequestHandlers = map[string]RequestHandler{}
26
27type ChannelHandler func(srv *Server, conn *gossh.ServerConn, newChan gossh.NewChannel, ctx Context)
28
29var DefaultChannelHandlers = map[string]ChannelHandler{
30 "session": DefaultSessionHandler,
31}
32
33var permissionsPublicKeyExt = "gliderlabs/ssh.PublicKey"
34
35func ensureNoPKInPermissions(ctx Context) error {
36 if _, ok := ctx.Permissions().Permissions.Extensions[permissionsPublicKeyExt]; ok {
37 return errors.New("misconfigured server: public key incorrectly set")
38 }
39
40 return nil
41}
42
43// Server defines parameters for running an SSH server. The zero value for
44// Server is a valid configuration. When both PasswordHandler and
45// PublicKeyHandler are nil, no client authentication is performed.
46type Server struct {
47 Addr string // TCP address to listen on, ":22" if empty
48 Handler Handler // handler to invoke, ssh.DefaultHandler if nil
49 HostSigners []Signer // private keys for the host key, must have at least one
50 Version string // server version to be sent before the initial handshake
51 Banner string // server banner
52
53 BannerHandler BannerHandler // server banner handler, overrides Banner
54 KeyboardInteractiveHandler KeyboardInteractiveHandler // keyboard-interactive authentication handler
55 PasswordHandler PasswordHandler // password authentication handler
56 PublicKeyHandler PublicKeyHandler // public key authentication handler
57 PtyCallback PtyCallback // callback for allocating and allowing PTY sessions, ssh.EmulatePtyCallback if nil
58 PtyHandler PtyHandler // pty allocation handler, ssh.emulatePtyHandler if nil
59 ConnCallback ConnCallback // optional callback for wrapping net.Conn before handling
60 LocalPortForwardingCallback LocalPortForwardingCallback // callback for allowing local port forwarding, denies all if nil
61 ReversePortForwardingCallback ReversePortForwardingCallback // callback for allowing reverse port forwarding, denies all if nil
62 ServerConfigCallback ServerConfigCallback // callback for configuring detailed SSH options
63 SessionRequestCallback SessionRequestCallback // callback for allowing or denying SSH sessions
64
65 ConnectionFailedCallback ConnectionFailedCallback // callback to report connection failures
66
67 IdleTimeout time.Duration // connection timeout when no activity, none if empty
68 MaxTimeout time.Duration // absolute connection timeout, none if empty
69
70 // ChannelHandlers allow overriding the built-in session handlers or provide
71 // extensions to the protocol, such as tcpip forwarding. By default only the
72 // "session" handler is enabled.
73 ChannelHandlers map[string]ChannelHandler
74
75 // RequestHandlers allow overriding the server-level request handlers or
76 // provide extensions to the protocol, such as tcpip forwarding. By default
77 // no handlers are enabled.
78 RequestHandlers map[string]RequestHandler
79
80 // SubsystemHandlers are handlers which are similar to the usual SSH command
81 // handlers, but handle named subsystems.
82 SubsystemHandlers map[string]SubsystemHandler
83
84 listenerWg sync.WaitGroup
85 mu sync.RWMutex
86 listeners map[net.Listener]struct{}
87 conns map[*gossh.ServerConn]struct{}
88 connWg sync.WaitGroup
89 doneChan chan struct{}
90}
91
92func (srv *Server) ensureHostSigner() error {
93 srv.mu.Lock()
94 defer srv.mu.Unlock()
95
96 if len(srv.HostSigners) == 0 {
97 signer, err := generateSigner()
98 if err != nil {
99 return err
100 }
101 srv.HostSigners = append(srv.HostSigners, signer)
102 }
103 return nil
104}
105
106func (srv *Server) ensureHandlers() {
107 srv.mu.Lock()
108 defer srv.mu.Unlock()
109
110 if srv.RequestHandlers == nil {
111 srv.RequestHandlers = map[string]RequestHandler{}
112 for k, v := range DefaultRequestHandlers {
113 srv.RequestHandlers[k] = v
114 }
115 }
116 if srv.ChannelHandlers == nil {
117 srv.ChannelHandlers = map[string]ChannelHandler{}
118 for k, v := range DefaultChannelHandlers {
119 srv.ChannelHandlers[k] = v
120 }
121 }
122 if srv.SubsystemHandlers == nil {
123 srv.SubsystemHandlers = map[string]SubsystemHandler{}
124 for k, v := range DefaultSubsystemHandlers {
125 srv.SubsystemHandlers[k] = v
126 }
127 }
128}
129
130func (srv *Server) config(ctx Context) *gossh.ServerConfig {
131 srv.mu.Lock()
132 defer srv.mu.Unlock()
133
134 var config *gossh.ServerConfig
135 if srv.ServerConfigCallback == nil {
136 config = &gossh.ServerConfig{}
137 } else {
138 config = srv.ServerConfigCallback(ctx)
139 }
140 for _, signer := range srv.HostSigners {
141 config.AddHostKey(signer)
142 }
143 if srv.PasswordHandler == nil && srv.PublicKeyHandler == nil && srv.KeyboardInteractiveHandler == nil {
144 config.NoClientAuth = true
145 }
146 if srv.PtyHandler == nil {
147 srv.PtyHandler = emulatePtyHandler
148 }
149 if srv.Version != "" {
150 config.ServerVersion = "SSH-2.0-" + srv.Version
151 }
152 if srv.Banner != "" {
153 config.BannerCallback = func(_ gossh.ConnMetadata) string {
154 return srv.Banner
155 }
156 }
157 if srv.BannerHandler != nil {
158 config.BannerCallback = func(conn gossh.ConnMetadata) string {
159 applyConnMetadata(ctx, conn)
160 return srv.BannerHandler(ctx)
161 }
162 }
163 if srv.PasswordHandler != nil {
164 config.PasswordCallback = func(conn gossh.ConnMetadata, password []byte) (*gossh.Permissions, error) {
165 resetPermissions(ctx)
166 applyConnMetadata(ctx, conn)
167 err := ensureNoPKInPermissions(ctx)
168 if err != nil {
169 return ctx.Permissions().Permissions, err
170 }
171 ok := srv.PasswordHandler(ctx, string(password))
172 if !ok {
173 return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
174 }
175 return ctx.Permissions().Permissions, nil
176 }
177 }
178 if srv.PublicKeyHandler != nil {
179 config.PublicKeyCallback = func(conn gossh.ConnMetadata, key gossh.PublicKey) (*gossh.Permissions, error) {
180 resetPermissions(ctx)
181 applyConnMetadata(ctx, conn)
182 err := ensureNoPKInPermissions(ctx)
183 if err != nil {
184 return ctx.Permissions().Permissions, err
185 }
186 ok := srv.PublicKeyHandler(ctx, key)
187 if !ok {
188 return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
189 }
190
191 pkStr := base64.StdEncoding.EncodeToString(key.Marshal())
192 if ctx.Permissions().Permissions.Extensions == nil {
193 ctx.Permissions().Permissions.Extensions = map[string]string{}
194 }
195 ctx.Permissions().Permissions.Extensions[permissionsPublicKeyExt] = pkStr
196
197 return ctx.Permissions().Permissions, nil
198 }
199 }
200 if srv.KeyboardInteractiveHandler != nil {
201 config.KeyboardInteractiveCallback = func(conn gossh.ConnMetadata, challenger gossh.KeyboardInteractiveChallenge) (*gossh.Permissions, error) {
202 resetPermissions(ctx)
203 applyConnMetadata(ctx, conn)
204 ok := srv.KeyboardInteractiveHandler(ctx, challenger)
205 err := ensureNoPKInPermissions(ctx)
206 if err != nil {
207 return ctx.Permissions().Permissions, err
208 }
209 if !ok {
210 return ctx.Permissions().Permissions, fmt.Errorf("permission denied")
211 }
212 return ctx.Permissions().Permissions, nil
213 }
214 }
215 return config
216}
217
218// Handle sets the Handler for the server.
219func (srv *Server) Handle(fn Handler) {
220 srv.mu.Lock()
221 defer srv.mu.Unlock()
222
223 srv.Handler = fn
224}
225
226// Close immediately closes all active listeners and all active
227// connections.
228//
229// Close returns any error returned from closing the Server's
230// underlying Listener(s).
231func (srv *Server) Close() error {
232 srv.mu.Lock()
233 defer srv.mu.Unlock()
234
235 srv.closeDoneChanLocked()
236 err := srv.closeListenersLocked()
237 for c := range srv.conns {
238 c.Close()
239 delete(srv.conns, c)
240 }
241 return err
242}
243
244// Shutdown gracefully shuts down the server without interrupting any
245// active connections. Shutdown works by first closing all open
246// listeners, and then waiting indefinitely for connections to close.
247// If the provided context expires before the shutdown is complete,
248// then the context's error is returned.
249func (srv *Server) Shutdown(ctx context.Context) error {
250 srv.mu.Lock()
251 lnerr := srv.closeListenersLocked()
252 srv.closeDoneChanLocked()
253 srv.mu.Unlock()
254
255 finished := make(chan struct{}, 1)
256 go func() {
257 srv.listenerWg.Wait()
258 srv.connWg.Wait()
259 finished <- struct{}{}
260 }()
261
262 select {
263 case <-ctx.Done():
264 return ctx.Err()
265 case <-finished:
266 return lnerr
267 }
268}
269
270// Serve accepts incoming connections on the Listener l, creating a new
271// connection goroutine for each. The connection goroutines read requests and then
272// calls srv.Handler to handle sessions.
273//
274// Serve always returns a non-nil error.
275func (srv *Server) Serve(l net.Listener) error {
276 srv.ensureHandlers()
277 defer l.Close()
278 if err := srv.ensureHostSigner(); err != nil {
279 return err
280 }
281 if srv.Handler == nil {
282 srv.Handler = DefaultHandler
283 }
284 var tempDelay time.Duration
285
286 srv.trackListener(l, true)
287 defer srv.trackListener(l, false)
288 for {
289 conn, e := l.Accept()
290 if e != nil {
291 select {
292 case <-srv.getDoneChan():
293 return ErrServerClosed
294 default:
295 }
296 if ne, ok := e.(net.Error); ok && ne.Temporary() {
297 if tempDelay == 0 {
298 tempDelay = 5 * time.Millisecond
299 } else {
300 tempDelay *= 2
301 }
302 if max := 1 * time.Second; tempDelay > max {
303 tempDelay = max
304 }
305 time.Sleep(tempDelay)
306 continue
307 }
308 return e
309 }
310 go srv.HandleConn(conn)
311 }
312}
313
314func (srv *Server) HandleConn(newConn net.Conn) {
315 ctx, cancel := newContext(srv)
316 if srv.ConnCallback != nil {
317 cbConn := srv.ConnCallback(ctx, newConn)
318 if cbConn == nil {
319 newConn.Close()
320 return
321 }
322 newConn = cbConn
323 }
324 conn := &serverConn{
325 Conn: newConn,
326 idleTimeout: srv.IdleTimeout,
327 closeCanceler: cancel,
328 }
329 if srv.MaxTimeout > 0 {
330 conn.maxDeadline = time.Now().Add(srv.MaxTimeout)
331 }
332 defer conn.Close()
333 sshConn, chans, reqs, err := gossh.NewServerConn(conn, srv.config(ctx))
334 if err != nil {
335 if srv.ConnectionFailedCallback != nil {
336 srv.ConnectionFailedCallback(conn, err)
337 }
338 return
339 }
340
341 if sshConn.Permissions != nil {
342 // Now that the connection was authed, if the permissionsPublicKeyExt was
343 // attached, we need to re-parse it as a public key.
344 if keyData, ok := sshConn.Permissions.Extensions[permissionsPublicKeyExt]; ok {
345 decodedData, err := base64.StdEncoding.DecodeString(keyData)
346 if err != nil {
347 if srv.ConnectionFailedCallback != nil {
348 srv.ConnectionFailedCallback(conn, err)
349 }
350 return
351 }
352
353 key, err := gossh.ParsePublicKey(decodedData)
354 if err != nil {
355 if srv.ConnectionFailedCallback != nil {
356 srv.ConnectionFailedCallback(conn, err)
357 }
358 return
359 }
360
361 ctx.SetValue(ContextKeyPublicKey, key)
362 }
363 }
364
365 // Additionally, now that the connection was authed, we can take the
366 // permissions off of the gossh.Conn and re-attach them to the Permissions
367 // object stored in the Context.
368 ctx.Permissions().Permissions = sshConn.Permissions
369
370 srv.trackConn(sshConn, true)
371 defer srv.trackConn(sshConn, false)
372
373 ctx.SetValue(ContextKeyConn, sshConn)
374 applyConnMetadata(ctx, sshConn)
375 // go gossh.DiscardRequests(reqs)
376 go srv.handleRequests(ctx, reqs)
377 for ch := range chans {
378 handler := srv.ChannelHandlers[ch.ChannelType()]
379 if handler == nil {
380 handler = srv.ChannelHandlers["default"]
381 }
382 if handler == nil {
383 ch.Reject(gossh.UnknownChannelType, "unsupported channel type")
384 continue
385 }
386 go handler(srv, sshConn, ch, ctx)
387 }
388}
389
390func (srv *Server) handleRequests(ctx Context, in <-chan *gossh.Request) {
391 for req := range in {
392 handler := srv.RequestHandlers[req.Type]
393 if handler == nil {
394 handler = srv.RequestHandlers["default"]
395 }
396 if handler == nil {
397 req.Reply(false, nil)
398 continue
399 }
400 /*reqCtx, cancel := context.WithCancel(ctx)
401 defer cancel() */
402 ret, payload := handler(ctx, srv, req)
403 req.Reply(ret, payload)
404 }
405}
406
407// ListenAndServe listens on the TCP network address srv.Addr and then calls
408// Serve to handle incoming connections. If srv.Addr is blank, ":22" is used.
409// ListenAndServe always returns a non-nil error.
410func (srv *Server) ListenAndServe() error {
411 addr := srv.Addr
412 if addr == "" {
413 addr = ":22"
414 }
415 ln, err := net.Listen("tcp", addr)
416 if err != nil {
417 return err
418 }
419 return srv.Serve(ln)
420}
421
422// AddHostKey adds a private key as a host key. If an existing host key exists
423// with the same algorithm, it is overwritten. Each server config must have at
424// least one host key.
425func (srv *Server) AddHostKey(key Signer) {
426 srv.mu.Lock()
427 defer srv.mu.Unlock()
428
429 // these are later added via AddHostKey on ServerConfig, which performs the
430 // check for one of every algorithm.
431
432 // This check is based on the AddHostKey method from the x/crypto/ssh
433 // library. This allows us to only keep one active key for each type on a
434 // server at once. So, if you're dynamically updating keys at runtime, this
435 // list will not keep growing.
436 for i, k := range srv.HostSigners {
437 if k.PublicKey().Type() == key.PublicKey().Type() {
438 srv.HostSigners[i] = key
439 return
440 }
441 }
442
443 srv.HostSigners = append(srv.HostSigners, key)
444}
445
446// SetOption runs a functional option against the server.
447func (srv *Server) SetOption(option Option) error {
448 // NOTE: there is a potential race here for any option that doesn't call an
449 // internal method. We can't actually lock here because if something calls
450 // (as an example) AddHostKey, it will deadlock.
451
452 // srv.mu.Lock()
453 // defer srv.mu.Unlock()
454
455 return option(srv)
456}
457
458func (srv *Server) getDoneChan() <-chan struct{} {
459 srv.mu.Lock()
460 defer srv.mu.Unlock()
461
462 return srv.getDoneChanLocked()
463}
464
465func (srv *Server) getDoneChanLocked() chan struct{} {
466 if srv.doneChan == nil {
467 srv.doneChan = make(chan struct{})
468 }
469 return srv.doneChan
470}
471
472func (srv *Server) closeDoneChanLocked() {
473 ch := srv.getDoneChanLocked()
474 select {
475 case <-ch:
476 // Already closed. Don't close again.
477 default:
478 // Safe to close here. We're the only closer, guarded
479 // by srv.mu.
480 close(ch)
481 }
482}
483
484func (srv *Server) closeListenersLocked() error {
485 var err error
486 for ln := range srv.listeners {
487 if cerr := ln.Close(); cerr != nil && err == nil {
488 err = cerr
489 }
490 delete(srv.listeners, ln)
491 }
492 return err
493}
494
495func (srv *Server) trackListener(ln net.Listener, add bool) {
496 srv.mu.Lock()
497 defer srv.mu.Unlock()
498
499 if srv.listeners == nil {
500 srv.listeners = make(map[net.Listener]struct{})
501 }
502 if add {
503 // If the *Server is being reused after a previous
504 // Close or Shutdown, reset its doneChan:
505 if len(srv.listeners) == 0 && len(srv.conns) == 0 {
506 srv.doneChan = nil
507 }
508 srv.listeners[ln] = struct{}{}
509 srv.listenerWg.Add(1)
510 } else {
511 delete(srv.listeners, ln)
512 srv.listenerWg.Done()
513 }
514}
515
516func (srv *Server) trackConn(c *gossh.ServerConn, add bool) {
517 srv.mu.Lock()
518 defer srv.mu.Unlock()
519
520 if srv.conns == nil {
521 srv.conns = make(map[*gossh.ServerConn]struct{})
522 }
523 if add {
524 srv.conns[c] = struct{}{}
525 srv.connWg.Add(1)
526 } else {
527 delete(srv.conns, c)
528 srv.connWg.Done()
529 }
530}