Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

View File

@@ -0,0 +1,358 @@
package manet
import (
"errors"
"fmt"
"net"
"path/filepath"
"runtime"
"strings"
ma "github.com/multiformats/go-multiaddr"
)
var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")
var errNotIP = fmt.Errorf("multiaddr does not start with an IP address")
// FromNetAddr converts a net.Addr type to a Multiaddr.
func FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
return defaultCodecs.FromNetAddr(a)
}
// FromNetAddr converts a net.Addr to Multiaddress.
func (cm *CodecMap) FromNetAddr(a net.Addr) (ma.Multiaddr, error) {
if a == nil {
return nil, fmt.Errorf("nil multiaddr")
}
p, err := cm.getAddrParser(a.Network())
if err != nil {
return nil, err
}
return p(a)
}
// ToNetAddr converts a Multiaddr to a net.Addr
// Must be ThinWaist. acceptable protocol stacks are:
// /ip{4,6}/{tcp, udp}
func ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
return defaultCodecs.ToNetAddr(maddr)
}
// ToNetAddr converts a Multiaddress to a standard net.Addr.
func (cm *CodecMap) ToNetAddr(maddr ma.Multiaddr) (net.Addr, error) {
protos := maddr.Protocols()
final := protos[len(protos)-1]
p, err := cm.getMaddrParser(final.Name)
if err != nil {
return nil, err
}
return p(maddr)
}
// MultiaddrToIPNet converts a multiaddr to an IPNet. Useful for seeing if another IP address is contained within this multiaddr network+mask
func MultiaddrToIPNet(m ma.Multiaddr) (*net.IPNet, error) {
var ipString string
var mask string
ma.ForEach(m, func(c ma.Component) bool {
if c.Protocol().Code == ma.P_IP4 || c.Protocol().Code == ma.P_IP6 {
ipString = c.Value()
}
if c.Protocol().Code == ma.P_IPCIDR {
mask = c.Value()
}
return ipString == "" || mask == ""
})
if ipString == "" {
return nil, errors.New("no ip protocol found")
}
if mask == "" {
return nil, errors.New("no mask found")
}
_, ipnet, err := net.ParseCIDR(ipString + "/" + string(mask))
return ipnet, err
}
func parseBasicNetMaddr(maddr ma.Multiaddr) (net.Addr, error) {
network, host, err := DialArgs(maddr)
if err != nil {
return nil, err
}
switch network {
case "tcp", "tcp4", "tcp6":
return net.ResolveTCPAddr(network, host)
case "udp", "udp4", "udp6":
return net.ResolveUDPAddr(network, host)
case "ip", "ip4", "ip6":
return net.ResolveIPAddr(network, host)
case "unix":
return net.ResolveUnixAddr(network, host)
}
return nil, fmt.Errorf("network not supported: %s", network)
}
func FromIPAndZone(ip net.IP, zone string) (ma.Multiaddr, error) {
switch {
case ip.To4() != nil:
return ma.NewComponent("ip4", ip.String())
case ip.To16() != nil:
ip6, err := ma.NewComponent("ip6", ip.String())
if err != nil {
return nil, err
}
if zone == "" {
return ip6, nil
} else {
zone, err := ma.NewComponent("ip6zone", zone)
if err != nil {
return nil, err
}
return zone.Encapsulate(ip6), nil
}
default:
return nil, errIncorrectNetAddr
}
}
// FromIP converts a net.IP type to a Multiaddr.
func FromIP(ip net.IP) (ma.Multiaddr, error) {
return FromIPAndZone(ip, "")
}
// ToIP converts a Multiaddr to a net.IP when possible
func ToIP(addr ma.Multiaddr) (net.IP, error) {
var ip net.IP
ma.ForEach(addr, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_IP6ZONE:
// we can't return these anyways.
return true
case ma.P_IP6, ma.P_IP4:
ip = net.IP(c.RawValue())
return false
}
return false
})
if ip == nil {
return nil, errNotIP
}
return ip, nil
}
// DialArgs is a convenience function that returns network and address as
// expected by net.Dial. See https://godoc.org/net#Dial for an overview of
// possible return values (we do not support the unixpacket ones yet). Unix
// addresses do not, at present, compose.
func DialArgs(m ma.Multiaddr) (string, string, error) {
zone, network, ip, port, hostname, err := dialArgComponents(m)
if err != nil {
return "", "", err
}
// If we have a hostname (dns*), we don't want any fancy ipv6 formatting
// logic (zone, brackets, etc.).
if hostname {
switch network {
case "ip", "ip4", "ip6":
return network, ip, nil
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
return network, ip + ":" + port, nil
}
// Hostname is only true when network is one of the above.
panic("unreachable")
}
switch network {
case "ip6":
if zone != "" {
ip += "%" + zone
}
fallthrough
case "ip4":
return network, ip, nil
case "tcp4", "udp4":
return network, ip + ":" + port, nil
case "tcp6", "udp6":
if zone != "" {
ip += "%" + zone
}
return network, "[" + ip + "]" + ":" + port, nil
case "unix":
if runtime.GOOS == "windows" {
// convert /c:/... to c:\...
ip = filepath.FromSlash(strings.TrimLeft(ip, "/"))
}
return network, ip, nil
default:
return "", "", fmt.Errorf("%s is not a 'thin waist' address", m)
}
}
// dialArgComponents extracts the raw pieces used in dialing a Multiaddr
func dialArgComponents(m ma.Multiaddr) (zone, network, ip, port string, hostname bool, err error) {
ma.ForEach(m, func(c ma.Component) bool {
switch network {
case "":
switch c.Protocol().Code {
case ma.P_IP6ZONE:
if zone != "" {
err = fmt.Errorf("%s has multiple zones", m)
return false
}
zone = c.Value()
return true
case ma.P_IP6:
network = "ip6"
ip = c.Value()
return true
case ma.P_IP4:
if zone != "" {
err = fmt.Errorf("%s has ip4 with zone", m)
return false
}
network = "ip4"
ip = c.Value()
return true
case ma.P_DNS:
network = "ip"
hostname = true
ip = c.Value()
return true
case ma.P_DNS4:
network = "ip4"
hostname = true
ip = c.Value()
return true
case ma.P_DNS6:
network = "ip6"
hostname = true
ip = c.Value()
return true
case ma.P_UNIX:
network = "unix"
ip = c.Value()
return false
}
case "ip":
switch c.Protocol().Code {
case ma.P_UDP:
network = "udp"
case ma.P_TCP:
network = "tcp"
default:
return false
}
port = c.Value()
case "ip4":
switch c.Protocol().Code {
case ma.P_UDP:
network = "udp4"
case ma.P_TCP:
network = "tcp4"
default:
return false
}
port = c.Value()
case "ip6":
switch c.Protocol().Code {
case ma.P_UDP:
network = "udp6"
case ma.P_TCP:
network = "tcp6"
default:
return false
}
port = c.Value()
}
// Done.
return false
})
return
}
func parseTCPNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.TCPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
// Get IP Addr
ipm, err := FromIPAndZone(ac.IP, ac.Zone)
if err != nil {
return nil, errIncorrectNetAddr
}
// Get TCP Addr
tcpm, err := ma.NewMultiaddr(fmt.Sprintf("/tcp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}
// Encapsulate
return ipm.Encapsulate(tcpm), nil
}
func parseUDPNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.UDPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
// Get IP Addr
ipm, err := FromIPAndZone(ac.IP, ac.Zone)
if err != nil {
return nil, errIncorrectNetAddr
}
// Get UDP Addr
udpm, err := ma.NewMultiaddr(fmt.Sprintf("/udp/%d", ac.Port))
if err != nil {
return nil, errIncorrectNetAddr
}
// Encapsulate
return ipm.Encapsulate(udpm), nil
}
func parseIPNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.IPAddr)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIPAndZone(ac.IP, ac.Zone)
}
func parseIPPlusNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.IPNet)
if !ok {
return nil, errIncorrectNetAddr
}
return FromIP(ac.IP)
}
func parseUnixNetAddr(a net.Addr) (ma.Multiaddr, error) {
ac, ok := a.(*net.UnixAddr)
if !ok {
return nil, errIncorrectNetAddr
}
path := ac.Name
if runtime.GOOS == "windows" {
// Convert c:\foobar\... to c:/foobar/...
path = filepath.ToSlash(path)
}
if len(path) == 0 || path[0] != '/' {
// convert "" and "c:/..." to "/..."
path = "/" + path
}
return ma.NewComponent("unix", path)
}

