Skip to content
This repository was archived by the owner on Jan 2, 2024. It is now read-only.
Closed
Prev Previous commit
Next Next commit
Get client working on OSX
  • Loading branch information
twitchyliquid64 committed Aug 1, 2017
commit 832f5860db153a6dda52fe77e69d52cba547665f
64 changes: 61 additions & 3 deletions src/github.com/songgao/water/syscalls_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package water
import (
"errors"
"fmt"
"io"
"os"
"sync"
"syscall"
"unsafe"
)
Expand Down Expand Up @@ -112,12 +114,68 @@ func newTUN(string) (ifce *Interface, err error) {
}

return &Interface{
isTAP: false,
name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
ReadWriteCloser: os.NewFile(uintptr(fd), string(ifName.name[:])),
isTAP: false,
name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
ReadWriteCloser: &tunReadCloser{
f: os.NewFile(uintptr(fd), string(ifName.name[:])),
},
}, nil
}

// tunReadCloser is a hack to work around the first 4 bytes "packet
// information" because there doesn't seem to be an IFF_NO_PI for darwin.
type tunReadCloser struct {
f io.ReadWriteCloser

rMu sync.Mutex
rBuf []byte

wMu sync.Mutex
wBuf []byte
}

var _ io.ReadWriteCloser = (*tunReadCloser)(nil)

func (t *tunReadCloser) Read(to []byte) (int, error) {
t.rMu.Lock()
defer t.rMu.Unlock()

if cap(t.rBuf) < len(to)+4 {
t.rBuf = make([]byte, len(to)+4)
}
t.rBuf = t.rBuf[:len(to)+4]

n, err := t.f.Read(t.rBuf)
copy(to, t.rBuf[4:])
return n - 4, err
}

func (t *tunReadCloser) Write(from []byte) (int, error) {
t.wMu.Lock()
defer t.wMu.Unlock()

if cap(t.wBuf) < len(from)+4 {
t.wBuf = make([]byte, len(from)+4)
}
t.wBuf = t.wBuf[:len(from)+4]

t.wBuf[3] = 2 // Family: IP (2)
copy(t.wBuf[4:], from)

n, err := t.f.Write(t.wBuf)
return n - 4, err
}

func (t *tunReadCloser) Close() error {
// lock to make sure no read/write is in process.
t.rMu.Lock()
defer t.rMu.Unlock()
t.wMu.Lock()
defer t.wMu.Unlock()

return t.f.Close()
}

