Add per-node ping monitoring with unreachable error tracking
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
89
ping.go
Normal file
89
ping.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package tendrils
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
func (t *Tendrils) pingNode(node *Node) {
|
||||
t.nodes.mu.RLock()
|
||||
var ips []string
|
||||
for _, iface := range node.Interfaces {
|
||||
for ipStr := range iface.IPs {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip != nil && ip.To4() != nil {
|
||||
ips = append(ips, ipStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.nodes.mu.RUnlock()
|
||||
|
||||
if len(ips) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, ipStr := range ips {
|
||||
reachable := t.pingIP(ipStr)
|
||||
if reachable {
|
||||
t.errors.ClearUnreachable(node, ipStr)
|
||||
} else {
|
||||
t.errors.SetUnreachable(node, ipStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tendrils) pingIP(ipStr string) bool {
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(500 * time.Millisecond))
|
||||
|
||||
ip := net.ParseIP(ipStr)
|
||||
seq := uint16(time.Now().UnixNano() & 0xFFFF)
|
||||
|
||||
msg := icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: int(seq),
|
||||
Seq: 1,
|
||||
Data: []byte("tendrils"),
|
||||
},
|
||||
}
|
||||
msgBytes, err := msg.Marshal(nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, err = conn.WriteTo(msgBytes, &net.IPAddr{IP: ip})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
buf := make([]byte, 1500)
|
||||
for {
|
||||
n, peer, err := conn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
parsed, err := icmp.ParseMessage(1, buf[:n])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if parsed.Type == ipv4.ICMPTypeEchoReply {
|
||||
if ipAddr, ok := peer.(*net.IPAddr); ok {
|
||||
if ipAddr.IP.String() == ipStr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user