View File

@@ -0,0 +1,5 @@
// Package manet provides Multiaddr specific versions of common
// functions in stdlib's net package. This means wrappers of
// standard net symbols like net.Dial and net.Listen, as well
// as conversion to/from net.Addr.
package manet

136
vendor/github.com/multiformats/go-multiaddr/net/ip.go generated vendored Normal file
View File

@@ -0,0 +1,136 @@
package manet
import (
"net"
ma "github.com/multiformats/go-multiaddr"
)
// Loopback Addresses
var (
// IP4Loopback is the ip4 loopback multiaddr
IP4Loopback = ma.StringCast("/ip4/127.0.0.1")
// IP6Loopback is the ip6 loopback multiaddr
IP6Loopback = ma.StringCast("/ip6/::1")
// IP4MappedIP6Loopback is the IPv4 Mapped IPv6 loopback address.
IP4MappedIP6Loopback = ma.StringCast("/ip6/::ffff:127.0.0.1")
)
// Unspecified Addresses (used for )
var (
IP4Unspecified = ma.StringCast("/ip4/0.0.0.0")
IP6Unspecified = ma.StringCast("/ip6/::")
)
// IsThinWaist returns whether a Multiaddr starts with "Thin Waist" Protocols.
// This means: /{IP4, IP6}[/{TCP, UDP}]
func IsThinWaist(m ma.Multiaddr) bool {
m = zoneless(m)
if m == nil {
return false
}
p := m.Protocols()
// nothing? not even a waist.
if len(p) == 0 {
return false
}
if p[0].Code != ma.P_IP4 && p[0].Code != ma.P_IP6 {
return false
}
// only IP? still counts.
if len(p) == 1 {
return true
}
switch p[1].Code {
case ma.P_TCP, ma.P_UDP, ma.P_IP4, ma.P_IP6:
return true
default:
return false
}
}
// IsIPLoopback returns whether a Multiaddr starts with a "Loopback" IP address
// This means either /ip4/127.*.*.*/*, /ip6/::1/*, or /ip6/::ffff:127.*.*.*.*/*,
// or /ip6zone/<any value>/ip6/<one of the preceding ip6 values>/*
func IsIPLoopback(m ma.Multiaddr) bool {
m = zoneless(m)
c, _ := ma.SplitFirst(m)
if c == nil {
return false
}
switch c.Protocol().Code {
case ma.P_IP4, ma.P_IP6:
return net.IP(c.RawValue()).IsLoopback()
}
return false
}
// IsIP6LinkLocal returns whether a Multiaddr starts with an IPv6 link-local
// multiaddress (with zero or one leading zone). These addresses are non
// routable.
func IsIP6LinkLocal(m ma.Multiaddr) bool {
m = zoneless(m)
c, _ := ma.SplitFirst(m)
if c == nil || c.Protocol().Code != ma.P_IP6 {
return false
}
ip := net.IP(c.RawValue())
return ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast()
}
// IsIPUnspecified returns whether a Multiaddr starts with an Unspecified IP address
// This means either /ip4/0.0.0.0/* or /ip6/::/*
func IsIPUnspecified(m ma.Multiaddr) bool {
m = zoneless(m)
if m == nil {
return false
}
c, _ := ma.SplitFirst(m)
return net.IP(c.RawValue()).IsUnspecified()
}
// If m matches [zone,ip6,...], return [ip6,...]
// else if m matches [], [zone], or [zone,...], return nil
// else return m
func zoneless(m ma.Multiaddr) ma.Multiaddr {
head, tail := ma.SplitFirst(m)
if head == nil {
return nil
}
if head.Protocol().Code == ma.P_IP6ZONE {
if tail == nil {
return nil
}
tailhead, _ := ma.SplitFirst(tail)
if tailhead.Protocol().Code != ma.P_IP6 {
return nil
}
return tail
} else {
return m
}
}
var nat64WellKnownPrefix net.IPNet
func init() {
_, np, err := net.ParseCIDR("64:ff9b::/96")
if err != nil {
panic(err)
}
nat64WellKnownPrefix = *np
}
// IsNAT64IPv4ConvertedIPv6Addr returns whether addr is a well-known prefix "64:ff9b::/96" addr
// used for NAT64 Translation. See RFC 6052
func IsNAT64IPv4ConvertedIPv6Addr(addr ma.Multiaddr) bool {
c, _ := ma.SplitFirst(addr)
return c != nil && c.Protocol().Code == ma.P_IP6 &&
nat64WellKnownPrefix.Contains(net.IP(c.RawValue()))
}

