add ssh timeout and ip prefix filter
This commit is contained in:
parent
0a9c10666a
commit
f631ac057b
|
@ -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
|
||||||
|
|
4
main.go
4
main.go
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,10 @@ type Config struct {
|
||||||
Secret string `toml:"secret"`
|
Secret string `toml:"secret"`
|
||||||
|
|
||||||
// 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"`
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -14,17 +14,19 @@ 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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})
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue