diff --git a/packages/networking/hyprspace/cli/init.go b/packages/networking/hyprspace/cli/init.go index 62715ee..9877758 100644 --- a/packages/networking/hyprspace/cli/init.go +++ b/packages/networking/hyprspace/cli/init.go @@ -52,7 +52,6 @@ func InitRun(r *cmd.Root, c *cmd.Sub) { Interface: config.Interface{ Name: args.InterfaceName, ListenPort: 8001, - Address: "10.1.1.1/24", 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 a68ea64..1064121 100644 --- a/packages/networking/hyprspace/cli/up.go +++ b/packages/networking/hyprspace/cli/up.go @@ -17,6 +17,7 @@ import ( "github.com/DataDrake/cli-ng/v2/cmd" "github.com/hyprspace/hyprspace/config" + hsdns "github.com/hyprspace/hyprspace/dns" "github.com/hyprspace/hyprspace/p2p" hsrpc "github.com/hyprspace/hyprspace/rpc" "github.com/hyprspace/hyprspace/tun" @@ -28,6 +29,7 @@ import ( "github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multibase" "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/yl2chen/cidranger" ) var ( @@ -85,12 +87,21 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { // Create new TUN device tunDev, err = tun.New( cfg.Interface.Name, - tun.Address(cfg.Interface.Address), + tun.Address(cfg.Interface.BuiltinAddr.String()+"/32"), tun.MTU(1420), ) if err != nil { checkErr(err) } + allRoutes, err := cfg.PeerLookup.ByRoute.CoveredNetworks(*cidranger.AllIPv4) + if err != nil { + checkErr(err) + } + var routeOpts []tun.Option + + for _, r := range allRoutes { + routeOpts = append(routeOpts, tun.Route(r.Network())) + } // Setup System Context ctx, ctxCancel = context.WithCancel(context.Background()) @@ -142,6 +153,9 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { // RPC server go hsrpc.RpcServer(ctx, multiaddr.StringCast(fmt.Sprintf("/unix/run/hyprspace-rpc.%s.sock", cfg.Interface.Name)), host, *cfg) + // Magic DNS server + go hsdns.MagicDnsServer(ctx, *cfg) + // metrics endpoint metricsPort, ok := os.LookupEnv("HYPRSPACE_METRICS_PORT") if ok { @@ -162,6 +176,7 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { if err != nil { checkErr(errors.New("unable to bring up tun device")) } + checkErr(tunDev.Apply(routeOpts...)) fmt.Println("[+] Network setup complete") @@ -172,10 +187,6 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { // Initialize active streams map and packet byte array. activeStreams = make(map[peer.ID]network.Stream) var packet = make([]byte, 1420) - ip, _, err := net.ParseCIDR(cfg.Interface.Address) - if err != nil { - checkErr(errors.New("unable to parse address")) - } for { // Read in a packet from the tun device. plen, err := tunDev.Iface.Read(packet) @@ -190,23 +201,18 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { } dstIP := net.IPv4(packet[16], packet[17], packet[18], packet[19]) - if ip.Equal(dstIP) { + if cfg.Interface.BuiltinAddr.Equal(dstIP) { continue } - var dst *peer.ID + var dst peer.ID // Check route table for destination address. - for _, route := range cfg.Routes { - if route.Network.Contains(dstIP) { - dst = &route.Target.ID - break - } - } - if dst == nil { - continue - } + route, found := cfg.FindRouteForIP(dstIP) - sendPacket(*dst, packet, plen) + if found { + dst = route.Target.ID + sendPacket(dst, packet, plen) + } } } @@ -345,15 +351,7 @@ func streamHandler(stream network.Stream) { } } stream.SetWriteDeadline(time.Now().Add(25 * time.Second)) - dstIP := net.IPv4(packet[16], packet[17], packet[18], packet[19]) - route, found := config.FindRouteForIP(cfg.Routes, dstIP) - if !found { - // not found means the packet is for us - tunDev.Iface.Write(packet[:size]) - } else { - // FIXME: should decrease the TTL here - sendPacket(route.Target.ID, packet, int(plen)) - } + tunDev.Iface.Write(packet[:size]) } } diff --git a/packages/networking/hyprspace/config/config.go b/packages/networking/hyprspace/config/config.go index cba4b70..d72d0c8 100644 --- a/packages/networking/hyprspace/config/config.go +++ b/packages/networking/hyprspace/config/config.go @@ -6,37 +6,55 @@ import ( "log" "net" "os" + "strings" "github.com/libp2p/go-libp2p/core/peer" + "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"` - Routes []Route `json:"-"` + 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"` - Address string `json:"address"` - PrivateKey string `json:"private_key"` + Name string `json:"name"` + ID peer.ID `json:"id"` + ListenPort int `json:"listen_port"` + BuiltinAddr net.IP `json:"-"` + PrivateKey string `json:"private_key"` } // Peer defines a peer in the configuration. We might add more to this later. type Peer struct { - ID peer.ID `json:"id"` - Routes []Route `json:"routes"` + ID peer.ID `json:"id"` + Name string `json:"name"` + BuiltinAddr net.IP `json:"-"` + Routes []Route `json:"routes"` } type Route struct { - Target Peer - NetworkStr string `json:"net"` - Network net.IPNet + NetworkStr string `json:"net"` + Network net.IPNet `json:"-"` +} + +// PeerLookup is a helper struct for quickly looking up a peer based on various parameters +type PeerLookup struct { + ByRoute cidranger.Ranger + ByName map[string]Peer +} + +type RouteTableEntry struct { + network net.IPNet + Target Peer +} + +func (rte RouteTableEntry) Network() net.IPNet { + return rte.network } // Read initializes a config from a file. @@ -49,7 +67,6 @@ func Read(path string) (*Config, error) { Interface: Interface{ Name: "hs0", ListenPort: 8001, - Address: "10.1.1.1/24", ID: "", PrivateKey: "", }, @@ -61,17 +78,39 @@ func Read(path string) (*Config, error) { return nil, err } - for _, p := range result.Peers { + result.Interface.BuiltinAddr = mkBuiltinAddr(result.Interface.ID) + + result.PeerLookup.ByRoute = cidranger.NewPCTrieRanger() + result.PeerLookup.ByName = make(map[string]Peer) + + for i, p := range result.Peers { + p.BuiltinAddr = mkBuiltinAddr(p.ID) + p.Routes = append(p.Routes, Route{ + Network: net.IPNet{ + IP: p.BuiltinAddr, + Mask: net.IPv4Mask(255, 255, 255, 255), + }, + }) for _, r := range p.Routes { - r.Target = p - _, n, err := net.ParseCIDR(r.NetworkStr) - if err != nil { - log.Fatal("[!] Invalid network:", r.NetworkStr) + if r.NetworkStr != "" { + _, n, err := net.ParseCIDR(r.NetworkStr) + if err != nil { + log.Fatal("[!] Invalid network:", r.NetworkStr) + } + r.Network = *n } - r.Network = *n - result.Routes = append(result.Routes, r) - fmt.Printf("[+] Route %s via %s\n", r.Network.String(), p.ID.String()) + + result.PeerLookup.ByRoute.Insert(&RouteTableEntry{ + network: r.Network, + Target: p, + }) + + fmt.Printf("[+] Route %s via /p2p/%s\n", r.Network.String(), p.ID) } + if p.Name != "" { + result.PeerLookup.ByName[strings.ToLower(p.Name)] = p + } + result.Peers[i] = p } // Overwrite path of config to input. @@ -79,6 +118,14 @@ func Read(path string) (*Config, error) { return &result, nil } +func mkBuiltinAddr(p peer.ID) net.IP { + builtinAddr := []byte{100, 64, 1, 2} + for i, b := range []byte(p) { + builtinAddr[(i%2)+2] ^= b + } + return net.IP(builtinAddr) +} + func FindPeer(peers []Peer, needle peer.ID) (*Peer, bool) { for _, p := range peers { if p.ID == needle { @@ -88,22 +135,32 @@ func FindPeer(peers []Peer, needle peer.ID) (*Peer, bool) { 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 +func (cfg Config) FindRoute(needle net.IPNet) (*RouteTableEntry, bool) { + networks, err := cfg.PeerLookup.ByRoute.CoveredNetworks(needle) + if err != nil { + fmt.Println(err) + return nil, false + } else if len(networks) == 0 { + return nil, false + } else if len(networks) > 1 { + for _, n := range networks { + fmt.Printf("[!] Found duplicate route %s to /p2p/%s for %s\n", n.Network(), n.(RouteTableEntry).Target.ID, needle) } } - return nil, false + return networks[0].(*RouteTableEntry), true } -func FindRouteForIP(routes []Route, needle net.IP) (*Route, bool) { - for _, r := range routes { - if r.Network.Contains(needle) { - return &r, true +func (cfg Config) FindRouteForIP(needle net.IP) (*RouteTableEntry, bool) { + networks, err := cfg.PeerLookup.ByRoute.ContainingNetworks(needle) + if err != nil { + fmt.Println(err) + return nil, false + } else if len(networks) == 0 { + return nil, false + } else if len(networks) > 1 { + for _, n := range networks { + fmt.Printf("[!] Found duplicate route %s to /p2p/%s for %s\n", n.Network(), n.(RouteTableEntry).Target.ID, needle) } } - return nil, false + return networks[0].(*RouteTableEntry), true } diff --git a/packages/networking/hyprspace/dns/server.go b/packages/networking/hyprspace/dns/server.go new file mode 100644 index 0000000..62a9a88 --- /dev/null +++ b/packages/networking/hyprspace/dns/server.go @@ -0,0 +1,158 @@ +package dns + +import ( + "context" + "fmt" + "net" + "os" + "strings" + "syscall" + + "github.com/hyprspace/hyprspace/config" + "github.com/iguanesolutions/go-systemd/v5/resolved" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/miekg/dns" + "github.com/multiformats/go-multibase" + "github.com/vishvananda/netlink" +) + +var domainSuffix = "hyprspace." + +func mkAliasRecord(alias string, p peer.ID) *dns.CNAME { + cid, _ := peer.ToCid(p).StringOfBase(multibase.Base36) + return &dns.CNAME{ + Hdr: dns.RR_Header{ + Name: fmt.Sprintf("%s.%s", alias, domainSuffix), + Rrtype: dns.TypeCNAME, + Class: dns.ClassINET, + Ttl: 0, + }, + Target: fmt.Sprintf("%s.%s", cid, domainSuffix), + } +} + +func mkIDRecord(p peer.ID, addr net.IP) *dns.A { + cid, _ := peer.ToCid(p).StringOfBase(multibase.Base36) + return &dns.A{ + Hdr: dns.RR_Header{ + Name: fmt.Sprintf("%s.%s", cid, domainSuffix), + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: 86400, + }, + A: addr.To4(), + } +} + +func writeResponse(msg *dns.Msg, q dns.Question, p peer.ID, addr net.IP) { + msg.Answer = append(msg.Answer, &dns.A{ + Hdr: dns.RR_Header{ + Name: q.Name, + Rrtype: dns.TypeA, + Class: dns.ClassINET, + Ttl: 0, + }, + A: addr.To4(), + }) + cid, _ := peer.ToCid(p).StringOfBase(multibase.Base36) + msg.Extra = append(msg.Extra, &dns.TXT{ + Hdr: dns.RR_Header{ + Name: q.Name, + Rrtype: dns.TypeTXT, + Class: dns.ClassINET, + Ttl: 0, + }, + Txt: []string{p.String(), cid}, + }) +} + +func MagicDnsServer(ctx context.Context, config config.Config) { + dns.HandleFunc(domainSuffix, func(w dns.ResponseWriter, r *dns.Msg) { + m := new(dns.Msg) + m.SetReply(r) + + for _, q := range r.Question { + 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)) + } else { + for _, p := range config.Peers { + if p.ID == qpeer { + m.Answer = append(m.Answer, mkIDRecord(p.ID, p.BuiltinAddr)) + break + } + } + } + } else { + hostname, err := os.Hostname() + if err != nil { + fmt.Println("[!] [dns] " + err.Error()) + } + + 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)) + } 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)) + } + } + } + } + + w.WriteMsg(m) + }) + + for _, netType := range []string{"tcp", "udp"} { + sv := &dns.Server{ + Addr: "127.80.1.53:5380", + Net: netType, + ReusePort: true, + } + fmt.Printf("[-] Starting DNS server on /ip4/127.80.1.53/%s/5380\n", sv.Net) + go func(server *dns.Server) { + if err := server.ListenAndServe(); err != nil { + fmt.Printf("[!] DNS server error: %s, %s\n", server.Net, err.Error()) + } + }(sv) + } + + conn, err := resolved.NewConn() + if err != nil { + fmt.Println("[!] [dns] Failed to connect to D-Bus:", err) + return + } + defer conn.Close() + + link, err := netlink.LinkByName(config.Interface.Name) + if err != nil { + fmt.Println("[!] [dns] Failed to get link ID:", err) + return + } + linkID := link.Attrs().Index + + for _, f := range [](func() error){ + func() error { + return conn.SetLinkDNSEx(ctx, linkID, []resolved.LinkDNSEx{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{ + Domain: domainSuffix, + RoutingDomain: false, + }}) + }, + } { + if err := f(); err != nil { + fmt.Println("[!] [dns] Failed to configure resolved:", err) + return + } + } +} diff --git a/packages/networking/hyprspace/go.mod b/packages/networking/hyprspace/go.mod index 67fdcd5..e30ca68 100644 --- a/packages/networking/hyprspace/go.mod +++ b/packages/networking/hyprspace/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/DataDrake/cli-ng/v2 v2.0.2 + github.com/iguanesolutions/go-systemd/v5 v5.1.1 github.com/libp2p/go-libp2p v0.31.0 github.com/libp2p/go-libp2p-kad-dht v0.25.0 github.com/multiformats/go-multiaddr v0.11.0 @@ -68,7 +69,7 @@ require ( github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/miekg/dns v1.1.55 // indirect + github.com/miekg/dns v1.1.55 github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/sha256-simd v1.0.1 // indirect @@ -99,6 +100,7 @@ require ( github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/yl2chen/cidranger v1.0.2 go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect diff --git a/packages/networking/hyprspace/go.sum b/packages/networking/hyprspace/go.sum index d672bef..1b235f8 100644 --- a/packages/networking/hyprspace/go.sum +++ b/packages/networking/hyprspace/go.sum @@ -142,6 +142,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvH github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/huin/goupnp v1.2.0 h1:uOKW26NG1hsSSbXIZ1IR7XP9Gjd1U8pnLaCMgntmkmY= github.com/huin/goupnp v1.2.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/iguanesolutions/go-systemd/v5 v5.1.1 h1:Hs0Z16knPGCBFnKECrICPh+RQ89Sgy0xyzcalrHMKdw= +github.com/iguanesolutions/go-systemd/v5 v5.1.1/go.mod h1:Quv57scs6S7T0rC6qyLfW20KU/P4p9hrbLPF+ILYrXY= github.com/ipfs/boxo v0.11.0 h1:urMxhZ3xoF4HssJVD3+0ssGT9pptEfHfbL8DYdoWFlg= github.com/ipfs/boxo v0.11.0/go.mod h1:8IfDmp+FzFGcF4zjAgHMVPpwYw4AjN9ePEzDfkaYJ1w= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -226,6 +228,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.42/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= @@ -376,9 +379,12 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSD github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= +github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU= +github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= @@ -417,6 +423,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -433,6 +440,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -452,6 +460,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -467,6 +477,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -485,15 +496,22 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -516,6 +534,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/packages/networking/hyprspace/p2p/pex.go b/packages/networking/hyprspace/p2p/pex.go index 333bcb9..bb816f2 100644 --- a/packages/networking/hyprspace/p2p/pex.go +++ b/packages/networking/hyprspace/p2p/pex.go @@ -102,7 +102,6 @@ func RequestPeX(ctx context.Context, host host.Host, peers []peer.ID) (addrInfos s.Close() return nil, err } - fmt.Printf("[-] Got PeX peer: %s/p2p/%s\n", addrStr, idStr) addrInfos = append(addrInfos, peer.AddrInfo{ ID: peerId, Addrs: []multiaddr.Multiaddr{ma}, diff --git a/packages/networking/hyprspace/project.nix b/packages/networking/hyprspace/project.nix index b058809..e63df42 100644 --- a/packages/networking/hyprspace/project.nix +++ b/packages/networking/hyprspace/project.nix @@ -10,7 +10,7 @@ }; packages.hyprspace = with pkgs; buildGo120Module { pname = "hyprspace"; - version = "0.6.5"; + version = "0.7.0"; src = with inputs.nix-filter.lib; let dirs = map inDirectory; @@ -23,13 +23,14 @@ ] ++ (dirs [ "cli" "config" + "dns" "p2p" "rpc" "tun" ]); }; - vendorSha256 = "sha256-zr9gRYA979VYaD8jvK1MMEDhbcpHvaJccR91wp5qClU="; + vendorSha256 = "sha256-cP93ndADvQ9gFvPdNgi3aY4kAaKAuL0wq6P6PcUwIX4="; meta = with lib; { description = "A Lightweight VPN Built on top of Libp2p for Truly Distributed Networks."; diff --git a/packages/networking/hyprspace/rpc/server.go b/packages/networking/hyprspace/rpc/server.go index 670f8d6..3da79f6 100644 --- a/packages/networking/hyprspace/rpc/server.go +++ b/packages/networking/hyprspace/rpc/server.go @@ -15,6 +15,7 @@ import ( "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" + "github.com/yl2chen/cidranger" ) type HyprspaceRPC struct { @@ -55,14 +56,19 @@ func (hsr *HyprspaceRPC) Status(args *Args, reply *StatusReply) error { func (hsr *HyprspaceRPC) Route(args *RouteArgs, reply *RouteReply) error { switch args.Action { case Show: - var routes []RouteInfo - for _, r := range hsr.config.Routes { - connected := hsr.host.Network().Connectedness(r.Target.ID) == network.Connected + var routeInfos []RouteInfo + allRoutes, err := hsr.config.PeerLookup.ByRoute.CoveredNetworks(*cidranger.AllIPv4) + if err != nil { + return err + } + for _, r := range allRoutes { + rte := *r.(*config.RouteTableEntry) + connected := hsr.host.Network().Connectedness(rte.Target.ID) == network.Connected relay := false - relayAddr := r.Target.ID + relayAddr := rte.Target.ID if connected { ConnLoop: - for _, c := range hsr.host.Network().ConnsToPeer(r.Target.ID) { + 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 { @@ -70,28 +76,28 @@ func (hsr *HyprspaceRPC) Route(args *RouteArgs, reply *RouteReply) error { if ra, err := c.RemoteMultiaddr().ValueForProtocol(multiaddr.P_P2P); err == nil { relayAddr, err = peer.Decode(ra) if err != nil { - relayAddr = r.Target.ID + relayAddr = rte.Target.ID } } } else { relay = false - relayAddr = r.Target.ID + relayAddr = rte.Target.ID break ConnLoop } } } } } - routes = append(routes, RouteInfo{ - Network: r.Network, - TargetAddr: r.Target.ID, + routeInfos = append(routeInfos, RouteInfo{ + Network: rte.Network(), + TargetAddr: rte.Target.ID, RelayAddr: relayAddr, IsRelay: relay, IsConnected: connected, }) } *reply = RouteReply{ - Routes: routes, + Routes: routeInfos, } default: return errors.New("no such action") diff --git a/packages/networking/hyprspace/tun/options.go b/packages/networking/hyprspace/tun/options.go index 046055e..59f6417 100644 --- a/packages/networking/hyprspace/tun/options.go +++ b/packages/networking/hyprspace/tun/options.go @@ -1,5 +1,7 @@ package tun +import "net" + // Option defines a TUN device modifier option. type Option func(tun *TUN) error @@ -26,3 +28,10 @@ func DestAddress(address string) Option { return tun.setDestAddress(address) } } + +// Route adds an entry to the system route table +func Route(dest net.IPNet) Option { + return func(tun *TUN) error { + return tun.addRoute(dest) + } +} diff --git a/packages/networking/hyprspace/tun/tun_linux.go b/packages/networking/hyprspace/tun/tun_linux.go index ed47924..8a91493 100644 --- a/packages/networking/hyprspace/tun/tun_linux.go +++ b/packages/networking/hyprspace/tun/tun_linux.go @@ -5,6 +5,7 @@ package tun import ( "errors" + "net" "github.com/songgao/water" "github.com/vishvananda/netlink" @@ -64,6 +65,18 @@ func (t *TUN) setDestAddress(address string) error { return errors.New("destination addresses are not supported under linux") } +func (t *TUN) addRoute(network net.IPNet) error { + link, err := netlink.LinkByName(t.Iface.Name()) + if err != nil { + return err + } + return netlink.RouteAdd(&netlink.Route{ + LinkIndex: link.Attrs().Index, + Dst: &network, + Priority: 3000, + }) +} + // Up brings up an interface to allow it to start accepting connections. func (t *TUN) Up() error { link, err := netlink.LinkByName(t.Iface.Name())