summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorMathias Hall-Andersen <mathias@hall-andersen.dk>2017-07-27 23:46:01 +0200
committerMathias Hall-Andersen <mathias@hall-andersen.dk>2017-07-27 23:46:01 +0200
commit92135131a7e87b9e078d32f4128bef1698132936 (patch)
treeae9dfe5243aa22a2f26e3b7baf346f7322551611 /src
parentfb3fa4f9158458654281129f44f354a65741aef3 (diff)
parentc3d9ae402d431b7697686dbaf021f879c8ccab36 (diff)
Merge branch 'master' of git.zx2c4.com:wireguard-go
Diffstat (limited to 'src')
-rw-r--r--src/config.go38
-rw-r--r--src/daemon_darwin.go9
-rw-r--r--src/tun_darwin.go278
-rw-r--r--src/uapi_darwin.go77
4 files changed, 380 insertions, 22 deletions
diff --git a/src/config.go b/src/config.go
index 509da58..9751a18 100644
--- a/src/config.go
+++ b/src/config.go
@@ -2,7 +2,6 @@ package main
import (
"bufio"
- "errors"
"fmt"
"io"
"net"
@@ -110,12 +109,10 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
/* interface configuration */
case "private_key":
+ var sk NoisePrivateKey
if value == "" {
- device.mutex.Lock()
- device.privateKey = NoisePrivateKey{}
- device.mutex.Unlock()
+ device.SetPrivateKey(sk)
} else {
- var sk NoisePrivateKey
err := sk.FromHex(value)
if err != nil {
logError.Println("Failed to set private_key:", err)
@@ -125,16 +122,21 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
}
case "listen_port":
- var port int
- _, err := fmt.Sscanf(value, "%d", &port)
- if err != nil || port > (1<<16) || port < 0 {
+ port, err := strconv.ParseUint(value, 10, 16)
+ if err != nil {
logError.Println("Failed to set listen_port:", err)
return &IPCError{Code: ipcErrorInvalidValue}
}
- device.net.mutex.Lock()
- device.net.addr.Port = port
- device.net.conn, err = net.ListenUDP("udp", device.net.addr)
- device.net.mutex.Unlock()
+ netc := &device.net
+ netc.mutex.Lock()
+ if netc.addr.Port != int(port) {
+ if netc.conn != nil {
+ netc.conn.Close()
+ }
+ netc.addr.Port = int(port)
+ netc.conn, err = net.ListenUDP("udp", netc.addr)
+ }
+ netc.mutex.Unlock()
if err != nil {
logError.Println("Failed to create UDP listener:", err)
return &IPCError{Code: ipcErrorInvalidValue}
@@ -151,15 +153,10 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
return &IPCError{Code: ipcErrorInvalidValue}
}
device.mutex.RLock()
- found, ok := device.peers[pubKey]
+ peer, _ := device.peers[pubKey]
device.mutex.RUnlock()
- if ok {
- peer = found
- } else {
- peer = device.NewPeer(pubKey)
- }
if peer == nil {
- panic(errors.New("bug: failed to find / create peer"))
+ peer = device.NewPeer(pubKey)
}
case "replace_peers":
@@ -182,9 +179,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
switch key {
case "remove":
- peer.mutex.Lock()
device.RemovePeer(peer.handshake.remoteStatic)
- peer.mutex.Unlock()
logDebug.Println("Removing", peer.String())
peer = nil
@@ -235,7 +230,6 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
return &IPCError{Code: ipcErrorInvalidValue}
}
ones, _ := network.Mask.Size()
- logError.Println(network, ones, network.IP)
device.routingTable.Insert(network.IP, uint(ones), peer)
default:
diff --git a/src/daemon_darwin.go b/src/daemon_darwin.go
new file mode 100644
index 0000000..913af0e
--- /dev/null
+++ b/src/daemon_darwin.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "errors"
+)
+
+func Daemonize() error {
+ return errors.New("Not implemented on OSX")
+}
diff --git a/src/tun_darwin.go b/src/tun_darwin.go
new file mode 100644
index 0000000..146817d
--- /dev/null
+++ b/src/tun_darwin.go
@@ -0,0 +1,278 @@
+/* Copyright (c) 2016, Song Gao <song@gao.io>
+ * All rights reserved.
+ *
+ * Code from https://github.com/songgao/water
+ */
+
+package main
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "golang.org/x/net/ipv4"
+ "golang.org/x/net/ipv6"
+ "golang.org/x/sys/unix"
+ "io"
+ "os"
+ "sync"
+ "unsafe"
+)
+
+const utunControlName = "com.apple.net.utun_control"
+
+// _CTLIOCGINFO value derived from /usr/include/sys/{kern_control,ioccom}.h
+const _CTLIOCGINFO = (0x40000000 | 0x80000000) | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3
+
+// sockaddr_ctl specifeid in /usr/include/sys/kern_control.h
+type sockaddrCtl struct {
+ scLen uint8
+ scFamily uint8
+ ssSysaddr uint16
+ scID uint32
+ scUnit uint32
+ scReserved [5]uint32
+}
+
+var sockaddrCtlSize uintptr = 32
+
+func CreateTUN(name string) (ifce TUNDevice, err error) {
+ ifIndex := -1
+ fmt.Sscanf(name, "utun%d", &ifIndex)
+ if ifIndex < 0 {
+ return nil, fmt.Errorf("error parsing interface name %s, must be utun[0-9]+", name)
+ }
+
+ fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2)
+
+ if err != nil {
+ return nil, fmt.Errorf("error in unix.Socket: %v", err)
+ }
+
+ var ctlInfo = &struct {
+ ctlID uint32
+ ctlName [96]byte
+ }{}
+
+ copy(ctlInfo.ctlName[:], []byte(utunControlName))
+
+ _, _, errno := unix.Syscall(
+ unix.SYS_IOCTL,
+ uintptr(fd),
+ uintptr(_CTLIOCGINFO),
+ uintptr(unsafe.Pointer(ctlInfo)),
+ )
+
+ if errno != 0 {
+ err = errno
+ return nil, fmt.Errorf("error in unix.Syscall(unix.SYS_IOTL, ...): %v", err)
+ }
+
+ sc := sockaddrCtl{
+ scLen: uint8(sockaddrCtlSize),
+ scFamily: unix.AF_SYSTEM,
+ ssSysaddr: 2,
+ scID: ctlInfo.ctlID,
+ scUnit: uint32(ifIndex) + 1,
+ }
+
+ scPointer := unsafe.Pointer(&sc)
+
+ _, _, errno = unix.RawSyscall(
+ unix.SYS_CONNECT,
+ uintptr(fd),
+ uintptr(scPointer),
+ uintptr(sockaddrCtlSize),
+ )
+
+ if errno != 0 {
+ err = errno
+ return nil, fmt.Errorf("error in unix.RawSyscall(unix.SYS_CONNECT, ...): %v", err)
+ }
+
+ // read (new) name of interface
+
+ var ifName struct {
+ name [16]byte
+ }
+ ifNameSize := uintptr(16)
+
+ _, _, errno = unix.Syscall6(
+ unix.SYS_GETSOCKOPT,
+ uintptr(fd),
+ 2, /* #define SYSPROTO_CONTROL 2 */
+ 2, /* #define UTUN_OPT_IFNAME 2 */
+ uintptr(unsafe.Pointer(&ifName)),
+ uintptr(unsafe.Pointer(&ifNameSize)), 0)
+
+ if errno != 0 {
+ err = errno
+ return nil, fmt.Errorf("error in unix.Syscall6(unix.SYS_GETSOCKOPT, ...): %v", err)
+ }
+
+ device := &tunReadCloser{
+ name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
+ f: os.NewFile(uintptr(fd), string(ifName.name[:])),
+ mtu: 1500,
+ }
+
+ // set default MTU
+
+ err = device.setMTU(DefaultMTU)
+
+ return device, err
+}
+
+// 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 {
+ name string
+ f io.ReadWriteCloser
+ mtu int
+
+ 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) {
+
+ if len(from) == 0 {
+ return 0, unix.EIO
+ }
+
+ 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]
+
+ // determine the IP Family for the NULL L2 Header
+
+ ipVer := from[0] >> 4
+ if ipVer == ipv4.Version {
+ t.wBuf[3] = unix.AF_INET
+ } else if ipVer == ipv6.Version {
+ t.wBuf[3] = unix.AF_INET6
+ } else {
+ return 0, errors.New("Unable to determine IP version from packet.")
+ }
+
+ 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 (t *tunReadCloser) Name() string {
+ return t.name
+}
+
+func (t *tunReadCloser) setMTU(n int) error {
+
+ // open datagram socket
+
+ var fd int
+
+ fd, err := unix.Socket(
+ unix.AF_INET,
+ unix.SOCK_DGRAM,
+ 0,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ defer unix.Close(fd)
+
+ // do ioctl call
+
+ var ifr [32]byte
+ copy(ifr[:], t.name)
+ binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
+ _, _, errno := unix.Syscall(
+ unix.SYS_IOCTL,
+ uintptr(fd),
+ uintptr(unix.SIOCSIFMTU),
+ uintptr(unsafe.Pointer(&ifr[0])),
+ )
+
+ if errno != 0 {
+ return fmt.Errorf("Failed to set MTU on %s", t.name)
+ }
+
+ return nil
+}
+
+func (t *tunReadCloser) MTU() (int, error) {
+
+ // open datagram socket
+
+ fd, err := unix.Socket(
+ unix.AF_INET,
+ unix.SOCK_DGRAM,
+ 0,
+ )
+
+ if err != nil {
+ return 0, err
+ }
+
+ defer unix.Close(fd)
+
+ // do ioctl call
+
+ var ifr [64]byte
+ copy(ifr[:], t.name)
+ _, _, errno := unix.Syscall(
+ unix.SYS_IOCTL,
+ uintptr(fd),
+ uintptr(unix.SIOCGIFMTU),
+ uintptr(unsafe.Pointer(&ifr[0])),
+ )
+ if errno != 0 {
+ return 0, fmt.Errorf("Failed to get MTU on %s", t.name)
+ }
+
+ // convert result to signed 32-bit int
+
+ val := binary.LittleEndian.Uint32(ifr[16:20])
+ if val >= (1 << 31) {
+ return int(val-(1<<31)) - (1 << 31), nil
+ }
+ return int(val), nil
+}
diff --git a/src/uapi_darwin.go b/src/uapi_darwin.go
new file mode 100644
index 0000000..9eee53c
--- /dev/null
+++ b/src/uapi_darwin.go
@@ -0,0 +1,77 @@
+package main
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "time"
+)
+
+type UAPIListener struct {
+ listener net.Listener // unix socket listener
+ connNew chan net.Conn
+ connErr chan error
+}
+
+func (l *UAPIListener) Accept() (net.Conn, error) {
+ for {
+ select {
+ case conn := <-l.connNew:
+ return conn, nil
+
+ case err := <-l.connErr:
+ return nil, err
+ }
+ }
+}
+
+func (l *UAPIListener) Close() error {
+ return l.listener.Close()
+}
+
+func (l *UAPIListener) Addr() net.Addr {
+ return nil
+}
+
+func NewUAPIListener(name string) (net.Listener, error) {
+
+ // open UNIX socket
+
+ socketPath := fmt.Sprintf("/var/run/wireguard/%s.sock", name)
+ listener, err := net.Listen("unix", socketPath)
+ if err != nil {
+ return nil, err
+ }
+
+ uapi := &UAPIListener{
+ listener: listener,
+ connNew: make(chan net.Conn, 1),
+ connErr: make(chan error, 1),
+ }
+
+ // watch for deletion of socket
+
+ go func(l *UAPIListener) {
+ for ; ; time.Sleep(time.Second) {
+ if _, err := os.Stat(socketPath); os.IsNotExist(err) {
+ l.connErr <- err
+ return
+ }
+ }
+ }(uapi)
+
+ // watch for new connections
+
+ go func(l *UAPIListener) {
+ for {
+ conn, err := l.listener.Accept()
+ if err != nil {
+ l.connErr <- err
+ break
+ }
+ l.connNew <- conn
+ }
+ }(uapi)
+
+ return uapi, nil
+}