diff --git a/cli/up.go b/cli/up.go index 2fa0a5e..b8a27ea 100644 --- a/cli/up.go +++ b/cli/up.go @@ -10,6 +10,7 @@ import ( "net" "os" "os/signal" + "runtime" "strconv" "strings" "syscall" @@ -22,14 +23,13 @@ import ( "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" - "github.com/songgao/water" "golang.org/x/net/ipv4" ) var ( // iface is the tun device used to pass packets between // Hyprspace and the user's machine. - iface *water.Interface + tunDev *tun.TUN // RevLookup allow quick lookups of an incoming stream // for security before accepting or responding to any data. RevLookup map[string]bool @@ -97,15 +97,36 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { } fmt.Println("[+] Creating TUN Device") - // Create new TUN device - iface, err = tun.New(cfg.Interface.Name, cfg.Interface.Address) - if err != nil { - checkErr(errors.New("interface already in use")) + + 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), + ) + } + if err != nil { + checkErr(err) } - // Set TUN MTU - tun.SetMTU(cfg.Interface.Name, 1420) - // Add Address to Interface - tun.SetAddress(cfg.Interface.Name, cfg.Interface.Address) // Setup System Context ctx := context.Background() @@ -113,34 +134,16 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { fmt.Println("[+] Creating LibP2P Node") // Check that the listener port is available. - var ln net.Listener - port := cfg.Interface.ListenPort - if port != 8001 { - ln, err = net.Listen("tcp", ":"+strconv.Itoa(port)) - if err != nil { - checkErr(errors.New("could not create node, listen port already in use by something else")) - } - } else { - for { - ln, err = net.Listen("tcp", ":"+strconv.Itoa(port)) - if err == nil { - break - } - if port >= 65535 { - checkErr(errors.New("failed to find open port")) - } - port++ - } - } - if ln != nil { - ln.Close() - } + port, err := verifyPort(cfg.Interface.ListenPort) + checkErr(err) // Create P2P Node - host, dht, err := p2p.CreateNode(ctx, + host, dht, err := p2p.CreateNode( + ctx, cfg.Interface.PrivateKey, port, - streamHandler) + streamHandler, + ) checkErr(err) // Setup Peer Table for Quick Packet --> Dest ID lookup @@ -170,7 +173,10 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { }() // Bring Up TUN Device - tun.Up(cfg.Interface.Name) + err = tunDev.Up() + if err != nil { + checkErr(errors.New("unable to bring up tun device")) + } fmt.Println("[+] Network Setup Complete...Waiting on Node Discovery") // Listen For New Packets on TUN Interface @@ -179,7 +185,7 @@ func UpRun(r *cmd.Root, c *cmd.Sub) { var header *ipv4.Header var plen int for { - plen, err = iface.Read(packet) + plen, err = tunDev.Iface.Read(packet) checkErr(err) header, _ = ipv4.ParseHeader(packet) _, ok := cfg.Peers[header.Dst.String()] @@ -231,7 +237,7 @@ func streamHandler(stream network.Stream) { if _, ok := RevLookup[stream.Conn().RemotePeer().Pretty()]; !ok { stream.Reset() } - io.Copy(iface.ReadWriteCloser, stream) + io.Copy(tunDev.Iface.ReadWriteCloser, stream) stream.Close() } @@ -256,3 +262,29 @@ func prettyDiscovery(ctx context.Context, node host.Host, peerTable map[string]p } } } + +func verifyPort(port int) (int, error) { + var ln net.Listener + var err error + 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 { + 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/tun/options.go b/tun/options.go new file mode 100644 index 0000000..39011ec --- /dev/null +++ b/tun/options.go @@ -0,0 +1,21 @@ +package tun + +type Option func(tun *TUN) error + +func Address(address string) Option { + return func(tun *TUN) error { + return tun.setAddress(address) + } +} + +func MTU(mtu int) Option { + return func(tun *TUN) error { + return tun.setMTU(mtu) + } +} + +func DestAddress(address string) Option { + return func(tun *TUN) error { + return tun.setDestAddress(address) + } +} diff --git a/tun/tun.go b/tun/tun.go index 3524986..81510e1 100644 --- a/tun/tun.go +++ b/tun/tun.go @@ -1,55 +1,21 @@ -//go:build !windows && !linux -// +build !windows,!linux - package tun -import ( - "fmt" - "os/exec" +import "github.com/songgao/water" - "github.com/songgao/water" -) +type TUN struct { + Iface *water.Interface + Src string + Dst string +} -// New creates and returns a new TUN interface for the application. -func New(name, address string) (result *water.Interface, err error) { - // Setup TUN Config - cfg := water.Config{ - DeviceType: water.TUN, +func (t *TUN) Apply(opts ...Option) error { + for _, opt := range opts { + if opt == nil { + continue + } + if err := opt(t); err != nil { + return err + } } - cfg.Name = name - // Create TUN Interface - result, err = water.New(cfg) - return -} - -// SetMTU sets the Maximum Tansmission Unit Size for a -// Packet on the interface. -func SetMTU(name string, mtu int) (err error) { - return ip("link", "set", "dev", name, "mtu", fmt.Sprintf("%d", mtu)) -} - -// SetAddress sets the interface's known address and subnet. -func SetAddress(name string, address string) (err error) { - return ip("addr", "add", address, "dev", name) -} - -// Up brings up an interface to allow it to start accepting connections. -func Up(name string) (err error) { - return ip("link", "set", "dev", name, "up") -} - -// Down brings down an interface stopping active connections. -func Down(name string) (err error) { - return ip("link", "set", "dev", name, "down") -} - -// Delete removes a TUN device from the host. -func Delete(name string) (err error) { - return ip("link", "delete", "dev", name) -} - -func ip(args ...string) (err error) { - cmd := exec.Command("ip", args...) - err = cmd.Run() - return + return nil } diff --git a/tun/tun_darwin.go b/tun/tun_darwin.go new file mode 100644 index 0000000..217a0a6 --- /dev/null +++ b/tun/tun_darwin.go @@ -0,0 +1,72 @@ +//go:build darwin +// +build darwin + +package tun + +import ( + "fmt" + "os/exec" + + "github.com/songgao/water" +) + +// New creates and returns a new TUN interface for the application. +func New(name string, opts ...Option) (*TUN, error) { + // Setup TUN Config + cfg := water.Config{ + DeviceType: water.TUN, + } + + // Create Water Interface + iface, err := water.New(cfg) + if err != nil { + return nil, err + } + + // Create TUN result struct + result := TUN{ + Iface: iface, + } + + // Apply options to set TUN config values + err = result.Apply(opts...) + return &result, err +} + +// SetMTU sets the Maximum Tansmission Unit Size for a +// Packet on the interface. +func (t *TUN) setMTU(mtu int) error { + return ifconfig(t.Iface.Name(), "mtu", fmt.Sprintf("%d", mtu)) +} + +// SetDestAddress sets the interface's address. +func (t *TUN) setAddress(address string) error { + t.Src = address + return nil +} + +// SetDestAddress sets the interface's address. +func (t *TUN) setDestAddress(address string) error { + t.Dst = address + return nil +} + +// Up brings up an interface to allow it to start accepting connections. +func (t *TUN) Up() error { + return ifconfig(t.Iface.Name(), "inet", t.Src, t.Dst, "up") +} + +// Down brings down an interface stopping active connections. +func (t *TUN) Down() error { + return ifconfig(t.Iface.Name(), "down") +} + +// Delete removes a TUN device from the host. +func Delete(name string) error { + return fmt.Errorf("removing an interface is unsupported under mac") +} + +func ifconfig(args ...string) error { + cmd := exec.Command("ifconfig", args...) + return cmd.Run() +} diff --git a/tun/tun_linux.go b/tun/tun_linux.go index b2d1b02..ed47924 100644 --- a/tun/tun_linux.go +++ b/tun/tun_linux.go @@ -4,48 +4,69 @@ package tun import ( + "errors" + "github.com/songgao/water" "github.com/vishvananda/netlink" ) // New creates and returns a new TUN interface for the application. -func New(name, address string) (result *water.Interface, err error) { +func New(name string, opts ...Option) (*TUN, error) { // Setup TUN Config cfg := water.Config{ DeviceType: water.TUN, } cfg.Name = name - // Create TUN Interface - result, err = water.New(cfg) - return + + // Create Water Interface + iface, err := water.New(cfg) + if err != nil { + return nil, err + } + + // Create TUN result struct + result := TUN{ + Iface: iface, + } + + // Apply options to set TUN config values + err = result.Apply(opts...) + return &result, err } -// SetMTU sets the Maximum Tansmission Unit Size for a +// setMTU sets the Maximum Tansmission Unit Size for a // Packet on the interface. -func SetMTU(name string, mtu int) error { - link, err := netlink.LinkByName(name) +func (t *TUN) setMTU(mtu int) error { + link, err := netlink.LinkByName(t.Iface.Name()) if err != nil { return err } return netlink.LinkSetMTU(link, mtu) } -// SetAddress sets the interface's known address and subnet. -func SetAddress(name string, address string) error { +// setDestAddress sets the interface's destination address and subnet. +func (t *TUN) setAddress(address string) error { addr, err := netlink.ParseAddr(address) if err != nil { return err } - link, err := netlink.LinkByName(name) + link, err := netlink.LinkByName(t.Iface.Name()) if err != nil { return err } return netlink.AddrAdd(link, addr) } +// SetDestAddress isn't supported under Linux. +// You should instead use set address to set the interface to handle +// all addresses within a subnet. +func (t *TUN) setDestAddress(address string) error { + return errors.New("destination addresses are not supported under linux") +} + // Up brings up an interface to allow it to start accepting connections. -func Up(name string) error { - link, err := netlink.LinkByName(name) +func (t *TUN) Up() error { + link, err := netlink.LinkByName(t.Iface.Name()) if err != nil { return err } @@ -53,8 +74,8 @@ func Up(name string) error { } // Down brings down an interface stopping active connections. -func Down(name string) error { - link, err := netlink.LinkByName(name) +func (t *TUN) Down() error { + link, err := netlink.LinkByName(t.Iface.Name()) if err != nil { return err } diff --git a/tun/tun_windows.go b/tun/tun_windows.go index 3d1c78a..b12b583 100644 --- a/tun/tun_windows.go +++ b/tun/tun_windows.go @@ -12,7 +12,7 @@ import ( ) // New creates and returns a new TUN interface for the application. -func New(name, address string) (result *water.Interface, err error) { +func New(name string, opts ...Option) (*TUN, error) { // TUN on Windows requires address and network to be set on device creation stage // We also set network to 0.0.0.0/0 so we able to reach networks behind the node // https://github.com/songgao/water/blob/master/params_windows.go @@ -21,10 +21,12 @@ func New(name, address string) (result *water.Interface, err error) { if err != nil { return nil, err } + network := net.IPNet{ IP: ip, Mask: net.IPv4Mask(0, 0, 0, 0), } + // Setup TUN Config cfg := water.Config{ DeviceType: water.TUN, @@ -34,35 +36,54 @@ func New(name, address string) (result *water.Interface, err error) { Network: network.String(), }, } - // Create TUN Interface - result, err = water.New(cfg) - return + + // Create Water Interface + iface, err := water.New(cfg) + if err != nil { + return nil, err + } + + // Create TUN result struct + result := TUN{ + Iface: iface, + } + + // Apply options to set TUN config values + err = result.Apply(opts...) + return &result, err } -// SetMTU sets the Maximum Tansmission Unit Size for a +// setMTU sets the Maximum Tansmission Unit Size for a // Packet on the interface. -func SetMTU(name string, mtu int) (err error) { - return netsh("interface", "ipv4", "set", "subinterface", name, "mtu=", fmt.Sprintf("%d", mtu)) +func (t *TUN) setMTU(mtu int) error { + return netsh("interface", "ipv4", "set", "subinterface", t.Iface.Name(), "mtu=", fmt.Sprintf("%d", mtu)) } -// SetAddress sets the interface's known address and subnet. -func SetAddress(name string, address string) (err error) { - return netsh("interface", "ip", "set", "address", "name=", name, "static", address) +// setAddress sets the interface's destination address and subnet. +func (t *TUN) setAddress(address string) error { + return netsh("interface", "ip", "set", "address", "name=", t.Iface.Name(), "static", address) +} + +// SetDestAddress isn't supported under Windows. +// You should instead use set address to set the interface to handle +// all addresses within a subnet. +func (t *TUN) setDestAddress(address string) error { + return errors.New("destination addresses are not supported under windows") } // Up brings up an interface to allow it to start accepting connections. -func Up(name string) (err error) { - return +func (t *TUN) Up() error { + return nil } // Down brings down an interface stopping active connections. -func Down(name string) (err error) { - return +func (t *TUN) Down() error { + return nil } // Delete removes a TUN device from the host. -func Delete(name string) (err error) { - return +func Delete(name string) error { + return nil } func netsh(args ...string) (err error) {