diff --git a/packages/networking/hyprspace/cli/down.go b/packages/networking/hyprspace/cli/down.go deleted file mode 100644 index dae2a29..0000000 --- a/packages/networking/hyprspace/cli/down.go +++ /dev/null @@ -1,62 +0,0 @@ -package cli - -import ( - "fmt" - "os" - "path/filepath" - "strconv" - - "github.com/DataDrake/cli-ng/v2/cmd" - "github.com/hyprspace/hyprspace/tun" -) - -// Down brings down a Hyprspace interface and removes it from the system. -var Down = cmd.Sub{ - Name: "down", - Alias: "d", - Short: "Bring Down A Hyprspace Interface.", - Args: &DownArgs{}, - Run: DownRun, -} - -// DownArgs handles the specific arguments for the down command. -type DownArgs struct { - InterfaceName string -} - -// DownRun handles the execution of the down command. -func DownRun(r *cmd.Root, c *cmd.Sub) { - // Parse Command Args - args := c.Args.(*DownArgs) - - // Parse Global Config Flag for Custom Config Path - configPath := r.Flags.(*GlobalFlags).Config - if configPath == "" { - configPath = "/etc/hyprspace/" + args.InterfaceName + ".json" - } - - // Read lock from file system to stop process. - lockPath := filepath.Join(filepath.Dir(configPath), args.InterfaceName+".lock") - out, err := os.ReadFile(lockPath) - checkErr(err) - - pid, err := strconv.Atoi(string(out)) - checkErr(err) - - process, err := os.FindProcess(pid) - checkErr(err) - - err0 := process.Signal(os.Interrupt) - - err1 := tun.Delete(args.InterfaceName) - - // Different types of systems may need the tun devices destroyed first or - // the process to exit first don't worry as long as one of these two has - // succeeded. - if err0 != nil && err1 != nil { - checkErr(err0) - checkErr(err1) - } - - fmt.Println("[+] deleted hyprspace " + args.InterfaceName + " daemon") -} diff --git a/packages/networking/hyprspace/cli/init.go b/packages/networking/hyprspace/cli/init.go index 9877758..e7f47b1 100644 --- a/packages/networking/hyprspace/cli/init.go +++ b/packages/networking/hyprspace/cli/init.go @@ -5,11 +5,9 @@ import ( "fmt" "os" "path/filepath" - "strings" "github.com/DataDrake/cli-ng/v2/cmd" "github.com/hyprspace/hyprspace/config" - "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p/core/crypto" "github.com/multiformats/go-multibase" ) @@ -19,41 +17,35 @@ var Init = cmd.Sub{ Name: "init", Alias: "i", Short: "Initialize An Interface Config", - Args: &InitArgs{}, Run: InitRun, } -// InitArgs handles the specific arguments for the init command. -type InitArgs struct { - InterfaceName string -} - // InitRun handles the execution of the init command. func InitRun(r *cmd.Root, c *cmd.Sub) { - // Parse Command Arguments - args := c.Args.(*InitArgs) - - // Parse Global Config Flag - configPath := r.Flags.(*GlobalFlags).Config - if configPath == "" { - configPath = "/etc/hyprspace/" + args.InterfaceName + ".json" + ifName := r.Flags.(*GlobalFlags).InterfaceName + if ifName == "" { + ifName = "hyprspace" } - // Create New Libp2p Node - host, err := libp2p.New() + configPath := r.Flags.(*GlobalFlags).Config + if configPath == "" { + configPath = "/etc/hyprspace/" + ifName + ".json" + } + + privKey, _, err := crypto.GenerateKeyPair(crypto.Ed25519, 256) checkErr(err) - // Get Node's Private Key - keyBytes, err := crypto.MarshalPrivateKey(host.Peerstore().PrivKey(host.ID())) + keyBytes, err := crypto.MarshalPrivateKey(privKey) checkErr(err) // Setup an initial default command. new := config.Config{ - Interface: config.Interface{ - Name: args.InterfaceName, - ListenPort: 8001, - ID: host.ID(), - PrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes), + EncodedPrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes), + EncodedListenAddresses: []string{ + "/ip4/0.0.0.0/tcp/8001", + "/ip4/0.0.0.0/udp/8001/quic-v1", + "/ip6/::/tcp/8001", + "/ip6/::/udp/8001/quic-v1", }, Peers: make([]config.Peer, 0), } @@ -67,21 +59,11 @@ func InitRun(r *cmd.Root, c *cmd.Sub) { f, err := os.Create(configPath) checkErr(err) - // Write out config to file. _, err = f.Write(out) checkErr(err) err = f.Close() checkErr(err) - // Print config creation message to user fmt.Printf("Initialized new config at %s\n", configPath) - fmt.Println("To edit the config run,") - fmt.Println() - if strings.HasPrefix(configPath, "/etc/") { - fmt.Printf(" sudo nano %s\n", configPath) - } else { - fmt.Printf(" nano %s\n", configPath) - } - fmt.Println() } diff --git a/packages/networking/hyprspace/cli/root.go b/packages/networking/hyprspace/cli/root.go index 7dc9bf7..d2a414f 100644 --- a/packages/networking/hyprspace/cli/root.go +++ b/packages/networking/hyprspace/cli/root.go @@ -31,7 +31,6 @@ func init() { cmd.Register(&cmd.Help) cmd.Register(&Init) cmd.Register(&Up) - cmd.Register(&Down) cmd.Register(&Status) cmd.Register(&Peers) cmd.Register(&Route) diff --git a/packages/networking/hyprspace/cli/up.go b/packages/networking/hyprspace/cli/up.go index ca02159..66f3bdb 100644 --- a/packages/networking/hyprspace/cli/up.go +++ b/packages/networking/hyprspace/cli/up.go @@ -11,7 +11,6 @@ import ( "os" "os/signal" "path/filepath" - "strconv" "syscall" "time" @@ -27,7 +26,6 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" - "github.com/multiformats/go-multibase" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/yl2chen/cidranger" ) @@ -51,34 +49,25 @@ var Up = cmd.Sub{ Name: "up", Alias: "up", Short: "Create and Bring Up a Hyprspace Interface.", - Args: &UpArgs{}, - Flags: &UpFlags{}, Run: UpRun, } -// UpArgs handles the specific arguments for the up command. -type UpArgs struct { - InterfaceName string -} - -// UpFlags handles the specific flags for the up command. -type UpFlags struct { - Foreground bool `short:"f" long:"foreground" desc:"Don't Create Background Daemon."` -} - // UpRun handles the execution of the up command. func UpRun(r *cmd.Root, c *cmd.Sub) { - // Parse Command Args - args := c.Args.(*UpArgs) + ifName := r.Flags.(*GlobalFlags).InterfaceName + if ifName == "" { + ifName = "hyprspace" + } // Parse Global Config Flag for Custom Config Path configPath := r.Flags.(*GlobalFlags).Config if configPath == "" { - configPath = "/etc/hyprspace/" + args.InterfaceName + ".json" + configPath = "/etc/hyprspace/" + ifName + ".json" } // Read in configuration from file. cfg2, err := config.Read(configPath) + cfg2.Interface = ifName cfg = cfg2 checkErr(err) @@ -86,8 +75,8 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { // Create new TUN device tunDev, err = tun.New( - cfg.Interface.Name, - tun.Address(cfg.Interface.BuiltinAddr.String()+"/32"), + cfg.Interface, + tun.Address(cfg.BuiltinAddr.String()+"/32"), tun.MTU(1420), ) if err != nil { @@ -108,16 +97,11 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { fmt.Println("[+] Creating LibP2P Node") - // Check that the listener port is available. - port, err := verifyPort(cfg.Interface.ListenPort) - checkErr(err) - - _, privateKey, err := multibase.Decode(cfg.Interface.PrivateKey) // Create P2P Node host, dht, err := p2p.CreateNode( ctx, - privateKey, - port, + cfg.PrivateKey, + cfg.ListenAddresses, streamHandler, p2p.NewClosedCircuitRelayFilter(cfg.Peers), cfg.Peers, @@ -136,7 +120,7 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { go p2p.Discover(ctx, host, dht, cfg.Peers) // Configure path for lock - lockPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface.Name+".lock") + lockPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface+".lock") // PeX go p2p.PeXService(ctx, host, cfg) @@ -151,10 +135,10 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { 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, *tunDev) + go hsrpc.RpcServer(ctx, multiaddr.StringCast(fmt.Sprintf("/unix/run/hyprspace-rpc.%s.sock", cfg.Interface)), host, *cfg, *tunDev) // Magic DNS server - go hsdns.MagicDnsServer(ctx, *cfg) + go hsdns.MagicDnsServer(ctx, *cfg, node) // metrics endpoint metricsPort, ok := os.LookupEnv("HYPRSPACE_METRICS_PORT") @@ -201,7 +185,7 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { } dstIP := net.IPv4(packet[16], packet[17], packet[18], packet[19]) - if cfg.Interface.BuiltinAddr.Equal(dstIP) { + if cfg.BuiltinAddr.Equal(dstIP) { continue } var dst peer.ID @@ -354,34 +338,3 @@ func streamHandler(stream network.Stream) { tunDev.Iface.Write(packet[:size]) } } - -func verifyPort(port int) (int, error) { - var ln net.Listener - var err error - - // If a user manually sets a port don't try to automatically - // find an open port. - if port != 8001 { - ln, err = net.Listen("tcp", ":"+strconv.Itoa(port)) - if err != nil { - return port, errors.New("could not create node, listen port already in use by something else") - } - } else { - // Automatically look for an open port when a custom port isn't - // selected by a user. - for { - ln, err = net.Listen("tcp", ":"+strconv.Itoa(port)) - if err == nil { - break - } - if port >= 65535 { - return port, errors.New("failed to find open port") - } - port++ - } - } - if ln != nil { - ln.Close() - } - return port, nil -} diff --git a/packages/networking/hyprspace/config/config.go b/packages/networking/hyprspace/config/config.go index b615d51..ac036f0 100644 --- a/packages/networking/hyprspace/config/config.go +++ b/packages/networking/hyprspace/config/config.go @@ -8,25 +8,24 @@ import ( "os" "strings" + "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" + "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-multibase" "github.com/yl2chen/cidranger" ) // Config is the main Configuration Struct for Hyprspace. type Config struct { - Path string `json:"-"` - Interface Interface `json:"interface"` - Peers []Peer `json:"peers"` - PeerLookup PeerLookup `json:"-"` -} - -// Interface defines all of the fields that a local node needs to know about itself! -type Interface struct { - Name string `json:"name"` - ID peer.ID `json:"id"` - ListenPort int `json:"listen_port"` - BuiltinAddr net.IP `json:"-"` - PrivateKey string `json:"private_key"` + Path string `json:"-"` + Interface string `json:"-"` + EncodedListenAddresses []string `json:"listenAddresses"` + ListenAddresses []multiaddr.Multiaddr `json:"-"` + Peers []Peer `json:"peers"` + PeerLookup PeerLookup `json:"-"` + EncodedPrivateKey string `json:"privateKey"` + PrivateKey crypto.PrivKey `json:"-"` + BuiltinAddr net.IP `json:"-"` } // Peer defines a peer in the configuration. We might add more to this later. @@ -64,11 +63,11 @@ func Read(path string) (*Config, error) { return nil, err } result := Config{ - Interface: Interface{ - Name: "hs0", - ListenPort: 8001, - ID: "", - PrivateKey: "", + EncodedListenAddresses: []string{ + "/ip4/0.0.0.0/tcp/8001", + "/ip4/0.0.0.0/udp/8001/quic-v1", + "/ip6/::/tcp/8001", + "/ip6/::/udp/8001/quic-v1", }, } @@ -78,7 +77,35 @@ func Read(path string) (*Config, error) { return nil, err } - result.Interface.BuiltinAddr = mkBuiltinAddr(result.Interface.ID) + _, keyBytes, err := multibase.Decode(result.EncodedPrivateKey) + if err != nil { + return nil, err + } + + pk, err := crypto.UnmarshalPrivateKey(keyBytes) + if err != nil { + return nil, err + } + + result.PrivateKey = pk + if err != nil { + return nil, err + } + + peerID, err := peer.IDFromPrivateKey(result.PrivateKey) + if err != nil { + return nil, err + } + + result.BuiltinAddr = mkBuiltinAddr(peerID) + + for _, addrString := range result.EncodedListenAddresses { + addr, err := multiaddr.NewMultiaddr(addrString) + if err != nil { + return nil, err + } + result.ListenAddresses = append(result.ListenAddresses, addr) + } result.PeerLookup.ByRoute = cidranger.NewPCTrieRanger() result.PeerLookup.ByName = make(map[string]Peer) diff --git a/packages/networking/hyprspace/dns/server.go b/packages/networking/hyprspace/dns/server.go index 62a9a88..85fe456 100644 --- a/packages/networking/hyprspace/dns/server.go +++ b/packages/networking/hyprspace/dns/server.go @@ -10,6 +10,7 @@ import ( "github.com/hyprspace/hyprspace/config" "github.com/iguanesolutions/go-systemd/v5/resolved" + "github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/peer" "github.com/miekg/dns" "github.com/multiformats/go-multibase" @@ -66,7 +67,7 @@ func writeResponse(msg *dns.Msg, q dns.Question, p peer.ID, addr net.IP) { }) } -func MagicDnsServer(ctx context.Context, config config.Config) { +func MagicDnsServer(ctx context.Context, config config.Config, node host.Host) { dns.HandleFunc(domainSuffix, func(w dns.ResponseWriter, r *dns.Msg) { m := new(dns.Msg) m.SetReply(r) @@ -75,8 +76,8 @@ func MagicDnsServer(ctx context.Context, config config.Config) { switch q.Qtype { case dns.TypeA: if qpeer, err := peer.Decode(strings.TrimSuffix(q.Name, "."+domainSuffix)); err == nil { - if qpeer == config.Interface.ID { - m.Answer = append(m.Answer, mkIDRecord(config.Interface.ID, config.Interface.BuiltinAddr)) + if qpeer == node.ID() { + m.Answer = append(m.Answer, mkIDRecord(node.ID(), config.BuiltinAddr)) } else { for _, p := range config.Peers { if p.ID == qpeer { @@ -94,8 +95,8 @@ func MagicDnsServer(ctx context.Context, config config.Config) { qName := strings.ToLower(strings.TrimSuffix(q.Name, "."+domainSuffix)) if qName == strings.ToLower(hostname) { - m.Answer = append(m.Answer, mkAliasRecord(qName, config.Interface.ID)) - m.Answer = append(m.Answer, mkIDRecord(config.Interface.ID, config.Interface.BuiltinAddr)) + m.Answer = append(m.Answer, mkAliasRecord(qName, node.ID())) + m.Answer = append(m.Answer, mkIDRecord(node.ID(), config.BuiltinAddr)) } else if p, found := config.PeerLookup.ByName[qName]; found { m.Answer = append(m.Answer, mkAliasRecord(qName, p.ID)) m.Answer = append(m.Answer, mkIDRecord(p.ID, p.BuiltinAddr)) @@ -128,7 +129,7 @@ func MagicDnsServer(ctx context.Context, config config.Config) { } defer conn.Close() - link, err := netlink.LinkByName(config.Interface.Name) + link, err := netlink.LinkByName(config.Interface) if err != nil { fmt.Println("[!] [dns] Failed to get link ID:", err) return @@ -137,14 +138,14 @@ func MagicDnsServer(ctx context.Context, config config.Config) { for _, f := range [](func() error){ func() error { - return conn.SetLinkDNSEx(ctx, linkID, []resolved.LinkDNSEx{resolved.LinkDNSEx{ + return conn.SetLinkDNSEx(ctx, linkID, []resolved.LinkDNSEx{{ Family: syscall.AF_INET, Address: []byte{127, 80, 1, 53}, Port: 5380, }}) }, func() error { - return conn.SetLinkDomains(ctx, linkID, []resolved.LinkDomain{resolved.LinkDomain{ + return conn.SetLinkDomains(ctx, linkID, []resolved.LinkDomain{{ Domain: domainSuffix, RoutingDomain: false, }}) diff --git a/packages/networking/hyprspace/p2p/node.go b/packages/networking/hyprspace/p2p/node.go index d1a616c..50eb17e 100644 --- a/packages/networking/hyprspace/p2p/node.go +++ b/packages/networking/hyprspace/p2p/node.go @@ -91,13 +91,7 @@ func getExtraBootstrapNodes(addr ma.Multiaddr) (nodesList []string) { } // CreateNode creates an internal Libp2p nodes and returns it and it's DHT Discovery service. -func CreateNode(ctx context.Context, inputKey []byte, port int, handler network.StreamHandler, acl relay.ACLFilter, vpnPeers []config.Peer) (node host.Host, dhtOut *dht.IpfsDHT, err error) { - // Unmarshal Private Key - privateKey, err := crypto.UnmarshalPrivateKey(inputKey) - if err != nil { - return - } - +func CreateNode(ctx context.Context, privateKey crypto.PrivKey, listenAddreses []ma.Multiaddr, handler network.StreamHandler, acl relay.ACLFilter, vpnPeers []config.Peer) (node host.Host, dhtOut *dht.IpfsDHT, err error) { maybePrivateNet := libp2p.ChainOptions() swarmKeyFile, ok := os.LookupEnv("HYPRSPACE_SWARM_KEY") if ok { @@ -112,18 +106,12 @@ func CreateNode(ctx context.Context, inputKey []byte, port int, handler network. maybePrivateNet = libp2p.PrivateNetwork(key) } - ip6quic := fmt.Sprintf("/ip6/::/udp/%d/quic-v1", port) - ip4quic := fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1", port) - - ip6tcp := fmt.Sprintf("/ip6/::/tcp/%d", port) - ip4tcp := fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port) - peerChan := make(chan peer.AddrInfo) // Create libp2p node basicHost, err := libp2p.New( maybePrivateNet, - libp2p.ListenAddrStrings(ip6tcp, ip4tcp, ip4quic, ip6quic), + libp2p.ListenAddrs(listenAddreses...), libp2p.Identity(privateKey), libp2p.DefaultSecurity, libp2p.NATPortMap(), diff --git a/packages/networking/hyprspace/project.nix b/packages/networking/hyprspace/project.nix index 5da34ca..6f60f7d 100644 --- a/packages/networking/hyprspace/project.nix +++ b/packages/networking/hyprspace/project.nix @@ -8,9 +8,9 @@ ]; env.GOPATH.eval = "$REPO_DATA_DIR/go"; }; - packages.hyprspace = with pkgs; buildGo120Module { + packages.hyprspace = with pkgs; buildGo120Module rec { pname = "hyprspace"; - version = "0.7.1"; + version = "0.8.0"; src = with inputs.nix-filter.lib; let dirs = map inDirectory; @@ -32,6 +32,8 @@ vendorSha256 = "sha256-cP93ndADvQ9gFvPdNgi3aY4kAaKAuL0wq6P6PcUwIX4="; + ldflags = [ "-s" "-w" "-X github.com/hyprspace/hyprspace/cli.appVersion=${version}" ]; + meta = with lib; { description = "A Lightweight VPN Built on top of Libp2p for Truly Distributed Networks."; homepage = "https://github.com/hyprspace/hyprspace";