430
vendor/github.com/multiformats/go-multiaddr/net/net.go generated vendored Normal file
View File

@@ -0,0 +1,430 @@
// Package manet provides Multiaddr
// (https://github.com/multiformats/go-multiaddr) specific versions of common
// functions in Go's standard `net` package. This means wrappers of standard
// net symbols like `net.Dial` and `net.Listen`, as well as conversion to
// and from `net.Addr`.
package manet
import (
"context"
"fmt"
"net"
ma "github.com/multiformats/go-multiaddr"
)
// Conn is the equivalent of a net.Conn object. It is the
// result of calling the Dial or Listen functions in this
// package, with associated local and remote Multiaddrs.
type Conn interface {
net.Conn
// LocalMultiaddr returns the local Multiaddr associated
// with this connection
LocalMultiaddr() ma.Multiaddr
// RemoteMultiaddr returns the remote Multiaddr associated
// with this connection
RemoteMultiaddr() ma.Multiaddr
}
type halfOpen interface {
net.Conn
CloseRead() error
CloseWrite() error
}
func wrap(nconn net.Conn, laddr, raddr ma.Multiaddr) Conn {
endpts := maEndpoints{
laddr: laddr,
raddr: raddr,
}
// This sucks. However, it's the only way to reliably expose the
// underlying methods. This way, users that need access to, e.g.,
// CloseRead and CloseWrite, can do so via type assertions.
switch nconn := nconn.(type) {
case *net.TCPConn:
return &struct {
*net.TCPConn
maEndpoints
}{nconn, endpts}
case *net.UDPConn:
return &struct {
*net.UDPConn
maEndpoints
}{nconn, endpts}
case *net.IPConn:
return &struct {
*net.IPConn
maEndpoints
}{nconn, endpts}
case *net.UnixConn:
return &struct {
*net.UnixConn
maEndpoints
}{nconn, endpts}
case halfOpen:
return &struct {
halfOpen
maEndpoints
}{nconn, endpts}
default:
return &struct {
net.Conn
maEndpoints
}{nconn, endpts}
}
}
// WrapNetConn wraps a net.Conn object with a Multiaddr friendly Conn.
//
// This function does it's best to avoid "hiding" methods exposed by the wrapped
// type. Guarantees:
//
// - If the wrapped connection exposes the "half-open" closer methods
// (CloseWrite, CloseRead), these will be available on the wrapped connection
// via type assertions.
// - If the wrapped connection is a UnixConn, IPConn, TCPConn, or UDPConn, all
// methods on these wrapped connections will be available via type assertions.
func WrapNetConn(nconn net.Conn) (Conn, error) {
if nconn == nil {
return nil, fmt.Errorf("failed to convert nconn.LocalAddr: nil")
}
laddr, err := FromNetAddr(nconn.LocalAddr())
if err != nil {
return nil, fmt.Errorf("failed to convert nconn.LocalAddr: %s", err)
}
raddr, err := FromNetAddr(nconn.RemoteAddr())
if err != nil {
return nil, fmt.Errorf("failed to convert nconn.RemoteAddr: %s", err)
}
return wrap(nconn, laddr, raddr), nil
}
type maEndpoints struct {
laddr ma.Multiaddr
raddr ma.Multiaddr
}
// LocalMultiaddr returns the local address associated with
// this connection
func (c *maEndpoints) LocalMultiaddr() ma.Multiaddr {
return c.laddr
}
// RemoteMultiaddr returns the remote address associated with
// this connection
func (c *maEndpoints) RemoteMultiaddr() ma.Multiaddr {
return c.raddr
}
// Dialer contains options for connecting to an address. It
// is effectively the same as net.Dialer, but its LocalAddr
// and RemoteAddr options are Multiaddrs, instead of net.Addrs.
type Dialer struct {
// Dialer is just an embedded net.Dialer, with all its options.
net.Dialer
// LocalAddr is the local address to use when dialing an
// address. The address must be of a compatible type for the
// network being dialed.
// If nil, a local address is automatically chosen.
LocalAddr ma.Multiaddr
}
// Dial connects to a remote address, using the options of the
// Dialer. Dialer uses an underlying net.Dialer to Dial a
// net.Conn, then wraps that in a Conn object (with local and
// remote Multiaddrs).
func (d *Dialer) Dial(remote ma.Multiaddr) (Conn, error) {
return d.DialContext(context.Background(), remote)
}
// DialContext allows to provide a custom context to Dial().
func (d *Dialer) DialContext(ctx context.Context, remote ma.Multiaddr) (Conn, error) {
// if a LocalAddr is specified, use it on the embedded dialer.
if d.LocalAddr != nil {
// convert our multiaddr to net.Addr friendly
naddr, err := ToNetAddr(d.LocalAddr)
if err != nil {
return nil, err
}
// set the dialer's LocalAddr as naddr
d.Dialer.LocalAddr = naddr
}
// get the net.Dial friendly arguments from the remote addr
rnet, rnaddr, err := DialArgs(remote)
if err != nil {
return nil, err
}
// ok, Dial!
var nconn net.Conn
switch rnet {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "unix":
nconn, err = d.Dialer.DialContext(ctx, rnet, rnaddr)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unrecognized network: %s", rnet)
}
// get local address (pre-specified or assigned within net.Conn)
local := d.LocalAddr
// This block helps us avoid parsing addresses in transports (such as unix
// sockets) that don't have local addresses when dialing out.
if local == nil && nconn.LocalAddr().String() != "" {
local, err = FromNetAddr(nconn.LocalAddr())
if err != nil {
return nil, err
}
}
return wrap(nconn, local, remote), nil
}
// Dial connects to a remote address. It uses an underlying net.Conn,
// then wraps it in a Conn object (with local and remote Multiaddrs).
func Dial(remote ma.Multiaddr) (Conn, error) {
return (&Dialer{}).Dial(remote)
}
// A Listener is a generic network listener for stream-oriented protocols.
// it uses an embedded net.Listener, overriding net.Listener.Accept to
// return a Conn and providing Multiaddr.
type Listener interface {
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn
Accept() (Conn, error)
// Close closes the listener.
// Any blocked Accept operations will be unblocked and return errors.
Close() error
// Multiaddr returns the listener's (local) Multiaddr.
Multiaddr() ma.Multiaddr
// Addr returns the net.Listener's network address.
Addr() net.Addr
}
type netListenerAdapter struct {
Listener
}
func (nla *netListenerAdapter) Accept() (net.Conn, error) {
return nla.Listener.Accept()
}
// NetListener turns this Listener into a net.Listener.
//
// - Connections returned from Accept implement multiaddr/net Conn.
// - Calling WrapNetListener on the net.Listener returned by this function will
// return the original (underlying) multiaddr/net Listener.
func NetListener(l Listener) net.Listener {
return &netListenerAdapter{l}
}
// maListener implements Listener
type maListener struct {
net.Listener
laddr ma.Multiaddr
}
// Accept waits for and returns the next connection to the listener.
// Returns a Multiaddr friendly Conn
func (l *maListener) Accept() (Conn, error) {
nconn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
var raddr ma.Multiaddr
// This block protects us in transports (i.e. unix sockets) that don't have
// remote addresses for inbound connections.
if addr := nconn.RemoteAddr(); addr != nil && addr.String() != "" {
raddr, err = FromNetAddr(addr)
if err != nil {
return nil, fmt.Errorf("failed to convert conn.RemoteAddr: %s", err)
}
}
var laddr ma.Multiaddr
if addr := nconn.LocalAddr(); addr != nil && addr.String() != "" {
laddr, err = FromNetAddr(addr)
if err != nil {
return nil, fmt.Errorf("failed to convert conn.LocalAddr: %s", err)
}
}
return wrap(nconn, laddr, raddr), nil
}
// Multiaddr returns the listener's (local) Multiaddr.
func (l *maListener) Multiaddr() ma.Multiaddr {
return l.laddr
}
// Addr returns the listener's network address.
func (l *maListener) Addr() net.Addr {
return l.Listener.Addr()
}
// Listen announces on the local network address laddr.
// The Multiaddr must be a "ThinWaist" stream-oriented network:
// ip4/tcp, ip6/tcp, (TODO: unix, unixpacket)
// See Dial for the syntax of laddr.
func Listen(laddr ma.Multiaddr) (Listener, error) {
// get the net.Listen friendly arguments from the remote addr
lnet, lnaddr, err := DialArgs(laddr)
if err != nil {
return nil, err
}
nl, err := net.Listen(lnet, lnaddr)
if err != nil {
return nil, err
}
// we want to fetch the new multiaddr from the listener, as it may
// have resolved to some other value. WrapNetListener does it for us.
return WrapNetListener(nl)
}
// WrapNetListener wraps a net.Listener with a manet.Listener.
func WrapNetListener(nl net.Listener) (Listener, error) {
if nla, ok := nl.(*netListenerAdapter); ok {
return nla.Listener, nil
}
laddr, err := FromNetAddr(nl.Addr())
if err != nil {
return nil, err
}
return &maListener{
Listener: nl,
laddr: laddr,
}, nil
}
// A PacketConn is a generic packet oriented network connection which uses an
// underlying net.PacketConn, wrapped with the locally bound Multiaddr.
type PacketConn interface {
net.PacketConn
LocalMultiaddr() ma.Multiaddr
ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error)
WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error)
}
// maPacketConn implements PacketConn
type maPacketConn struct {
net.PacketConn
laddr ma.Multiaddr
}
var _ PacketConn = (*maPacketConn)(nil)
// LocalMultiaddr returns the bound local Multiaddr.
func (l *maPacketConn) LocalMultiaddr() ma.Multiaddr {
return l.laddr
}
func (l *maPacketConn) ReadFromMultiaddr(b []byte) (int, ma.Multiaddr, error) {
n, addr, err := l.ReadFrom(b)
maddr, _ := FromNetAddr(addr)
return n, maddr, err
}
func (l *maPacketConn) WriteToMultiaddr(b []byte, maddr ma.Multiaddr) (int, error) {
addr, err := ToNetAddr(maddr)
if err != nil {
return 0, err
}
return l.WriteTo(b, addr)
}
// ListenPacket announces on the local network address laddr.
// The Multiaddr must be a packet driven network, like udp4 or udp6.
// See Dial for the syntax of laddr.
func ListenPacket(laddr ma.Multiaddr) (PacketConn, error) {
lnet, lnaddr, err := DialArgs(laddr)
if err != nil {
return nil, err
}
pc, err := net.ListenPacket(lnet, lnaddr)
if err != nil {
return nil, err
}
// We want to fetch the new multiaddr from the listener, as it may
// have resolved to some other value. WrapPacketConn does this.
return WrapPacketConn(pc)
}
// WrapPacketConn wraps a net.PacketConn with a manet.PacketConn.
func WrapPacketConn(pc net.PacketConn) (PacketConn, error) {
laddr, err := FromNetAddr(pc.LocalAddr())
if err != nil {
return nil, err
}
return &maPacketConn{
PacketConn: pc,
laddr: laddr,
}, nil
}
// InterfaceMultiaddrs will return the addresses matching net.InterfaceAddrs
func InterfaceMultiaddrs() ([]ma.Multiaddr, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
maddrs := make([]ma.Multiaddr, len(addrs))
for i, a := range addrs {
maddrs[i], err = FromNetAddr(a)
if err != nil {
return nil, err
}
}
return maddrs, nil
}
// AddrMatch returns the Multiaddrs that match the protocol stack on addr
func AddrMatch(match ma.Multiaddr, addrs []ma.Multiaddr) []ma.Multiaddr {
// we should match transports entirely.
p1s := match.Protocols()
out := make([]ma.Multiaddr, 0, len(addrs))
for _, a := range addrs {
p2s := a.Protocols()
if len(p1s) != len(p2s) {
continue
}
match := true
for i, p2 := range p2s {
if p1s[i].Code != p2.Code {
match = false
break
}
}
if match {
out = append(out, a)
}
}
return out
}

