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,
ListenPort: 8001,
Address: "10.1.1.1/24",
ID: host.ID().Pretty(),
ID: host.ID(),
PrivateKey: multibase.MustNewEncoder(multibase.Base58BTC).Encode(keyBytes),
},
}

View file

@ -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
}

View file

@ -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() == "<nil>" {
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
}

View file

@ -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
}

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) {
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)
}

View file

@ -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;

View file

@ -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()))
}
}
}