glider-ssh/ssh.go

128 lines
4.0 KiB
Go
Raw Permalink Normal View History

2021-11-19 01:07:30 +00:00
package glider_ssh
2016-10-03 21:54:17 +00:00
import (
"crypto/subtle"
"net"
gossh "golang.org/x/crypto/ssh"
2016-10-03 21:54:17 +00:00
)
type Signal string
// POSIX signals as listed in RFC 4254 Section 6.10.
const (
SIGABRT Signal = "ABRT"
SIGALRM Signal = "ALRM"
SIGFPE Signal = "FPE"
SIGHUP Signal = "HUP"
SIGILL Signal = "ILL"
SIGINT Signal = "INT"
SIGKILL Signal = "KILL"
SIGPIPE Signal = "PIPE"
SIGQUIT Signal = "QUIT"
SIGSEGV Signal = "SEGV"
SIGTERM Signal = "TERM"
SIGUSR1 Signal = "USR1"
SIGUSR2 Signal = "USR2"
)
// DefaultHandler is the default Handler used by Serve.
var DefaultHandler Handler
2016-10-03 21:54:17 +00:00
// Option is a functional option handler for Server.
2016-10-03 21:54:17 +00:00
type Option func(*Server) error
// Handler is a callback for handling established SSH sessions.
2016-10-03 21:54:17 +00:00
type Handler func(Session)
// PublicKeyHandler is a callback for performing public key authentication.
type PublicKeyHandler func(ctx Context, key PublicKey) bool
// PasswordHandler is a callback for performing password authentication.
type PasswordHandler func(ctx Context, password string) bool
// KeyboardInteractiveHandler is a callback for performing keyboard-interactive authentication.
type KeyboardInteractiveHandler func(ctx Context, challenger gossh.KeyboardInteractiveChallenge) bool
// PtyCallback is a hook for allowing PTY sessions.
type PtyCallback func(ctx Context, pty Pty) bool
2016-10-03 21:54:17 +00:00
// SessionRequestCallback is a callback for allowing or denying SSH sessions.
type SessionRequestCallback func(sess Session, requestType string) bool
// ConnCallback is a hook for new connections before handling.
// It allows wrapping for timeouts and limiting by returning
// the net.Conn that will be used as the underlying connection.
2019-10-08 21:39:01 +00:00
type ConnCallback func(ctx Context, conn net.Conn) net.Conn
// LocalPortForwardingCallback is a hook for allowing port forwarding
type LocalPortForwardingCallback func(ctx Context, destinationHost string, destinationPort uint32) bool
Remote forwarding (#88) * context: fixed documentation to be more specific about ContextKeyConn being the key for a gossh.ServerConn Signed-off-by: Jeff Lindsay <progrium@gmail.com> * server: fixes handler setup, changed to interface based handlers, added global request handler map * tcpip: working remote forwarding Signed-off-by: Jeff Lindsay <progrium@gmail.com> * context: docs typo Signed-off-by: Jeff Lindsay <progrium@gmail.com> * session: always reply to unblock clients trying something Signed-off-by: Jeff Lindsay <progrium@gmail.com> * tcpip: stop listening when ssh clients disconnect Signed-off-by: Jeff Lindsay <progrium@gmail.com> * Remote forwarding (#87) * Update generateSigner key size to 2048 (#62) Fixes #58 * Add syntax highlighting to readme (#67) * small api updates (#69) These updates make it easier to implement and pass custom Session and Context implementations No compatibilty breaking, all tests pass * Move channelHandlers to avoid data race (#59) * Update tests to work with go 1.10+ (#73) Fixes #72 * Update shutdown to use a WaitGroup rather than sleeping (#74) * Fix race condition in TestServerClose (#75) In test server close, 3 things need to happen in order: - Client session start - Server.Close - Client session exit (With io.EOF) This fix ensures the client won't do anything until after the call to close which ensure's we'll get io.EOF rather than a different error. * Update circleci config to test multiple go versions * Update CircleCI config to test 1.9 and the latest The x/crypto/ssh library dropped support go < 1.9 as that's the first version to have the math/bits library. https://github.com/golang/crypto/commit/83c378c48d6ee2ca9c20551b599aa74cb7765785 * Wait for connections to finish when shutting down PR #74 introduced a WaitGroup for listeners, but it doesn't wait for open connections before closing the server. This patch waits until all conns are closed before returning from Shutdown. * Support port forwarding of literal IPv6 addresses (#85) * Support port forwarding of literal IPv6 addresses To disambiguate between colons as host:port separators and as IPv6 address separators, literal IPv6 addresses use square brackets around the address (https://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers). So host ::1, port 22 is written as [::1]:22, and therefore a simple concatenation of host, colon, and port doesn't work. Fortunately net.JoinHostPort already implements this functionality, so with a bit of type gymnastics we can generate dest in an IPv6-safe way. * Support port forwarding of literal IPv6 addresses To disambiguate between colons as host:port separators and as IPv6 address separators, literal IPv6 addresses use square brackets around the address (https://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers). So host ::1, port 22 is written as [::1]:22, and therefore a simple concatenation of host, colon, and port doesn't work. Fortunately net.JoinHostPort already implements this functionality, so with a bit of type gymnastics we can generate dest in an IPv6-safe way. * Reverse port forwarding callback added * garbage removed
2018-11-13 16:04:02 +00:00
// ReversePortForwardingCallback is a hook for allowing reverse port forwarding
type ReversePortForwardingCallback func(ctx Context, bindHost string, bindPort uint32) bool
// ServerConfigCallback is a hook for creating custom default server configs
type ServerConfigCallback func(ctx Context) *gossh.ServerConfig
// ConnectionFailedCallback is a hook for reporting failed connections
// Please note: the net.Conn is likely to be closed at this point
type ConnectionFailedCallback func(conn net.Conn, err error)
// Window represents the size of a PTY window.
2016-10-03 21:54:17 +00:00
type Window struct {
Width int
Height int
}
// Pty represents a PTY request and configuration.
2016-10-03 21:54:17 +00:00
type Pty struct {
Term string
2016-10-03 21:54:17 +00:00
Window Window
// HELP WANTED: terminal modes!
2016-10-03 21:54:17 +00:00
}
// Serve accepts incoming SSH connections on the listener l, creating a new
// connection goroutine for each. The connection goroutines read requests and
// then calls handler to handle sessions. Handler is typically nil, in which
// case the DefaultHandler is used.
2021-11-19 00:05:48 +00:00
func Serve(l net.Listener, handler Handler, options ...Option) (*Server, error) {
2016-10-03 21:54:17 +00:00
srv := &Server{Handler: handler}
for _, option := range options {
if err := srv.SetOption(option); err != nil {
2021-11-19 00:05:48 +00:00
return nil, err
2016-10-03 21:54:17 +00:00
}
}
2021-11-19 00:05:48 +00:00
return srv, srv.Serve(l)
2016-10-03 21:54:17 +00:00
}
// ListenAndServe listens on the TCP network address addr and then calls Serve
// with handler to handle sessions on incoming connections. Handler is typically
// nil, in which case the DefaultHandler is used.
2021-11-19 02:07:07 +00:00
func ListenAndServe(addr string, handler Handler, options ...Option) (*Server, error) {
2016-10-03 21:54:17 +00:00
srv := &Server{Addr: addr, Handler: handler}
for _, option := range options {
if err := srv.SetOption(option); err != nil {
2021-11-19 02:07:07 +00:00
return nil, err
2016-10-03 21:54:17 +00:00
}
}
2021-11-19 02:07:07 +00:00
return srv, srv.ListenAndServe()
2016-10-03 21:54:17 +00:00
}
// Handle registers the handler as the DefaultHandler.
2016-10-03 21:54:17 +00:00
func Handle(handler Handler) {
DefaultHandler = handler
2016-10-03 21:54:17 +00:00
}
// KeysEqual is constant time compare of the keys to avoid timing attacks.
2016-10-03 21:54:17 +00:00
func KeysEqual(ak, bk PublicKey) bool {
//avoid panic if one of the keys is nil, return false instead
if ak == nil || bk == nil {
return false
}
a := ak.Marshal()
b := bk.Marshal()
2016-10-03 21:54:17 +00:00
return (len(a) == len(b) && subtle.ConstantTimeCompare(a, b) == 1)
}