View File

@@ -0,0 +1,177 @@
package manet
import (
"net"
"strings"
ma "github.com/multiformats/go-multiaddr"
)
// Private4 and Private6 are well-known private networks
var Private4, Private6 []*net.IPNet
var privateCIDR4 = []string{
// localhost
"127.0.0.0/8",
// private networks
"10.0.0.0/8",
"100.64.0.0/10",
"172.16.0.0/12",
"192.168.0.0/16",
// link local
"169.254.0.0/16",
}
var privateCIDR6 = []string{
// localhost
"::1/128",
// ULA reserved
"fc00::/7",
// link local
"fe80::/10",
}
// Unroutable4 and Unroutable6 are well known unroutable address ranges
var Unroutable4, Unroutable6 []*net.IPNet
var unroutableCIDR4 = []string{
"0.0.0.0/8",
"192.0.0.0/26",
"192.0.2.0/24",
"192.88.99.0/24",
"198.18.0.0/15",
"198.51.100.0/24",
"203.0.113.0/24",
"224.0.0.0/4",
"240.0.0.0/4",
"255.255.255.255/32",
}
var unroutableCIDR6 = []string{
"ff00::/8",
}
// unResolvableDomains do not resolve to an IP address.
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
var unResolvableDomains = []string{
// Reverse DNS Lookup
".in-addr.arpa",
".ip6.arpa",
// RFC 6761: Users MAY assume that queries for "invalid" names will always return NXDOMAIN
// responses
".invalid",
}
// privateUseDomains are reserved for private use and have no central authority for consistent
// address resolution
// Ref: https://en.wikipedia.org/wiki/Special-use_domain_name#Reserved_domain_names
var privateUseDomains = []string{
// RFC 8375: Reserved for home networks
".home.arpa",
// MDNS
".local",
// RFC 6761: No central authority for .test names
".test",
}
// RFC 6761: Users may assume that IPv4 and IPv6 address queries for localhost names will
// always resolve to the respective IP loopback address
const localHostDomain = ".localhost"
func init() {
Private4 = parseCIDR(privateCIDR4)
Private6 = parseCIDR(privateCIDR6)
Unroutable4 = parseCIDR(unroutableCIDR4)
Unroutable6 = parseCIDR(unroutableCIDR6)
}
func parseCIDR(cidrs []string) []*net.IPNet {
ipnets := make([]*net.IPNet, len(cidrs))
for i, cidr := range cidrs {
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
panic(err)
}
ipnets[i] = ipnet
}
return ipnets
}
// IsPublicAddr returns true if the IP part of the multiaddr is a publicly routable address
// or if it's a dns address without a special use domain e.g. .local.
func IsPublicAddr(a ma.Multiaddr) bool {
isPublic := false
ma.ForEach(a, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_IP6ZONE:
return true
case ma.P_IP4:
ip := net.IP(c.RawValue())
isPublic = !inAddrRange(ip, Private4) && !inAddrRange(ip, Unroutable4)
case ma.P_IP6:
ip := net.IP(c.RawValue())
isPublic = !inAddrRange(ip, Private6) && !inAddrRange(ip, Unroutable6)
case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
dnsAddr := c.Value()
isPublic = true
if isSubdomain(dnsAddr, localHostDomain) {
isPublic = false
return false
}
for _, ud := range unResolvableDomains {
if isSubdomain(dnsAddr, ud) {
isPublic = false
return false
}
}
for _, pd := range privateUseDomains {
if isSubdomain(dnsAddr, pd) {
isPublic = false
break
}
}
}
return false
})
return isPublic
}
// isSubdomain checks if child is sub domain of parent. It also returns true if child and parent are
// the same domain.
// Parent must have a "." prefix.
func isSubdomain(child, parent string) bool {
return strings.HasSuffix(child, parent) || child == parent[1:]
}
// IsPrivateAddr returns true if the IP part of the mutiaddr is in a private network
func IsPrivateAddr(a ma.Multiaddr) bool {
isPrivate := false
ma.ForEach(a, func(c ma.Component) bool {
switch c.Protocol().Code {
case ma.P_IP6ZONE:
return true
case ma.P_IP4:
isPrivate = inAddrRange(net.IP(c.RawValue()), Private4)
case ma.P_IP6:
isPrivate = inAddrRange(net.IP(c.RawValue()), Private6)
case ma.P_DNS, ma.P_DNS4, ma.P_DNS6, ma.P_DNSADDR:
dnsAddr := c.Value()
if isSubdomain(dnsAddr, localHostDomain) {
isPrivate = true
}
// We don't check for privateUseDomains because private use domains can
// resolve to public IP addresses
}
return false
})
return isPrivate
}
func inAddrRange(ip net.IP, ipnets []*net.IPNet) bool {
for _, ipnet := range ipnets {
if ipnet.Contains(ip) {
return true
}
}
return false
}

