packages/hyprspace: update config file format, 0.4.1 -> 0.5.0

This commit is contained in:
Max Headroom 2023-01-23 00:34:17 +01:00
parent 2e00712037
commit 2809d3d1e1
7 changed files with 125 additions and 155 deletions

View file

@ -53,7 +53,7 @@ func InitRun(r *cmd.Root, c *cmd.Sub) {
Name: args.InterfaceName, Name: args.InterfaceName,
ListenPort: 8001, ListenPort: 8001,
Address: "10.1.1.1/24", Address: "10.1.1.1/24",
ID: host.ID().Pretty(), ID: host.ID(),
PrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes), PrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes),
}, },
} }

View file

@ -10,7 +10,6 @@ import (
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"runtime"
"strconv" "strconv"
"syscall" "syscall"
"time" "time"
@ -30,14 +29,12 @@ import (
) )
var ( var (
cfg *config.Config
// iface is the tun device used to pass packets between // iface is the tun device used to pass packets between
// Hyprspace and the user's machine. // Hyprspace and the user's machine.
tunDev *tun.TUN 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 is a map of active streams to a peer
activeStreams map[string]network.Stream activeStreams map[peer.ID]network.Stream
// context // context
ctx context.Context ctx context.Context
// context cancel function // context cancel function
@ -76,43 +73,18 @@ func UpRun(r *cmd.Root, c *cmd.Sub) {
} }
// Read in configuration from file. // Read in configuration from file.
cfg, err := config.Read(configPath) cfg2, err := config.Read(configPath)
cfg = cfg2
checkErr(err) 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") fmt.Println("[+] Creating TUN Device")
if runtime.GOOS == "darwin" { // Create new TUN device
if len(cfg.Peers) > 1 { tunDev, err = tun.New(
checkErr(errors.New("cannot create interface macos does not support more than one peer")) cfg.Interface.Name,
} tun.Address(cfg.Interface.Address),
tun.MTU(1420),
// 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),
)
}
if err != nil { if err != nil {
checkErr(err) checkErr(err)
} }
@ -137,23 +109,14 @@ func UpRun(r *cmd.Root, c *cmd.Sub) {
checkErr(err) checkErr(err)
host.SetStreamHandler(p2p.PeXProtocol, p2p.NewPeXStreamHandler(host, cfg)) host.SetStreamHandler(p2p.PeXProtocol, p2p.NewPeXStreamHandler(host, cfg))
for _, id := range cfg.Peers { for _, p := range cfg.Peers {
p, err := peer.Decode(id.ID) host.ConnManager().Protect(p.ID, "/hyprspace/peer")
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)
} }
fmt.Println("[+] Setting Up Node Discovery via DHT") fmt.Println("[+] Setting Up Node Discovery via DHT")
// Setup P2P Discovery // Setup P2P Discovery
go p2p.Discover(ctx, host, dht, peerTable) go p2p.Discover(ctx, host, dht, cfg.Peers)
// Configure path for lock // Configure path for lock
lockPath := filepath.Join(filepath.Dir(cfg.Path), cfg.Interface.Name+".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) go signalHandler(ctx, host, lockPath, dht)
// Log about various events // Log about various events
go eventLogger(ctx, host, cfg) go eventLogger(ctx, host)
// RPC server // RPC server
go hsrpc.RpcServer(ctx, multiaddr.StringCast(fmt.Sprintf("/unix/run/hyprspace-rpc.%s.sock", cfg.Interface.Name)), host, *cfg) 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. // 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) var packet = make([]byte, 1420)
ip, _, err := net.ParseCIDR(cfg.Interface.Address) ip, _, err := net.ParseCIDR(cfg.Interface.Address)
if err != nil { 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]) 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. // Check route table for destination address.
for route, _ := range cfg.Routes { for _, route := range cfg.Routes {
_, network, _ := net.ParseCIDR(route) if route.Network.Contains(dstIP) {
if network.Contains(dstIP) { dst = &route.Target
src := net.IPv4(packet[12], packet[13], packet[14], packet[15]) break
_, 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
}
} }
} }
if dst == nil {
continue
}
// Check if we already have an open connection to the destination peer. // Check if we already have an open connection to the destination peer.
stream, ok := activeStreams[dst] stream, ok := activeStreams[dst.ID]
if ok { if ok {
// Write out the packet's length to the libp2p stream to ensure // Write out the packet's length to the libp2p stream to ensure
// we know the full size of the packet at the other end. // 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 // If we encounter an error when writing to a stream we should
// close that stream and delete it from the active stream map. // close that stream and delete it from the active stream map.
stream.Close() stream.Close()
delete(activeStreams, dst) delete(activeStreams, dst.ID)
} }
// Check if the destination of the packet is a known peer to stream, err = host.NewStream(ctx, dst.ID, p2p.Protocol)
// the interface. if err != nil {
if peer, ok := peerTable[dst]; ok { fmt.Println("[!] Failed to open stream to " + dst.ID.String())
stream, err = host.NewStream(ctx, peer, p2p.Protocol) go p2p.Rediscover()
if err != nil { continue
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.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)) subCon, err := host.EventBus().Subscribe(new(event.EvtPeerConnectednessChanged))
checkErr(err) checkErr(err)
for { for {
@ -315,14 +275,14 @@ func eventLogger(ctx context.Context, host host.Host, cfg *config.Config) {
return return
case ev := <-subCon.Out(): case ev := <-subCon.Out():
evt := ev.(event.EvtPeerConnectednessChanged) evt := ev.(event.EvtPeerConnectednessChanged)
for vpnIp, vpnPeer := range cfg.Peers { for _, vpnPeer := range cfg.Peers {
if vpnPeer.ID == evt.Peer.Pretty() { if vpnPeer.ID == evt.Peer {
if evt.Connectedness == network.Connected { if evt.Connectedness == network.Connected {
for _, c := range host.Network().ConnsToPeer(evt.Peer) { 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 { } else if evt.Connectedness == network.NotConnected {
fmt.Printf("[!] Disconnected from %s\n", vpnIp) fmt.Printf("[!] Disconnected from %s\n", evt.Peer.String())
} }
break break
} }
@ -333,7 +293,7 @@ func eventLogger(ctx context.Context, host host.Host, cfg *config.Config) {
func streamHandler(stream network.Stream) { func streamHandler(stream network.Stream) {
// If the remote node ID isn't in the list of known nodes don't respond. // 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() stream.Reset()
return return
} }

View file

@ -2,36 +2,41 @@ package config
import ( import (
"fmt" "fmt"
"log"
"net" "net"
"os" "os"
"github.com/libp2p/go-libp2p/core/peer"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
// Config is the main Configuration Struct for Hyprspace. // Config is the main Configuration Struct for Hyprspace.
type Config struct { type Config struct {
Path string `yaml:"path,omitempty"` Path string `yaml:"path,omitempty"`
Interface Interface `yaml:"interface"` Interface Interface `yaml:"interface"`
Peers map[string]Peer `yaml:"peers"` Peers []Peer `yaml:"peers"`
Routes map[string]Route `yaml:"routes"` Routes []Route
} }
// Interface defines all of the fields that a local node needs to know about itself! // Interface defines all of the fields that a local node needs to know about itself!
type Interface struct { type Interface struct {
Name string `yaml:"name"` Name string `yaml:"name"`
ID string `yaml:"id"` ID peer.ID `yaml:"id"`
ListenPort int `yaml:"listen_port"` ListenPort int `yaml:"listen_port"`
Address string `yaml:"address"` Address string `yaml:"address"`
PrivateKey string `yaml:"private_key"` PrivateKey string `yaml:"private_key"`
} }
// Peer defines a peer in the configuration. We might add more to this later. // Peer defines a peer in the configuration. We might add more to this later.
type Peer struct { type Peer struct {
ID string `yaml:"id"` ID peer.ID `yaml:"id"`
Routes []Route `yaml:"routes"`
} }
type Route struct { type Route struct {
IP string `yaml:"ip"` Target Peer
NetworkStr string `yaml:"net"`
Network net.IPNet
} }
// Read initializes a config from a file. // Read initializes a config from a file.
@ -56,21 +61,16 @@ func Read(path string) (*Config, error) {
return nil, err return nil, err
} }
// Check peers have valid ip addresses for _, p := range result.Peers {
for ip := range result.Peers { for _, r := range p.Routes {
if net.ParseIP(ip).String() == "<nil>" { r.Target = p
return nil, fmt.Errorf("%s is not a valid ip address", ip) _, n, err := net.ParseCIDR(r.NetworkStr)
} else { if err != nil {
fmt.Printf("[+] Assign this ip: %s to node: %s.\n", ip, result.Peers[ip].ID) log.Fatal("[!] Invalid network:", r.NetworkStr)
} }
} r.Network = *n
result.Routes = append(result.Routes, r)
for route := range result.Routes { fmt.Printf("[+] Route %s via %s\n", r.Network.String(), p.ID.String())
_, _, 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)
} }
} }
@ -78,3 +78,23 @@ func Read(path string) (*Config, error) {
result.Path = path result.Path = path
return &result, nil 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
}

View file

@ -5,16 +5,16 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/hyprspace/hyprspace/config"
dht "github.com/libp2p/go-libp2p-kad-dht" dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
) )
var discoverNow = make(chan bool) var discoverNow = make(chan bool)
// Discover starts up a DHT based discovery system finding and adding nodes with the same rendezvous string. // 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 dur := time.Second * 1
ticker := time.NewTicker(dur) ticker := time.NewTicker(dur)
defer ticker.Stop() 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) ticker.Reset(time.Millisecond * 1)
case <-ticker.C: case <-ticker.C:
connectedToAny := false connectedToAny := false
for _, id := range peerTable { for _, p := range peers {
if h.Network().Connectedness(id) != network.Connected { if h.Network().Connectedness(p.ID) != network.Connected {
addrs, err := dht.FindPeer(ctx, id) addrs, err := dht.FindPeer(ctx, p.ID)
if err != nil { if err != nil {
continue continue
} }

View file

@ -29,12 +29,15 @@ func checkErrPeX(err error, stream network.Stream) bool {
} }
func NewPeXStreamHandler(host host.Host, cfg *config.Config) func(network.Stream) { 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) { 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() stream.Reset()
return return
} }
@ -47,12 +50,8 @@ func NewPeXStreamHandler(host host.Host, cfg *config.Config) func(network.Stream
if str == "r" { if str == "r" {
// peer requests addresses // peer requests addresses
for _, p := range cfg.Peers { for _, p := range cfg.Peers {
peerId, err := peer.Decode(p.ID) if p.ID != stream.Conn().RemotePeer() {
if checkErrPeX(err, stream) { for _, c := range host.Network().ConnsToPeer(p.ID) {
return
}
if peerId != stream.Conn().RemotePeer() {
for _, c := range host.Network().ConnsToPeer(peerId) {
_, err := stream.Write([]byte(fmt.Sprintf("%s|%s\n", c.RemotePeer().String(), c.RemoteMultiaddr().String()))) _, err := stream.Write([]byte(fmt.Sprintf("%s|%s\n", c.RemotePeer().String(), c.RemoteMultiaddr().String())))
if checkErrPeX(err, stream) { if checkErrPeX(err, stream) {
return return
@ -114,17 +113,13 @@ func PeXService(ctx context.Context, host host.Host, cfg *config.Config) {
case ev := <-subCon.Out(): case ev := <-subCon.Out():
evt := ev.(event.EvtPeerConnectednessChanged) evt := ev.(event.EvtPeerConnectednessChanged)
for _, vpnPeer := range cfg.Peers { for _, vpnPeer := range cfg.Peers {
if vpnPeer.ID == evt.Peer.String() { if vpnPeer.ID == evt.Peer {
if evt.Connectedness == network.Connected { if evt.Connectedness == network.Connected {
go RequestPeX(ctx, host, []peer.ID{evt.Peer}) go RequestPeX(ctx, host, []peer.ID{evt.Peer})
} else if evt.Connectedness == network.NotConnected { } else if evt.Connectedness == network.NotConnected {
peers := []peer.ID{} peers := []peer.ID{}
for _, p := range cfg.Peers { for _, p := range cfg.Peers {
peerId, err := peer.Decode(p.ID) peers = append(peers, p.ID)
if err != nil {
continue
}
peers = append(peers, peerId)
} }
go RequestPeX(ctx, host, peers) go RequestPeX(ctx, host, peers)
} }

View file

@ -10,7 +10,7 @@
}; };
packages.hyprspace = with pkgs; buildGo118Module { packages.hyprspace = with pkgs; buildGo118Module {
pname = "hyprspace"; pname = "hyprspace";
version = "0.4.1"; version = "0.5.0";
src = with inputs.nix-filter.lib; let src = with inputs.nix-filter.lib; let
dirs = map inDirectory; dirs = map inDirectory;

View file

@ -11,7 +11,6 @@ import (
"github.com/hyprspace/hyprspace/config" "github.com/hyprspace/hyprspace/config"
"github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
) )
@ -23,15 +22,11 @@ type HyprspaceRPC struct {
func (hsr *HyprspaceRPC) Status(args *Args, reply *StatusReply) error { func (hsr *HyprspaceRPC) Status(args *Args, reply *StatusReply) error {
netPeersCurrent := 0 netPeersCurrent := 0
var netPeerAddrsCurrent []string var netPeerAddrsCurrent []string
for _, id := range hsr.config.Peers { for _, p := range hsr.config.Peers {
peerId, err := peer.Decode(id.ID) if hsr.host.Network().Connectedness(p.ID) == network.Connected {
if err != nil {
return err
}
if hsr.host.Network().Connectedness(peerId) == network.Connected {
netPeersCurrent = netPeersCurrent + 1 netPeersCurrent = netPeersCurrent + 1
for _, c := range hsr.host.Network().ConnsToPeer(peerId) { for _, c := range hsr.host.Network().ConnsToPeer(p.ID) {
netPeerAddrsCurrent = append(netPeerAddrsCurrent, fmt.Sprintf("%s/p2p/%s", c.RemoteMultiaddr().String(), peerId.String())) netPeerAddrsCurrent = append(netPeerAddrsCurrent, fmt.Sprintf("%s/p2p/%s", c.RemoteMultiaddr().String(), p.ID.String()))
} }
} }
} }