Add NodeInfo field to PeerEntry and PeerInfo structures, and update related handlers to include NodeInfo in peer data retrieval and handshake processes.

This commit is contained in:
Andy Oknen 2025-08-15 15:17:49 +00:00
parent c0a9bc802a
commit 1f8f36860f
4 changed files with 63 additions and 3 deletions

View file

@ -33,6 +33,7 @@ type PeerEntry struct {
Latency time.Duration `json:"latency,omitempty"` Latency time.Duration `json:"latency,omitempty"`
LastErrorTime time.Duration `json:"last_error_time,omitempty"` LastErrorTime time.Duration `json:"last_error_time,omitempty"`
LastError string `json:"last_error,omitempty"` LastError string `json:"last_error,omitempty"`
NodeInfo string `json:"nodeinfo,omitempty"` // NodeInfo from peer handshake
} }
func (a *AdminSocket) getPeersHandler(_ *GetPeersRequest, res *GetPeersResponse) error { func (a *AdminSocket) getPeersHandler(_ *GetPeersRequest, res *GetPeersResponse) error {
@ -63,6 +64,11 @@ func (a *AdminSocket) getPeersHandler(_ *GetPeersRequest, res *GetPeersResponse)
peer.LastError = p.LastError.Error() peer.LastError = p.LastError.Error()
peer.LastErrorTime = time.Since(p.LastErrorTime) peer.LastErrorTime = time.Since(p.LastErrorTime)
} }
// Add NodeInfo if available
if len(p.NodeInfo) > 0 {
peer.NodeInfo = string(p.NodeInfo)
}
res.Peers = append(res.Peers, peer) res.Peers = append(res.Peers, peer)
} }

View file

