freifunkmanager/ssh/manager.go

104 lines
2.3 KiB
Go
Raw Normal View History

2017-05-06 14:37:24 +02:00
package ssh
import (
"errors"
2017-05-06 14:37:24 +02:00
"net"
2017-05-14 10:04:45 +02:00
"strings"
2017-05-06 14:37:24 +02:00
"sync"
2017-05-14 10:04:45 +02:00
"time"
2017-05-06 14:37:24 +02:00
2018-06-30 01:45:51 +02:00
log "github.com/sirupsen/logrus"
2017-05-06 14:37:24 +02:00
"golang.org/x/crypto/ssh"
)
// the SSH Connection Manager for multiple connections
type Manager struct {
2017-05-14 10:04:45 +02:00
config *ssh.ClientConfig
clientsBlacklist map[string]time.Time
clientsMUX sync.Mutex
2018-07-24 15:07:11 +02:00
timeout time.Duration
2017-05-06 14:37:24 +02:00
}
// create a new SSH Connection Manager by ssh file
2018-07-24 15:07:11 +02:00
func NewManager(file string, timeout time.Duration) *Manager {
2017-05-06 14:37:24 +02:00
var auths []ssh.AuthMethod
if auth := SSHAgent(); auth != nil {
auths = append(auths, auth)
}
if auth := PublicKeyFile(file); auth != nil {
auths = append(auths, auth)
}
sshConfig := &ssh.ClientConfig{
User: "root",
Auth: auths,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
return &Manager{
2017-05-14 10:04:45 +02:00
config: sshConfig,
clientsBlacklist: make(map[string]time.Time),
2018-07-24 15:07:11 +02:00
timeout: timeout,
2017-05-06 14:37:24 +02:00
}
}
2018-07-24 15:07:11 +02:00
// Conn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type Conn struct {
net.Conn
ReadTimeout time.Duration
WriteTimeout time.Duration
}
func (c *Conn) Read(b []byte) (int, error) {
err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
if err != nil {
return 0, err
}
return c.Conn.Read(b)
}
func (c *Conn) Write(b []byte) (int, error) {
err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
if err != nil {
return 0, err
}
return c.Conn.Write(b)
}
func (m *Manager) ConnectTo(addr net.TCPAddr) (*ssh.Client, error) {
2017-05-06 14:37:24 +02:00
m.clientsMUX.Lock()
defer m.clientsMUX.Unlock()
2017-05-14 10:04:45 +02:00
if t, ok := m.clientsBlacklist[addr.IP.String()]; ok {
2017-05-16 00:22:15 +02:00
if time.Now().Add(-time.Hour * 24).Before(t) {
return nil, errors.New("node on blacklist")
2017-05-14 10:04:45 +02:00
} else {
delete(m.clientsBlacklist, addr.IP.String())
}
}
2017-05-06 14:37:24 +02:00
2018-07-24 15:07:11 +02:00
addrString := addr.String()
conn, err := net.DialTimeout("tcp", addrString, m.timeout)
if err != nil {
return nil, err
}
timeoutConn := &Conn{conn, m.timeout, m.timeout}
c, chans, reqs, err := ssh.NewClientConn(timeoutConn, addrString, m.config)
if err != nil {
return nil, err
}
client := ssh.NewClient(c, chans, reqs)
2017-05-06 14:37:24 +02:00
if err != nil {
2017-05-14 10:04:45 +02:00
if strings.Contains(err.Error(), "no supported methods remain") {
m.clientsBlacklist[addr.IP.String()] = time.Now()
2018-06-30 01:45:51 +02:00
log.Warnf("node was set on the blacklist: %s", err)
return nil, errors.New("node on blacklist")
2017-05-14 10:04:45 +02:00
}
return nil, err
2017-05-06 14:37:24 +02:00
}
return client, nil
2017-05-06 14:37:24 +02:00
}