View File

@@ -0,0 +1,97 @@
package manet
import (
"fmt"
"net"
"sync"
ma "github.com/multiformats/go-multiaddr"
)
// FromNetAddrFunc is a generic function which converts a net.Addr to Multiaddress
type FromNetAddrFunc func(a net.Addr) (ma.Multiaddr, error)
// ToNetAddrFunc is a generic function which converts a Multiaddress to net.Addr
type ToNetAddrFunc func(ma ma.Multiaddr) (net.Addr, error)
var defaultCodecs = NewCodecMap()
func init() {
RegisterFromNetAddr(parseTCPNetAddr, "tcp", "tcp4", "tcp6")
RegisterFromNetAddr(parseUDPNetAddr, "udp", "udp4", "udp6")
RegisterFromNetAddr(parseIPNetAddr, "ip", "ip4", "ip6")
RegisterFromNetAddr(parseIPPlusNetAddr, "ip+net")
RegisterFromNetAddr(parseUnixNetAddr, "unix")
RegisterToNetAddr(parseBasicNetMaddr, "tcp", "udp", "ip6", "ip4", "unix")
}
// CodecMap holds a map of NetCodecs indexed by their Protocol ID
// along with parsers for the addresses they use.
// It is used to keep a list of supported network address codecs (protocols
// which addresses can be converted to and from multiaddresses).
type CodecMap struct {
addrParsers map[string]FromNetAddrFunc
maddrParsers map[string]ToNetAddrFunc
lk sync.Mutex
}
// NewCodecMap initializes and returns a CodecMap object.
func NewCodecMap() *CodecMap {
return &CodecMap{
addrParsers: make(map[string]FromNetAddrFunc),
maddrParsers: make(map[string]ToNetAddrFunc),
}
}
// RegisterFromNetAddr registers a conversion from net.Addr instances to multiaddrs.
func RegisterFromNetAddr(from FromNetAddrFunc, networks ...string) {
defaultCodecs.RegisterFromNetAddr(from, networks...)
}
// RegisterToNetAddr registers a conversion from multiaddrs to net.Addr instances.
func RegisterToNetAddr(to ToNetAddrFunc, protocols ...string) {
defaultCodecs.RegisterToNetAddr(to, protocols...)
}
// RegisterFromNetAddr registers a conversion from net.Addr instances to multiaddrs
func (cm *CodecMap) RegisterFromNetAddr(from FromNetAddrFunc, networks ...string) {
cm.lk.Lock()
defer cm.lk.Unlock()
for _, n := range networks {
cm.addrParsers[n] = from
}
}
// RegisterToNetAddr registers a conversion from multiaddrs to net.Addr instances
func (cm *CodecMap) RegisterToNetAddr(to ToNetAddrFunc, protocols ...string) {
cm.lk.Lock()
defer cm.lk.Unlock()
for _, p := range protocols {
cm.maddrParsers[p] = to
}
}
func (cm *CodecMap) getAddrParser(net string) (FromNetAddrFunc, error) {
cm.lk.Lock()
defer cm.lk.Unlock()
parser, ok := cm.addrParsers[net]
if !ok {
return nil, fmt.Errorf("unknown network %v", net)
}
return parser, nil
}
func (cm *CodecMap) getMaddrParser(name string) (ToNetAddrFunc, error) {
cm.lk.Lock()
defer cm.lk.Unlock()
p, ok := cm.maddrParsers[name]
if !ok {
return nil, fmt.Errorf("network not supported: %s", name)
}
return p, nil
}