@ -37,6 +37,7 @@ type PeerInfo struct {
TXRate uint64 TXRate uint64
Uptime time.Duration Uptime time.Duration
Latency time.Duration Latency time.Duration
NodeInfo []byte // NodeInfo received during handshake
} }
type TreeEntryInfo struct { type TreeEntryInfo struct {
@ -92,6 +93,11 @@ func (c *Core) GetPeers() []PeerInfo {
peerinfo.RXRate = atomic.LoadUint64(&c.rxrate) peerinfo.RXRate = atomic.LoadUint64(&c.rxrate)
peerinfo.TXRate = atomic.LoadUint64(&c.txrate) peerinfo.TXRate = atomic.LoadUint64(&c.txrate)
peerinfo.Uptime = time.Since(c.up) peerinfo.Uptime = time.Since(c.up)
// Add NodeInfo from handshake
if len(state._nodeInfo) > 0 {
peerinfo.NodeInfo = make([]byte, len(state._nodeInfo))
copy(peerinfo.NodeInfo, state._nodeInfo)
}
} }
if p, ok := conns[conn]; ok { if p, ok := conns[conn]; ok {
peerinfo.Key = p.Key peerinfo.Key = p.Key

View file

@ -64,9 +64,10 @@ type link struct {
linkType linkType // Type of link, i.e. outbound/inbound, persistent/ephemeral linkType linkType // Type of link, i.e. outbound/inbound, persistent/ephemeral
linkProto string // Protocol carrier of link, e.g. TCP, AWDL linkProto string // Protocol carrier of link, e.g. TCP, AWDL
// The remaining fields can only be modified safely from within the links actor // The remaining fields can only be modified safely from within the links actor
_conn *linkConn // Connected link, if any, nil if not connected _conn *linkConn // Connected link, if any, nil if not connected
_err error // Last error on the connection, if any _err error // Last error on the connection, if any
_errtime time.Time // Last time an error occurred _errtime time.Time // Last time an error occurred
_nodeInfo []byte // NodeInfo received from peer during handshake
} }
type linkOptions struct { type linkOptions struct {
@ -246,6 +247,7 @@ func (l *links) add(u *url.URL, sintf string, linkType linkType) error {
linkType: linkType, linkType: linkType,
linkProto: strings.ToUpper(u.Scheme), linkProto: strings.ToUpper(u.Scheme),
kick: make(chan struct{}), kick: make(chan struct{}),
_nodeInfo: nil, // Initialize NodeInfo field
} }
state.ctx, state.cancel = context.WithCancel(l.core.ctx) state.ctx, state.cancel = context.WithCancel(l.core.ctx)
@ -524,6 +526,7 @@ func (l *links) listen(u *url.URL, sintf string, local bool) (*Listener, error)
linkType: linkTypeIncoming, linkType: linkTypeIncoming,
linkProto: strings.ToUpper(u.Scheme), linkProto: strings.ToUpper(u.Scheme),
kick: make(chan struct{}), kick: make(chan struct{}),
_nodeInfo: nil, // Initialize NodeInfo field
} }
} }
if state._conn != nil { if state._conn != nil {
@ -605,6 +608,16 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
meta := version_getBaseMetadata() meta := version_getBaseMetadata()
meta.publicKey = l.core.public meta.publicKey = l.core.public
meta.priority = options.priority meta.priority = options.priority
// Add our NodeInfo to handshake if available
phony.Block(&l.core.proto.nodeinfo, func() {
nodeInfo := l.core.proto.nodeinfo._getNodeInfo()
if len(nodeInfo) > 0 {
meta.nodeInfo = make([]byte, len(nodeInfo))
copy(meta.nodeInfo, nodeInfo)
}
})
metaBytes, err := meta.encode(l.core.secret, options.password) metaBytes, err := meta.encode(l.core.secret, options.password)
if err != nil { if err != nil {
return fmt.Errorf("failed to generate handshake: %w", err) return fmt.Errorf("failed to generate handshake: %w", err)
@ -661,6 +674,20 @@ func (l *links) handler(linkType linkType, options linkOptions, conn net.Conn, s
} }
} }
// Store the received NodeInfo in the link state
if len(meta.nodeInfo) > 0 {
phony.Block(l, func() {
// Find the link state for this connection
for _, state := range l._links {
if state._conn != nil && state._conn.Conn == conn {
state._nodeInfo = make([]byte, len(meta.nodeInfo))
copy(state._nodeInfo, meta.nodeInfo)
break
}
}
})
}
dir := "outbound" dir := "outbound"
if linkType == linkTypeIncoming { if linkType == linkTypeIncoming {
dir = "inbound" dir = "inbound"

View file

@ -8,6 +8,7 @@ import (
"bytes" "bytes"
"crypto/ed25519" "crypto/ed25519"
"encoding/binary" "encoding/binary"
"fmt"
"io" "io"
"golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2b"
@ -21,6 +22,7 @@ type version_metadata struct {
minorVer uint16 minorVer uint16
publicKey ed25519.PublicKey publicKey ed25519.PublicKey
priority uint8 priority uint8
nodeInfo []byte // NodeInfo data from configuration
} }
const ( const (
@ -35,6 +37,7 @@ const (
metaVersionMinor // uint16 metaVersionMinor // uint16
metaPublicKey // [32]byte metaPublicKey // [32]byte
metaPriority // uint8 metaPriority // uint8
metaNodeInfo // []byte
) )
type handshakeError string type handshakeError string
@ -52,6 +55,7 @@ func version_getBaseMetadata() version_metadata {
return version_metadata{ return version_metadata{
majorVer: ProtocolVersionMajor, majorVer: ProtocolVersionMajor,
minorVer: ProtocolVersionMinor, minorVer: ProtocolVersionMinor,
nodeInfo: nil, // Will be set during handshake
} }
} }
@ -77,6 +81,16 @@ func (m *version_metadata) encode(privateKey ed25519.PrivateKey, password []byte
bs = binary.BigEndian.AppendUint16(bs, 1) bs = binary.BigEndian.AppendUint16(bs, 1)
bs = append(bs, m.priority) bs = append(bs, m.priority)
// Add NodeInfo if available (with size validation)
if len(m.nodeInfo) > 0 {
if len(m.nodeInfo) > 16384 {
return nil, fmt.Errorf("NodeInfo exceeds max length of 16384 bytes")
}
bs = binary.BigEndian.AppendUint16(bs, metaNodeInfo)
bs = binary.BigEndian.AppendUint16(bs, uint16(len(m.nodeInfo)))
bs = append(bs, m.nodeInfo...)
}
hasher, err := blake2b.New512(password) hasher, err := blake2b.New512(password)
if err != nil { if err != nil {
return nil, err return nil, err
@ -135,6 +149,13 @@ func (m *version_metadata) decode(r io.Reader, password []byte) error {
case metaPriority: case metaPriority:
m.priority = bs[0] m.priority = bs[0]
case metaNodeInfo:
if oplen > 16384 {
return fmt.Errorf("received NodeInfo exceeds max length of 16384 bytes")
}
m.nodeInfo = make([]byte, oplen)
copy(m.nodeInfo, bs[:oplen])
} }
bs = bs[oplen:] bs = bs[oplen:]
} }