Files
netbird/client/ssh/server.go
2022-06-05 13:08:11 +02:00

85 lines
1.7 KiB
Go

package ssh
import (
"fmt"
"github.com/gliderlabs/ssh"
gossh "golang.org/x/crypto/ssh"
"io"
"net"
"strings"
"sync"
)
type Server struct {
listener net.Listener
allowedKeys map[string]ssh.PublicKey
mu sync.Mutex
hostKeyPEM []byte
}
// NewSSHServer creates new server with provided host key
func NewSSHServer(hostKeyPEM []byte) (*Server, error) {
ln, err := net.Listen("tcp", ":2222")
if err != nil {
return nil, err
}
return &Server{listener: ln, mu: sync.Mutex{}, hostKeyPEM: hostKeyPEM}, nil
}
func (srv *Server) UpdateKeys(newKeys []string) error {
srv.mu.Lock()
defer srv.mu.Unlock()
srv.allowedKeys = make(map[string]ssh.PublicKey, len(newKeys))
for _, strKey := range newKeys {
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(strKey))
if err != nil {
return err
}
srv.allowedKeys[strKey] = parsedKey
}
return nil
}
// Stop stops SSH server. Blocking
func (srv *Server) Stop() error {
err := srv.listener.Close()
if err != nil {
return err
}
return nil
}
// Start starts SSH server. Blocking
func (srv *Server) Start() error {
handler := func(s ssh.Session) {
authorizedKey := gossh.MarshalAuthorizedKey(s.PublicKey())
io.WriteString(s, fmt.Sprintf("public key used by %s:\n", s.User()))
s.Write(authorizedKey)
}
publicKeyOption := ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
srv.mu.Lock()
defer srv.mu.Unlock()
k := strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))
if allowed, ok := srv.allowedKeys[k]; ok {
if ssh.KeysEqual(allowed, key) {
return true
}
}
return false
})
hostKeyPEM := ssh.HostKeyPEM(srv.hostKeyPEM)
err := ssh.Serve(srv.listener, handler, publicKeyOption, hostKeyPEM)
if err != nil {
return err
}
return nil
}