Standardize Tun creation and setup process

This commit is contained in:
Alec Scott 2022-01-27 18:56:18 -07:00
parent b1caae2d87
commit f7664f3263
6 changed files with 249 additions and 116 deletions

106
cli/up.go
View File

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

21
tun/options.go Normal file
View File

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

View File

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

72
tun/tun_darwin.go Normal file
View File

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

View File

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

View File

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