2014-12-07 08:31:23 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
2014-12-10 00:51:24 +01:00
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"golang.org/x/crypto/ssh"
|
2014-12-07 08:31:23 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type Server struct {
|
|
|
|
sshConfig *ssh.ServerConfig
|
|
|
|
sshSigner *ssh.Signer
|
|
|
|
done chan struct{}
|
2014-12-10 03:22:46 +01:00
|
|
|
clients map[Client]struct{}
|
2014-12-10 00:51:24 +01:00
|
|
|
lock sync.Mutex
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewServer(privateKey []byte) (*Server, error) {
|
|
|
|
signer, err := ssh.ParsePrivateKey(privateKey)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
config := ssh.ServerConfig{
|
2014-12-10 00:51:24 +01:00
|
|
|
NoClientAuth: false,
|
|
|
|
PasswordCallback: func(conn ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
|
|
|
return nil, nil
|
|
|
|
},
|
|
|
|
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
|
|
|
return nil, nil
|
|
|
|
},
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
config.AddHostKey(signer)
|
|
|
|
|
|
|
|
server := Server{
|
|
|
|
sshConfig: &config,
|
|
|
|
sshSigner: &signer,
|
2014-12-10 00:51:24 +01:00
|
|
|
done: make(chan struct{}),
|
2014-12-10 03:22:46 +01:00
|
|
|
clients: map[Client]struct{}{},
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return &server, nil
|
|
|
|
}
|
|
|
|
|
2014-12-10 02:01:35 +01:00
|
|
|
func (s *Server) Broadcast(msg string, except *Client) {
|
2014-12-10 00:51:24 +01:00
|
|
|
logger.Debugf("Broadcast to %d: %s", len(s.clients), strings.TrimRight(msg, "\r\n"))
|
2014-12-10 03:22:46 +01:00
|
|
|
for client := range s.clients {
|
2014-12-10 02:01:35 +01:00
|
|
|
if except != nil && client == *except {
|
|
|
|
continue
|
|
|
|
}
|
2014-12-10 00:51:24 +01:00
|
|
|
client.Msg <- msg
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:51:24 +01:00
|
|
|
func (s *Server) Start(laddr string) error {
|
2014-12-07 08:31:23 +01:00
|
|
|
// Once a ServerConfig has been configured, connections can be
|
|
|
|
// accepted.
|
|
|
|
socket, err := net.Listen("tcp", laddr)
|
|
|
|
if err != nil {
|
2014-12-10 00:51:24 +01:00
|
|
|
return err
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
logger.Infof("Listening on %s", laddr)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
conn, err := socket.Accept()
|
2014-12-10 00:51:24 +01:00
|
|
|
|
2014-12-07 08:31:23 +01:00
|
|
|
if err != nil {
|
2014-12-10 00:51:24 +01:00
|
|
|
// TODO: Handle shutdown more gracefully?
|
2014-12-07 08:31:23 +01:00
|
|
|
logger.Errorf("Failed to accept connection, aborting loop: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-12-10 00:51:24 +01:00
|
|
|
// Goroutineify to resume accepting sockets early.
|
|
|
|
go func() {
|
|
|
|
// From a standard TCP connection to an encrypted SSH connection
|
|
|
|
sshConn, channels, requests, err := ssh.NewServerConn(conn, s.sshConfig)
|
|
|
|
if err != nil {
|
|
|
|
logger.Errorf("Failed to handshake: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.Infof("Connection from: %s, %s, %s", sshConn.RemoteAddr(), sshConn.User(), sshConn.ClientVersion())
|
|
|
|
|
|
|
|
go ssh.DiscardRequests(requests)
|
|
|
|
|
|
|
|
client := NewClient(s, sshConn.User())
|
|
|
|
// TODO: mutex this
|
2014-12-07 08:31:23 +01:00
|
|
|
|
2014-12-10 00:51:24 +01:00
|
|
|
s.lock.Lock()
|
2014-12-10 03:22:46 +01:00
|
|
|
s.clients[*client] = struct{}{}
|
2014-12-10 02:01:35 +01:00
|
|
|
num := len(s.clients)
|
2014-12-10 00:51:24 +01:00
|
|
|
s.lock.Unlock()
|
2014-12-07 08:31:23 +01:00
|
|
|
|
2014-12-10 02:01:35 +01:00
|
|
|
s.Broadcast(fmt.Sprintf("* Joined: %s (%d present)\r\n", client.Name, num), nil)
|
2014-12-10 00:51:24 +01:00
|
|
|
|
2014-12-10 03:22:46 +01:00
|
|
|
go func() {
|
|
|
|
sshConn.Wait()
|
|
|
|
s.lock.Lock()
|
|
|
|
delete(s.clients, *client)
|
|
|
|
s.lock.Unlock()
|
|
|
|
|
|
|
|
s.Broadcast(fmt.Sprintf("* Left: %s\r\n", client.Name), nil)
|
|
|
|
}()
|
|
|
|
|
2014-12-10 00:51:24 +01:00
|
|
|
go client.handleChannels(channels)
|
|
|
|
}()
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2014-12-10 00:51:24 +01:00
|
|
|
go func() {
|
|
|
|
<-s.done
|
|
|
|
socket.Close()
|
|
|
|
}()
|
|
|
|
|
|
|
|
return nil
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|
|
|
|
|
2014-12-10 00:51:24 +01:00
|
|
|
func (s *Server) Stop() {
|
|
|
|
close(s.done)
|
2014-12-07 08:31:23 +01:00
|
|
|
}
|