View File

@@ -0,0 +1,83 @@
package manet
import (
"fmt"
ma "github.com/multiformats/go-multiaddr"
)
// ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces. If ifaceAddr is nil, we request interface addresses
// from the network stack. (this is so you can provide a cached value if resolving many addrs)
func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
// split address into its components
split := ma.Split(resolve)
// if first component (ip) is not unspecified, use it as is.
if !IsIPUnspecified(split[0]) {
return []ma.Multiaddr{resolve}, nil
}
out := make([]ma.Multiaddr, 0, len(ifaceAddrs))
for _, ia := range ifaceAddrs {
// must match the first protocol to be resolve.
if ia.Protocols()[0].Code != resolve.Protocols()[0].Code {
continue
}
split[0] = ia
joined := ma.Join(split...)
out = append(out, joined)
}
if len(out) < 1 {
return nil, fmt.Errorf("failed to resolve: %s", resolve)
}
return out, nil
}
// ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
// use the known local interfaces.
func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
// todo optimize: only fetch these if we have a "any" addr.
if len(ifaceAddrs) < 1 {
var err error
ifaceAddrs, err = interfaceAddresses()
if err != nil {
return nil, err
}
}
var outputAddrs []ma.Multiaddr
for _, a := range unspecAddrs {
// unspecified?
resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs)
if err != nil {
continue // optimistic. if we can't resolve anything, we'll know at the bottom.
}
outputAddrs = append(outputAddrs, resolved...)
}
if len(outputAddrs) < 1 {
return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs)
}
return outputAddrs, nil
}
// interfaceAddresses returns a list of addresses associated with local machine
// Note: we do not return link local addresses. IP loopback is ok, because we
// may be connecting to other nodes in the same machine.
func interfaceAddresses() ([]ma.Multiaddr, error) {
maddrs, err := InterfaceMultiaddrs()
if err != nil {
return nil, err
}
var out []ma.Multiaddr
for _, a := range maddrs {
if IsIP6LinkLocal(a) {
continue
}
out = append(out, a)
}
return out, nil
}