glider-ssh/ssh.go
Jeff Lindsay cbabf54144
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.

83c378c48d

* 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 10:04:02 -06:00

113 lines
3.2 KiB
Go

package ssh
import (
"crypto/subtle"
"net"
)
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
// Option is a functional option handler for Server.
type Option func(*Server) error
// Handler is a callback for handling established SSH sessions.
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
// PtyCallback is a hook for allowing PTY sessions.
type PtyCallback func(ctx Context, pty Pty) 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.
type ConnCallback func(conn net.Conn) net.Conn
// LocalPortForwardingCallback is a hook for allowing port forwarding
type LocalPortForwardingCallback func(ctx Context, destinationHost string, destinationPort uint32) bool
// ReversePortForwardingCallback is a hook for allowing reverse port forwarding
type ReversePortForwardingCallback func(ctx Context, bindHost string, bindPort uint32) bool
// Window represents the size of a PTY window.
type Window struct {
Width int
Height int
}
// Pty represents a PTY request and configuration.
type Pty struct {
Term string
Window Window
// HELP WANTED: terminal modes!
}
// 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.
func Serve(l net.Listener, handler Handler, options ...Option) error {
srv := &Server{Handler: handler}
for _, option := range options {
if err := srv.SetOption(option); err != nil {
return err
}
}
return srv.Serve(l)
}
// 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.
func ListenAndServe(addr string, handler Handler, options ...Option) error {
srv := &Server{Addr: addr, Handler: handler}
for _, option := range options {
if err := srv.SetOption(option); err != nil {
return err
}
}
return srv.ListenAndServe()
}
// Handle registers the handler as the DefaultHandler.
func Handle(handler Handler) {
DefaultHandler = handler
}
// KeysEqual is constant time compare of the keys to avoid timing attacks.
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()
return (len(a) == len(b) && subtle.ConstantTimeCompare(a, b) == 1)
}