Files
brianmcgee debe729050
buildbot/nix-eval Build done.
buildbot/nix-build Build done.
feat: distinguish between advertised and reachable ip addresses
- introduces `NodeMeta` to `memberlist` gossip messages so we can see all the IP addresses a node is listening on and not just its advertised address.
- introduces an `AddressBook` to map between advertised IP addresses and reachable IP addresses based on a peer's bind addresses and the local network interfaces a node is bound to.
- introduces an `Alive` delegate to filter unreachable nodes from `memberlist`

All this is to support multi-clan scenarios where only a subset of bridge nodes share a common network interface (VPN) with other clans.
2026-02-04 14:37:11 +00:00

78 lines
1.7 KiB
Go

// Package msgpack provides msgpack encoding/decoding with deterministic output.
package msgpack
import (
"fmt"
"io"
"net"
"reflect"
"github.com/hashicorp/go-msgpack/v2/codec"
)
var handle = &codec.MsgpackHandle{
WriteExt: true,
}
// netIPExt implements codec.BytesExt for net.IP encoding/decoding.
type netIPExt struct{}
func (netIPExt) WriteExt(v any) []byte {
ip, ok := v.(net.IP)
if !ok {
panic(fmt.Sprintf("expected net.IP, received %T", v))
}
return ip
}
func (netIPExt) ReadExt(dst any, src []byte) {
ip, ok := dst.(*net.IP)
if !ok {
panic(fmt.Sprintf("expected *net.IP, received %T", dst))
}
*ip = make(net.IP, len(src))
copy(*ip, src)
}
func init() {
handle.Canonical = true
if err := handle.SetBytesExt(reflect.TypeFor[net.IP](), 1, netIPExt{}); err != nil {
panic(fmt.Sprintf("failed to register msgpack handler for net.IP: %s", err))
}
}
// NewDecoder creates a new Decoder instance for decoding data from the provided io.Reader.
func NewDecoder(r io.Reader) *codec.Decoder {
return codec.NewDecoder(r, handle)
}
// NewEncoder creates a new Encoder instance for encoding data to the provided io.Writer.
func NewEncoder(w io.Writer) *codec.Encoder {
return codec.NewEncoder(w, handle)
}
// Marshal encodes v to msgpack with canonical (deterministic) encoding.
func Marshal(v any) ([]byte, error) {
var buf []byte
enc := codec.NewEncoderBytes(&buf, handle)
if err := enc.Encode(v); err != nil {
return nil, fmt.Errorf("msgpack marshal: %w", err)
}
return buf, nil
}
// Unmarshal decodes msgpack data into v.
func Unmarshal(data []byte, v any) error {
dec := codec.NewDecoderBytes(data, handle)
if err := dec.Decode(v); err != nil {
return fmt.Errorf("msgpack unmarshal: %w", err)
}
return nil
}