diff --git a/packages/networking/hyprspace/cli/init.go b/packages/networking/hyprspace/cli/init.go index dd0b8da..dbd67a4 100644 --- a/packages/networking/hyprspace/cli/init.go +++ b/packages/networking/hyprspace/cli/init.go @@ -53,7 +53,7 @@ func InitRun(r *cmd.Root, c *cmd.Sub) { Name: args.InterfaceName, ListenPort: 8001, Address: "10.1.1.1/24", - ID: host.ID().Pretty(), + ID: host.ID(), PrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes), }, } diff --git a/packages/networking/hyprspace/cli/up.go b/packages/networking/hyprspace/cli/up.go index 84092de..4f7f2b1 100644 --- a/packages/networking/hyprspace/cli/up.go +++ b/packages/networking/hyprspace/cli/up.go @@ -10,7 +10,6 @@ import ( "os" "os/signal" "path/filepath" - "runtime" "strconv" "syscall" "time" @@ -30,14 +29,12 @@ import ( ) var ( + cfg *config.Config // iface is the tun device used to pass packets between // Hyprspace and the user's machine. tunDev *tun.TUN - // RevLookup allow quick lookups of an incoming stream - // for security before accepting or responding to any data. - RevLookup map[string]string // activeStreams is a map of active streams to a peer - activeStreams map[string]network.Stream + activeStreams map[peer.ID]network.Stream // context ctx context.Context // context cancel function @@ -76,43 +73,18 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { } // Read in configuration from file. - cfg, err := config.Read(configPath) + cfg2, err := config.Read(configPath) + cfg = cfg2 checkErr(err) - // Setup reverse lookup hash map for authentication. - RevLookup = make(map[string]string, len(cfg.Peers)) - for ip, id := range cfg.Peers { - RevLookup[id.ID] = ip - } - fmt.Println("[+] Creating TUN Device") - if runtime.GOOS == "darwin" { - if len(cfg.Peers) > 1 { - checkErr(errors.New("cannot create interface macos does not support more than one peer")) - } - - // Grab ip address of only peer in config - var destPeer string - for ip := range cfg.Peers { - destPeer = ip - } - - // Create new TUN device - tunDev, err = tun.New( - cfg.Interface.Name, - tun.Address(cfg.Interface.Address), - tun.DestAddress(destPeer), - tun.MTU(1420), - ) - } else { - // Create new TUN device - tunDev, err = tun.New( - cfg.Interface.Name, - tun.Address(cfg.Interface.Address), - tun.MTU(1420), - ) - } + // Create new TUN device + tunDev, err = tun.New( + cfg.Interface.Name, + tun.Address(cfg.Interface.Address), + tun.MTU(1420), + ) if err != nil { checkErr(err) } @@ -137,23 +109,14 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { checkErr(err) host.SetStreamHandler(p2p.PeXProtocol, p2p.NewPeXStreamHandler(host, cfg)) - for _, id := range cfg.Peers { - p, err := peer.Decode(id.ID) - checkErr(err) - host.ConnManager().Protect(p, "/hyprspace/peer") - } - - // Setup Peer Table for Quick Packet --> Dest ID lookup - peerTable := make(map[string]peer.ID) - for ip, id := range cfg.Peers { - peerTable[ip], err = peer.Decode(id.ID) - checkErr(err) + for _, p := range cfg.Peers { + host.ConnManager().Protect(p.ID, "/hyprspace/peer") } fmt.Println("[+] Setting Up Node Discovery via DHT") // Setup P2P Discovery - go p2p.Discover(ctx, host, dht, peerTable) + go p2p.Discover(ctx, host, dht, cfg.Peers) // Configure path for lock lockPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface.Name+".lock") @@ -165,7 +128,7 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { go signalHandler(ctx, host, lockPath, dht) // Log about various events - go eventLogger(ctx, host, cfg) + go eventLogger(ctx, host) // RPC server go hsrpc.RpcServer(ctx, multiaddr.StringCast(fmt.Sprintf("/unix/run/hyprspace-rpc.%s.sock", cfg.Interface.Name)), host, *cfg) @@ -187,7 +150,7 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { // + ----------------------------------------+ // Initialize active streams map and packet byte array. - activeStreams = make(map[string]network.Stream) + activeStreams = make(map[peer.ID]network.Stream) var packet = make([]byte, 1420) ip, _, err := net.ParseCIDR(cfg.Interface.Address) if err != nil { @@ -207,23 +170,24 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { } dstIP := net.IPv4(packet[16], packet[17], packet[18], packet[19]) - dst := dstIP.String() + if ip.Equal(dstIP) { + continue + } + var dst *config.Peer // Check route table for destination address. - for route, _ := range cfg.Routes { - _, network, _ := net.ParseCIDR(route) - if network.Contains(dstIP) { - src := net.IPv4(packet[12], packet[13], packet[14], packet[15]) - _, ok := peerTable[dst] - // Only rewrite if initiator is us or receiver is not a known peer - if src.Equal(ip) && !ok { - dst = cfg.Routes[route].IP - } + for _, route := range cfg.Routes { + if route.Network.Contains(dstIP) { + dst = &route.Target + break } } + if dst == nil { + continue + } // Check if we already have an open connection to the destination peer. - stream, ok := activeStreams[dst] + stream, ok := activeStreams[dst.ID] if ok { // Write out the packet's length to the libp2p stream to ensure // we know the full size of the packet at the other end. @@ -240,36 +204,32 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { // If we encounter an error when writing to a stream we should // close that stream and delete it from the active stream map. stream.Close() - delete(activeStreams, dst) + delete(activeStreams, dst.ID) } - // Check if the destination of the packet is a known peer to - // the interface. - if peer, ok := peerTable[dst]; ok { - stream, err = host.NewStream(ctx, peer, p2p.Protocol) - if err != nil { - fmt.Println("[!] Failed to open stream to " + dst) - go p2p.Rediscover() - continue - } - stream.SetWriteDeadline(time.Now().Add(25 * time.Second)) - // Write packet length - err = binary.Write(stream, binary.LittleEndian, uint16(plen)) - if err != nil { - stream.Close() - continue - } - // Write the packet - _, err = stream.Write(packet[:plen]) - if err != nil { - stream.Close() - continue - } - - // If all succeeds when writing the packet to the stream - // we should reuse this stream by adding it active streams map. - activeStreams[dst] = stream + stream, err = host.NewStream(ctx, dst.ID, p2p.Protocol) + if err != nil { + fmt.Println("[!] Failed to open stream to " + dst.ID.String()) + go p2p.Rediscover() + continue } + stream.SetWriteDeadline(time.Now().Add(25 * time.Second)) + // Write packet length + err = binary.Write(stream, binary.LittleEndian, uint16(plen)) + if err != nil { + stream.Close() + continue + } + // Write the packet + _, err = stream.Write(packet[:plen]) + if err != nil { + stream.Close() + continue + } + + // If all succeeds when writing the packet to the stream + // we should reuse this stream by adding it active streams map. + activeStreams[dst.ID] = stream } } @@ -306,7 +266,7 @@ func signalHandler(ctx context.Context, host host.Host, lockPath string, dht *dh } } -func eventLogger(ctx context.Context, host host.Host, cfg *config.Config) { +func eventLogger(ctx context.Context, host host.Host) { subCon, err := host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged)) checkErr(err) for { @@ -315,14 +275,14 @@ func eventLogger(ctx context.Context, host host.Host, cfg *config.Config) { return case ev := <-subCon.Out(): evt := ev.(event.EvtPeerConnectednessChanged) - for vpnIp, vpnPeer := range cfg.Peers { - if vpnPeer.ID == evt.Peer.Pretty() { + for _, vpnPeer := range cfg.Peers { + if vpnPeer.ID == evt.Peer { if evt.Connectedness == network.Connected { for _, c := range host.Network().ConnsToPeer(evt.Peer) { - fmt.Printf("[+] Connected to %s at %s/p2p/%s\n", vpnIp, c.RemoteMultiaddr().String(), evt.Peer.Pretty()) + fmt.Printf("[+] Connected to %s/p2p/%s\n", c.RemoteMultiaddr().String(), evt.Peer.String()) } } else if evt.Connectedness == network.NotConnected { - fmt.Printf("[!] Disconnected from %s\n", vpnIp) + fmt.Printf("[!] Disconnected from %s\n", evt.Peer.String()) } break } @@ -333,7 +293,7 @@ func eventLogger(ctx context.Context, host host.Host, cfg *config.Config) { func streamHandler(stream network.Stream) { // If the remote node ID isn't in the list of known nodes don't respond. - if _, ok := RevLookup[stream.Conn().RemotePeer().Pretty()]; !ok { + if _, ok := config.FindPeer(cfg.Peers, stream.Conn().RemotePeer()); !ok { stream.Reset() return } diff --git a/packages/networking/hyprspace/config/config.go b/packages/networking/hyprspace/config/config.go index 3ebfdec..ed07610 100644 --- a/packages/networking/hyprspace/config/config.go +++ b/packages/networking/hyprspace/config/config.go @@ -2,36 +2,41 @@ package config import ( "fmt" + "log" "net" "os" + "github.com/libp2p/go-libp2p/core/peer" "gopkg.in/yaml.v2" ) // Config is the main Configuration Struct for Hyprspace. type Config struct { - Path string `yaml:"path,omitempty"` - Interface Interface `yaml:"interface"` - Peers map[string]Peer `yaml:"peers"` - Routes map[string]Route `yaml:"routes"` + Path string `yaml:"path,omitempty"` + Interface Interface `yaml:"interface"` + Peers []Peer `yaml:"peers"` + Routes []Route } // Interface defines all of the fields that a local node needs to know about itself! type Interface struct { - Name string `yaml:"name"` - ID string `yaml:"id"` - ListenPort int `yaml:"listen_port"` - Address string `yaml:"address"` - PrivateKey string `yaml:"private_key"` + Name string `yaml:"name"` + ID peer.ID `yaml:"id"` + ListenPort int `yaml:"listen_port"` + Address string `yaml:"address"` + PrivateKey string `yaml:"private_key"` } // Peer defines a peer in the configuration. We might add more to this later. type Peer struct { - ID string `yaml:"id"` + ID peer.ID `yaml:"id"` + Routes []Route `yaml:"routes"` } type Route struct { - IP string `yaml:"ip"` + Target Peer + NetworkStr string `yaml:"net"` + Network net.IPNet } // Read initializes a config from a file. @@ -56,21 +61,16 @@ func Read(path string) (*Config, error) { return nil, err } - // Check peers have valid ip addresses - for ip := range result.Peers { - if net.ParseIP(ip).String() == "" { - return nil, fmt.Errorf("%s is not a valid ip address", ip) - } else { - fmt.Printf("[+] Assign this ip: %s to node: %s.\n", ip, result.Peers[ip].ID) - } - } - - for route := range result.Routes { - _, _, err := net.ParseCIDR(route) - if err != nil { - return nil, fmt.Errorf("%s is not a valid route", route) - } else { - fmt.Printf("[+] Assign route %s via %s.\n", route, result.Routes[route].IP) + for _, p := range result.Peers { + for _, r := range p.Routes { + r.Target = p + _, n, err := net.ParseCIDR(r.NetworkStr) + if err != nil { + log.Fatal("[!] Invalid network:", r.NetworkStr) + } + r.Network = *n + result.Routes = append(result.Routes, r) + fmt.Printf("[+] Route %s via %s\n", r.Network.String(), p.ID.String()) } } @@ -78,3 +78,23 @@ func Read(path string) (*Config, error) { result.Path = path return &result, nil } + +func FindPeer(peers []Peer, needle peer.ID) (*Peer, bool) { + for _, p := range peers { + if p.ID == needle { + return &p, true + } + } + return nil, false +} + +func FindRoute(routes []Route, needle net.IPNet) (*Route, bool) { + for _, r := range routes { + bits1, _ := r.Network.Mask.Size() + bits2, _ := needle.Mask.Size() + if r.Network.IP.Equal(needle.IP) && bits1 == bits2 { + return &r, true + } + } + return nil, false +} diff --git a/packages/networking/hyprspace/p2p/discover.go b/packages/networking/hyprspace/p2p/discover.go index 114d2b8..29050a4 100644 --- a/packages/networking/hyprspace/p2p/discover.go +++ b/packages/networking/hyprspace/p2p/discover.go @@ -5,16 +5,16 @@ import ( "fmt" "time" + "github.com/hyprspace/hyprspace/config" dht "github.com/libp2p/go-libp2p-kad-dht" "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/network" - "github.com/libp2p/go-libp2p/core/peer" ) var discoverNow = make(chan bool) // Discover starts up a DHT based discovery system finding and adding nodes with the same rendezvous string. -func Discover(ctx context.Context, h host.Host, dht *dht.IpfsDHT, peerTable map[string]peer.ID) { +func Discover(ctx context.Context, h host.Host, dht *dht.IpfsDHT, peers []config.Peer) { dur := time.Second * 1 ticker := time.NewTicker(dur) defer ticker.Stop() @@ -29,9 +29,9 @@ func Discover(ctx context.Context, h host.Host, dht *dht.IpfsDHT, peerTable map[ ticker.Reset(time.Millisecond * 1) case <-ticker.C: connectedToAny := false - for _, id := range peerTable { - if h.Network().Connectedness(id) != network.Connected { - addrs, err := dht.FindPeer(ctx, id) + for _, p := range peers { + if h.Network().Connectedness(p.ID) != network.Connected { + addrs, err := dht.FindPeer(ctx, p.ID) if err != nil { continue } diff --git a/packages/networking/hyprspace/p2p/pex.go b/packages/networking/hyprspace/p2p/pex.go index c51be2b..6b0fc33 100644 --- a/packages/networking/hyprspace/p2p/pex.go +++ b/packages/networking/hyprspace/p2p/pex.go @@ -29,12 +29,15 @@ func checkErrPeX(err error, stream network.Stream) bool { } func NewPeXStreamHandler(host host.Host, cfg *config.Config) func(network.Stream) { - revLookup := make(map[string]string, len(cfg.Peers)) - for ip, id := range cfg.Peers { - revLookup[id.ID] = ip - } return func(stream network.Stream) { - if _, ok := revLookup[stream.Conn().RemotePeer().String()]; !ok { + found := false + for _, p := range cfg.Peers { + if p.ID == stream.Conn().RemotePeer() { + found = true + break + } + } + if !found { stream.Reset() return } @@ -47,12 +50,8 @@ func NewPeXStreamHandler(host host.Host, cfg *config.Config) func(network.Stream if str == "r" { // peer requests addresses for _, p := range cfg.Peers { - peerId, err := peer.Decode(p.ID) - if checkErrPeX(err, stream) { - return - } - if peerId != stream.Conn().RemotePeer() { - for _, c := range host.Network().ConnsToPeer(peerId) { + if p.ID != stream.Conn().RemotePeer() { + for _, c := range host.Network().ConnsToPeer(p.ID) { _, err := stream.Write([]byte(fmt.Sprintf("%s|%s\n", c.RemotePeer().String(), c.RemoteMultiaddr().String()))) if checkErrPeX(err, stream) { return @@ -114,17 +113,13 @@ func PeXService(ctx context.Context, host host.Host, cfg *config.Config) { case ev := <-subCon.Out(): evt := ev.(event.EvtPeerConnectednessChanged) for _, vpnPeer := range cfg.Peers { - if vpnPeer.ID == evt.Peer.String() { + if vpnPeer.ID == evt.Peer { if evt.Connectedness == network.Connected { go RequestPeX(ctx, host, []peer.ID{evt.Peer}) } else if evt.Connectedness == network.NotConnected { peers := []peer.ID{} for _, p := range cfg.Peers { - peerId, err := peer.Decode(p.ID) - if err != nil { - continue - } - peers = append(peers, peerId) + peers = append(peers, p.ID) } go RequestPeX(ctx, host, peers) } diff --git a/packages/networking/hyprspace/project.nix b/packages/networking/hyprspace/project.nix index d6c2dd8..f21796d 100644 --- a/packages/networking/hyprspace/project.nix +++ b/packages/networking/hyprspace/project.nix @@ -10,7 +10,7 @@ }; packages.hyprspace = with pkgs; buildGo118Module { pname = "hyprspace"; - version = "0.4.1"; + version = "0.5.0"; src = with inputs.nix-filter.lib; let dirs = map inDirectory; diff --git a/packages/networking/hyprspace/rpc/server.go b/packages/networking/hyprspace/rpc/server.go index e4aeb93..0846f8a 100644 --- a/packages/networking/hyprspace/rpc/server.go +++ b/packages/networking/hyprspace/rpc/server.go @@ -11,7 +11,6 @@ import ( "github.com/hyprspace/hyprspace/config" "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" ) @@ -23,15 +22,11 @@ type HyprspaceRPC struct { func (hsr *HyprspaceRPC) Status(args *Args, reply *StatusReply) error { netPeersCurrent := 0 var netPeerAddrsCurrent []string - for _, id := range hsr.config.Peers { - peerId, err := peer.Decode(id.ID) - if err != nil { - return err - } - if hsr.host.Network().Connectedness(peerId) == network.Connected { + 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(peerId) { - netPeerAddrsCurrent = append(netPeerAddrsCurrent, fmt.Sprintf("%s/p2p/%s", c.RemoteMultiaddr().String(), peerId.String())) + for _, c := range hsr.host.Network().ConnsToPeer(p.ID) { + netPeerAddrsCurrent = append(netPeerAddrsCurrent, fmt.Sprintf("%s/p2p/%s", c.RemoteMultiaddr().String(), p.ID.String())) } } }