add ssh timeout and ip prefix filter

This commit is contained in:
Martin/Geno 2018-07-24 15:07:11 +02:00
parent 0a9c10666a
commit f631ac057b
No known key found for this signature in database
GPG Key ID: 9D7D3C6BFF600C6A
10 changed files with 69 additions and 17 deletions

View File

@ -7,6 +7,8 @@ secret = "passw0rd"
ssh_key = "~/.ssh/id_rsa" ssh_key = "~/.ssh/id_rsa"
ssh_interface = "wlp4s0" ssh_interface = "wlp4s0"
ssh_ipaddress_suffix = "fe80:"
ssh_timeout = "1m"
# enable receiving # enable receiving
yanic_enable = true yanic_enable = true

View File

@ -44,13 +44,13 @@ func main() {
log.Info("starting...") log.Info("starting...")
sshmanager := ssh.NewManager(config.SSHPrivateKey) sshmanager := ssh.NewManager(config.SSHPrivateKey, config.SSHTimeout.Duration)
nodes = runtime.NewNodes(config.StatePath, config.SSHInterface, sshmanager) nodes = runtime.NewNodes(config.StatePath, config.SSHInterface, sshmanager)
nodesSaveWorker := worker.NewWorker(time.Duration(3)*time.Second, nodes.Saver) nodesSaveWorker := worker.NewWorker(time.Duration(3)*time.Second, nodes.Saver)
nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater) nodesUpdateWorker := worker.NewWorker(time.Duration(3)*time.Minute, nodes.Updater)
nodesYanic := runtimeYanic.NewNodes(&runtimeYanic.NodesConfig{}) nodesYanic := runtimeYanic.NewNodes(&runtimeYanic.NodesConfig{})
db := runtime.NewYanicDB(nodes) db := runtime.NewYanicDB(nodes, config.SSHIPAddressSuffix)
go nodesSaveWorker.Start() go nodesSaveWorker.Start()
go nodesUpdateWorker.Start() go nodesUpdateWorker.Start()

View File