func newTAP(ifName string) (ifce *Interface, err error) {
return nil, errors.New("tap interface not implemented on this platform")
}
21 changes: 13 additions & 8 deletions src/subnet/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import (

// Client represents a connection to a subnet server.
type Client struct {
newGateway string
serverAddr string
port string
debugMessages bool
newGateway string
serverAddr string
port string

wg sync.WaitGroup
serverIP net.IP
Expand Down Expand Up @@ -67,6 +68,7 @@ func NewClient(servAddr, port, network, iName string, newGateway string,
log.Printf("Created iface %s\n", intf.Name())

ret := &Client{
debugMessages: true,
intf: intf,
newGateway: newGateway,
serverAddr: servAddr,
Expand All @@ -92,7 +94,7 @@ func (c *Client) init(serverAddr, port string) error {
c.tlsConn = tlsConn
c.connectionOk = true

if err := SetDevIP(c.intf.Name(), c.localAddr, c.localNetMask, false); err != nil {
if err := SetDevIP(c.intf.Name(), c.localAddr, c.localNetMask, c.debugMessages); err != nil {
return err
}
log.Printf("IP of %s set to %s, localNetMask %s\n", c.intf.Name(), c.localAddr.String(), net.IP(c.localNetMask.Mask).String())
Expand All @@ -107,7 +109,7 @@ func (c *Client) init(serverAddr, port string) error {
log.Printf("Default gateway is %s on %s\n", gateway, gatewayDevice)

// route all traffic to the VPN server through the current gateway device
if err := AddRoute(c.serverIP, gateway, gatewayDevice, false); err != nil {
if err := AddRoute(c.serverIP, gateway, gatewayDevice, c.debugMessages); err != nil {
return err
}
log.Printf("Traffic to %s now routed via %s on %s.\n", c.serverIP.String(), gw, gatewayDevice)
Expand All @@ -122,14 +124,14 @@ func (c *Client) init(serverAddr, port string) error {
func (c *Client) Run() {

if c.newGateway != "" { //Redirect default traffic via our VPN
err := SetDefaultGateway(c.newGateway, c.intf.Name(), false)
err := SetDefaultGateway(c.newGateway, c.intf.Name(), c.debugMessages)
if err != nil {
log.Printf("Could set gateway: %s\n", err.Error())
return
}
}

err := SetInterfaceStatus(c.intf.Name(), true, false)
err := SetInterfaceStatus(c.intf.Name(), true, c.debugMessages)
if err != nil {
log.Printf("Could not bring up interface %s: %s\n", c.intf.Name(), err.Error())
return
Expand All @@ -153,7 +155,10 @@ func (c *Client) netSendRoutine() {
}

for c.connectionOk && connOK {
pkt := <-c.packetsIn
pkt, ok := <-c.packetsIn
if !ok{
break
}

if pkt.Dest.IsMulticast() { //Don't forward multicast
continue
Expand Down
73 changes: 73 additions & 0 deletions src/subnet/helpers_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package subnet

import (
"errors"
"fmt"
"net"
"os/exec"
"regexp"
"strings"
)

//SetInterfaceStatus brings up or down a network interface.
func SetInterfaceStatus(iName string, up bool, debug bool) error {
statusString := "down"
if up {
statusString = "up"
}

//TODO: Support setting the QLEN
sargs := fmt.Sprintf("%s %s mtu %d", iName, statusString, devMtuSize)
return commandExec("ifconfig", strings.Split(sargs, " "), debug)}

//SetDevIP sets the local IP address of a network interface.
func SetDevIP(iName string, localAddr net.IP, addr *net.IPNet, debug bool) error {
sargs := fmt.Sprintf("set %s MANUAL %s 0x%s", iName, localAddr.String(), addr.Mask)
return commandExec("ipconfig", strings.Split(sargs, " "), debug)
}

// SetDefaultGateway sets the systems gateway to the IP / device specified.
func SetDefaultGateway(gw, iName string, debug bool) error {
sargs := fmt.Sprintf("-n change default %s -interface %s", gw, iName)
args := strings.Split(sargs, " ")
return commandExec("route", args, debug)
}

// AddRoute routes all traffic for addr via interface iName.
func AddRoute(addr, viaAddr net.IP, iName string, debug bool) error {
sargs := fmt.Sprintf("-n add %s %s -interface %s", addr.String(), viaAddr.String(), iName)
args := strings.Split(sargs, " ")
return commandExec("route", args, debug)
}

// DelRoute deletes the route in the system routing table to a specific destination.
func DelRoute(addr, viaAddr net.IP, iName string, debug bool) error {
sargs := fmt.Sprintf("-n delete %s %s -interface %s", addr.String(), viaAddr.String(), iName)
args := strings.Split(sargs, " ")
return commandExec("route", args, debug)
}

var parseRouteGetRegex = regexp.MustCompile(`(?m)^\W*([^\:]+):\W(.*)$`)

// GetNetGateway return net gateway (default route) and nic.
func GetNetGateway() (gw, dev string, err error) {
cmd := exec.Command("route", "-n", "get", "default")
output, e := cmd.Output()
if e != nil {
return "", "", e
}

matches := parseRouteGetRegex.FindAllSubmatch(output, -1)
defaultRouteInfo := map[string]string{}
for _, match := range matches {
defaultRouteInfo[string(match[1])] = string(match[2])
}

_, gatewayExists := defaultRouteInfo["gateway"]
_, interfaceExists := defaultRouteInfo["interface"]
if !gatewayExists || !interfaceExists {
return "", "", errors.New("internal error: could not read gateway or interface")
}

return defaultRouteInfo["gateway"], defaultRouteInfo["interface"], nil
}
16 changes: 16 additions & 0 deletions src/subnet/net_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package subnet

import (
"testing"
)

func TestNet(t *testing.T) {
gw, device, err := GetNetGateway()
if err != nil {
t.Fatal(err)
}
if len(device) < 2 || len(gw) < 3 {
t.Error(gw, device)
t.Fatal("Expected longer results for device and interface")
}
}
2 changes: 1 addition & 1 deletion src/subnet/reverser.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (r *Reverser) AddRouteEntry(destination net.IP, via net.IP, dev string) {
// to system configuration.
func (r *Reverser) Close() {
for _, route := range r.RouteDeletions {
e := DelRoute(route.dest, route.via, route.dev, false)
e := DelRoute(route.dest, route.via, route.dev, true)
if e == nil {
log.Printf("Deleted route to %s via %s on %s\n", route.dest.String(), route.via.String(), route.dev)
} else {
Expand Down
14 changes: 14 additions & 0 deletions src/subnet/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package subnet
import (
"errors"
"math/rand"
"log"
"net"
"os/exec"
"time"
)

Expand All @@ -19,3 +21,15 @@ func hostToIP(addr string) (net.IP, error) {
rand.Seed(time.Now().Unix())
return addrs[rand.Int()%len(addrs)], nil
}

func commandExec(command string, args []string, debug bool) error {
cmd := exec.Command(command, args...)
if debug {
log.Println("exec "+command+": ", args)
}
e := cmd.Run()
if e != nil {
log.Println("Command failed: ", e)
}
return e
}