mirror of
https://github.com/hyprspace/hyprspace.git
synced 2026-09-12 19:51:07 +05:00
FindPeerByIDPrefix previously returned the first peer whose ID started with the given prefix, silently ignoring further matches. With Ed25519 peer IDs all sharing the leading "12D3KooW" (8 chars), short prefixes can match multiple peers; the chosen peer then depends on slice order, which is effectively undefined from the user's perspective. Change FindPeerByIDPrefix and its wrapper FindPeerByCLIRef to return (*Peer, error): - 0 matches -> (nil, nil) - 1 match -> (&peer, nil) - 2+ match -> (nil, error) describing the ambiguity Call sites in config.Read and rpc/server.go updated accordingly: ambiguity surfaces as a config-load / CLI error instead of a silent wrong-peer resolution. Not a wire-protocol or config-format change. Only behavior visible at CLI invocation and config load. Users relying on short prefixes that happened to match multiple peers will now see a clear error and must lengthen the prefix.
206 lines
5.0 KiB
Go
206 lines
5.0 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/rpc"
|
|
"os"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"github.com/hyprspace/hyprspace/config"
|
|
"github.com/hyprspace/hyprspace/p2p"
|
|
"github.com/hyprspace/hyprspace/tun"
|
|
"github.com/ipfs/go-log/v2"
|
|
"github.com/libp2p/go-libp2p/core/host"
|
|
"github.com/libp2p/go-libp2p/core/network"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
"github.com/multiformats/go-multiaddr"
|
|
"github.com/yl2chen/cidranger"
|
|
)
|
|
|
|
var logger = log.Logger("hyprspace/rpc")
|
|
|
|
type HyprspaceRPC struct {
|
|
host host.Host
|
|
config config.Config
|
|
tunDev tun.TUN
|
|
}
|
|
|
|
func (hsr *HyprspaceRPC) Status(args *Args, reply *StatusReply) error {
|
|
netPeersCurrent := 0
|
|
var netPeerAddrsCurrent []string
|
|
for _, p := range hsr.config.Peers {
|
|
if hsr.host.Network().Connectedness(p.ID) == network.Connected {
|
|
netPeersCurrent = netPeersCurrent + 1
|
|
for _, c := range hsr.host.Network().ConnsToPeer(p.ID) {
|
|
netPeerAddrsCurrent = append(netPeerAddrsCurrent, fmt.Sprintf("@%s (%s) %s/p2p/%s",
|
|
p.Name,
|
|
hsr.host.Peerstore().LatencyEWMA(p.ID).String(),
|
|
c.RemoteMultiaddr().String(),
|
|
p.ID.String(),
|
|
))
|
|
}
|
|
}
|
|
}
|
|
var addrStrings []string
|
|
for _, ma := range hsr.host.Addrs() {
|
|
addrStrings = append(addrStrings, ma.String())
|
|
}
|
|
*reply = StatusReply{
|
|
hsr.host.ID().String(),
|
|
len(hsr.host.Network().Conns()),
|
|
netPeersCurrent,
|
|
netPeerAddrsCurrent,
|
|
len(hsr.config.Peers),
|
|
addrStrings,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (hsr *HyprspaceRPC) Route(args *RouteArgs, reply *RouteReply) error {
|
|
switch args.Action {
|
|
case Show:
|
|
var routeInfos []RouteInfo
|
|
allRoutes4, err := hsr.config.PeerLookup.ByRoute.CoveredNetworks(*cidranger.AllIPv4)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
allRoutes6, err := hsr.config.PeerLookup.ByRoute.CoveredNetworks(*cidranger.AllIPv6)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
allRoutes := append(allRoutes4, allRoutes6...)
|
|
for _, r := range allRoutes {
|
|
rte := *r.(*config.RouteTableEntry)
|
|
connected := hsr.host.Network().Connectedness(rte.Target.ID) == network.Connected
|
|
relay := false
|
|
relayAddr := rte.Target.ID
|
|
if connected {
|
|
ConnLoop:
|
|
for _, c := range hsr.host.Network().ConnsToPeer(rte.Target.ID) {
|
|
for _, s := range c.GetStreams() {
|
|
if s.Protocol() == p2p.Protocol {
|
|
if _, err := c.RemoteMultiaddr().ValueForProtocol(multiaddr.P_CIRCUIT); err == nil {
|
|
relay = true
|
|
if ra, err := c.RemoteMultiaddr().ValueForProtocol(multiaddr.P_P2P); err == nil {
|
|
relayAddr, err = peer.Decode(ra)
|
|
if err != nil {
|
|
relayAddr = rte.Target.ID
|
|
}
|
|
}
|
|
} else {
|
|
relay = false
|
|
relayAddr = rte.Target.ID
|
|
break ConnLoop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
routeInfos = append(routeInfos, RouteInfo{
|
|
Network: rte.Network(),
|
|
TargetName: rte.Target.Name,
|
|
TargetAddr: rte.Target.ID,
|
|
RelayAddr: relayAddr,
|
|
IsRelay: relay,
|
|
IsConnected: connected,
|
|
})
|
|
}
|
|
*reply = RouteReply{
|
|
Routes: routeInfos,
|
|
}
|
|
case Add:
|
|
if len(args.Args) != 2 {
|
|
return errors.New("expected exactly 2 arguments")
|
|
}
|
|
_, network, err := net.ParseCIDR(args.Args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
target, err := config.FindPeerByCLIRef(hsr.config.Peers, args.Args[1])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if target == nil {
|
|
return errors.New("no such peer")
|
|
}
|
|
err = hsr.tunDev.Apply(tun.Route(*network))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hsr.config.PeerLookup.ByRoute.Insert(&config.RouteTableEntry{
|
|
Net: *network,
|
|
Target: *target,
|
|
})
|
|
case Del:
|
|
if len(args.Args) != 1 {
|
|
return errors.New("expected exactly 1 argument")
|
|
}
|
|
_, network, err := net.ParseCIDR(args.Args[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = hsr.tunDev.Apply(tun.RemoveRoute(*network))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = hsr.config.PeerLookup.ByRoute.Remove(*network)
|
|
if err != nil {
|
|
_ = hsr.tunDev.Apply(tun.Route(*network))
|
|
return err
|
|
}
|
|
default:
|
|
return errors.New("no such action")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (hsr *HyprspaceRPC) Peers(args *Args, reply *PeersReply) error {
|
|
var peerAddrs []string
|
|
for _, c := range hsr.host.Network().Conns() {
|
|
peerAddrs = append(peerAddrs, fmt.Sprintf("%s/p2p/%s", c.RemoteMultiaddr().String(), c.RemotePeer().String()))
|
|
}
|
|
*reply = PeersReply{peerAddrs}
|
|
return nil
|
|
}
|
|
|
|
func RpcServer(ctx context.Context, wg *sync.WaitGroup, ma multiaddr.Multiaddr, host host.Host, config config.Config, tunDev tun.TUN) {
|
|
wg.Add(1)
|
|
defer wg.Done()
|
|
hsr := HyprspaceRPC{host, config, tunDev}
|
|
rpc.Register(&hsr)
|
|
|
|
addr, err := ma.ValueForProtocol(multiaddr.P_UNIX)
|
|
if err != nil {
|
|
logger.With(err).Fatal("Failed to parse multiaddr")
|
|
}
|
|
|
|
var l net.Listener
|
|
oldUmask := syscall.Umask(0o007)
|
|
|
|
err = os.Remove(addr)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
logger.Fatal("[!] Could not remove old RPC socket: ", err)
|
|
}
|
|
|
|
var lc net.ListenConfig
|
|
l, err = lc.Listen(ctx, "unix", addr)
|
|
syscall.Umask(oldUmask)
|
|
|
|
if err != nil {
|
|
logger.With(err).Fatal("Failed to launch RPC server")
|
|
}
|
|
|
|
logger.Info("RPC server ready")
|
|
defer l.Close()
|
|
go rpc.Accept(l)
|
|
<-ctx.Done()
|
|
logger.Info("Closing RPC server")
|
|
}
|