@ -22,6 +22,8 @@ type Config struct {
// SSH private key // SSH private key
SSHPrivateKey string `toml:"ssh_key"` SSHPrivateKey string `toml:"ssh_key"`
SSHInterface string `toml:"ssh_interface"` SSHInterface string `toml:"ssh_interface"`
SSHIPAddressSuffix string `toml:"ssh_ipaddress_suffix"`
SSHTimeout duration.Duration `toml:"ssh_timeout"`
// yanic socket // yanic socket
YanicEnable bool `toml:"yanic_enable"` YanicEnable bool `toml:"yanic_enable"`

View File

@ -3,6 +3,7 @@ package runtime
import ( import (
"bytes" "bytes"
"net" "net"
"strings"
yanicData "github.com/FreifunkBremen/yanic/data" yanicData "github.com/FreifunkBremen/yanic/data"
"github.com/FreifunkBremen/yanic/lib/jsontime" "github.com/FreifunkBremen/yanic/lib/jsontime"
@ -23,13 +24,16 @@ type Node struct {
} `json:"statistics" mapstructure:"-"` } `json:"statistics" mapstructure:"-"`
} }
func NewNode(nodeOrigin *yanicRuntime.Node) *Node { func NewNode(nodeOrigin *yanicRuntime.Node, ipPrefix string) *Node {
if nodeinfo := nodeOrigin.Nodeinfo; nodeinfo != nil { if nodeinfo := nodeOrigin.Nodeinfo; nodeinfo != nil {
node := &Node{ node := &Node{
Hostname: nodeinfo.Hostname, Hostname: nodeinfo.Hostname,
NodeID: nodeinfo.NodeID, NodeID: nodeinfo.NodeID,
} }
for _, ip := range nodeinfo.Network.Addresses { for _, ip := range nodeinfo.Network.Addresses {
if !strings.HasPrefix(ip, ipPrefix) {
continue
}
ipAddr := net.ParseIP(ip) ipAddr := net.ParseIP(ip)
if node.Address == nil || ipAddr.IsGlobalUnicast() { if node.Address == nil || ipAddr.IsGlobalUnicast() {
node.Address = ipAddr node.Address = ipAddr

View File

@ -15,7 +15,7 @@ func TestNode(t *testing.T) {
node1 := &yanicRuntime.Node{ node1 := &yanicRuntime.Node{
Address: &net.UDPAddr{IP: net.ParseIP("ff02::1")}, Address: &net.UDPAddr{IP: net.ParseIP("ff02::1")},
} }
n1 := NewNode(node1) n1 := NewNode(node1, "")
assert.Nil(n1) assert.Nil(n1)
node1.Nodeinfo = &yanicData.NodeInfo{ node1.Nodeinfo = &yanicData.NodeInfo{
@ -23,11 +23,11 @@ func TestNode(t *testing.T) {
Wireless: &yanicData.Wireless{}, Wireless: &yanicData.Wireless{},
Location: &yanicData.Location{Altitude: 13}, Location: &yanicData.Location{Altitude: 13},
} }
n1 = NewNode(node1) n1 = NewNode(node1, "")
assert.NotNil(n1) assert.NotNil(n1)
assert.Equal(float64(13), n1.Location.Altitude) assert.Equal(float64(13), n1.Location.Altitude)
n2 := NewNode(node1) n2 := NewNode(node1, "")
assert.True(n2.IsEqual(n1)) assert.True(n2.IsEqual(n1))
node1.Nodeinfo.Owner.Contact = "blub2" node1.Nodeinfo.Owner.Contact = "blub2"

View File

@ -15,16 +15,18 @@ import (
type YanicDB struct { type YanicDB struct {
databaseYanic.Connection databaseYanic.Connection
nodes *Nodes nodes *Nodes
prefix string
} }
func NewYanicDB(nodes *Nodes) *YanicDB { func NewYanicDB(nodes *Nodes, prefix string) *YanicDB {
return &YanicDB{ return &YanicDB{
nodes: nodes, nodes: nodes,
prefix: prefix,
} }
} }
func (conn *YanicDB) InsertNode(n *runtimeYanic.Node) { func (conn *YanicDB) InsertNode(n *runtimeYanic.Node) {
node := NewNode(n) node := NewNode(n, conn.prefix)
if node == nil { if node == nil {
return return
} }

View File

@ -3,6 +3,7 @@ package ssh
import ( import (
"net" "net"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -12,7 +13,7 @@ func TestExecute(t *testing.T) {
addr := net.TCPAddr{IP: net.ParseIP("fd2f:5119:f2c::127"), Port: 22} addr := net.TCPAddr{IP: net.ParseIP("fd2f:5119:f2c::127"), Port: 22}
mgmt := NewManager("~/.ssh/id_rsa") mgmt := NewManager("~/.ssh/id_rsa", time.Second)
assert.NotNil(mgmt, "no new manager created") assert.NotNil(mgmt, "no new manager created")
client, err := mgmt.ConnectTo(addr) client, err := mgmt.ConnectTo(addr)

View File

@ -16,10 +16,11 @@ type Manager struct {
config *ssh.ClientConfig config *ssh.ClientConfig
clientsBlacklist map[string]time.Time clientsBlacklist map[string]time.Time
clientsMUX sync.Mutex clientsMUX sync.Mutex
timeout time.Duration
} }
// create a new SSH Connection Manager by ssh file // create a new SSH Connection Manager by ssh file
func NewManager(file string) *Manager { func NewManager(file string, timeout time.Duration) *Manager {
var auths []ssh.AuthMethod var auths []ssh.AuthMethod
if auth := SSHAgent(); auth != nil { if auth := SSHAgent(); auth != nil {
auths = append(auths, auth) auths = append(auths, auth)
@ -36,9 +37,34 @@ func NewManager(file string) *Manager {
return &Manager{ return &Manager{
config: sshConfig, config: sshConfig,
clientsBlacklist: make(map[string]time.Time), clientsBlacklist: make(map[string]time.Time),
timeout: timeout,
} }
} }
// 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) { func (m *Manager) ConnectTo(addr net.TCPAddr) (*ssh.Client, error) {
m.clientsMUX.Lock() m.clientsMUX.Lock()
defer m.clientsMUX.Unlock() defer m.clientsMUX.Unlock()
@ -50,7 +76,20 @@ func (m *Manager) ConnectTo(addr net.TCPAddr) (*ssh.Client, error) {
} }
} }
client, err := ssh.Dial("tcp", addr.String(), m.config) 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)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "no supported methods remain") { if strings.Contains(err.Error(), "no supported methods remain") {
m.clientsBlacklist[addr.IP.String()] = time.Now() m.clientsBlacklist[addr.IP.String()] = time.Now()

View File

@ -3,6 +3,7 @@ package ssh
import ( import (
"net" "net"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -10,7 +11,7 @@ import (
func TestManager(t *testing.T) { func TestManager(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
mgmt := NewManager("~/.ssh/id_rsa") mgmt := NewManager("~/.ssh/id_rsa", time.Second)
assert.NotNil(mgmt, "no new manager created") assert.NotNil(mgmt, "no new manager created")
client, _ := mgmt.ConnectTo(net.TCPAddr{IP: net.ParseIP("fd2f:5119:f2c::127"), Port: 22}) client, _ := mgmt.ConnectTo(net.TCPAddr{IP: net.ParseIP("fd2f:5119:f2c::127"), Port: 22})

View File

@ -4,6 +4,7 @@ import (
"net" "net"
"strconv" "strconv"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -11,7 +12,7 @@ import (
func TestRun(t *testing.T) { func TestRun(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
addr := net.TCPAddr{IP: net.ParseIP("fd2f:5119:f2c::127"), Port: 22} addr := net.TCPAddr{IP: net.ParseIP("fd2f:5119:f2c::127"), Port: 22}
mgmt := NewManager("~/.ssh/id_rsa") mgmt := NewManager("~/.ssh/id_rsa", time.Second)
assert.NotNil(mgmt, "no new manager created") assert.NotNil(mgmt, "no new manager created")
client, err := mgmt.ConnectTo(addr) client, err := mgmt.ConnectTo(addr)