Start to dust off Darwin
This commit is contained in:
parent
168ef61a63
commit
258a9223b9
|
@ -2,17 +2,10 @@ package main
|
|||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
/* Daemonizes the process on linux
|
||||
*
|
||||
* This is done by spawning and releasing a copy with the --foreground flag
|
||||
*/
|
||||
func Daemonize(attr *os.ProcAttr) error {
|
||||
// I would like to use os.Executable,
|
||||
// however this means dropping support for Go <1.8
|
||||
path, err := exec.LookPath(os.Args[0])
|
||||
path, err := os.Executable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func Daemonize() error {
|
||||
return errors.New("Not implemented on OSX")
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
/* Daemonizes the process on windows
|
||||
*
|
||||
* This is done by spawning and releasing a copy with the --foreground flag
|
||||
*/
|
||||
|
||||
func Daemonize() error {
|
||||
argv := []string{os.Args[0], "--foreground"}
|
||||
argv = append(argv, os.Args[1:]...)
|
||||
attr := &os.ProcAttr{
|
||||
Dir: ".",
|
||||
Env: os.Environ(),
|
||||
Files: []*os.File{
|
||||
os.Stdin,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
process, err := os.StartProcess(
|
||||
argv[0],
|
||||
argv,
|
||||
attr,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
process.Release()
|
||||
return nil
|
||||
}
|
2
main.go
2
main.go
|
@ -25,6 +25,8 @@ func printUsage() {
|
|||
|
||||
func main() {
|
||||
|
||||
Warning()
|
||||
|
||||
// parse arguments
|
||||
|
||||
var foreground bool
|
||||
|
|
190
tun_darwin.go
190
tun_darwin.go
|
@ -1,22 +1,12 @@
|
|||
/* 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"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -36,26 +26,20 @@ type sockaddrCtl struct {
|
|||
scReserved [5]uint32
|
||||
}
|
||||
|
||||
// NativeTUN is a hack to work around the first 4 bytes "packet
|
||||
// NativeTun 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 NativeTUN struct {
|
||||
type NativeTun struct {
|
||||
name string
|
||||
f io.ReadWriteCloser
|
||||
fd *os.File
|
||||
mtu int
|
||||
|
||||
rMu sync.Mutex
|
||||
rBuf []byte
|
||||
|
||||
wMu sync.Mutex
|
||||
wBuf []byte
|
||||
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
}
|
||||
|
||||
var sockaddrCtlSize uintptr = 32
|
||||
|
||||
func CreateTUN(name string) (ifce TUNDevice, err error) {
|
||||
func CreateTUN(name string) (TUNDevice, error) {
|
||||
ifIndex := -1
|
||||
fmt.Sscanf(name, "utun%d", &ifIndex)
|
||||
if ifIndex < 0 {
|
||||
|
@ -65,7 +49,7 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
|
|||
fd, err := unix.Socket(unix.AF_SYSTEM, unix.SOCK_DGRAM, 2)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error in unix.Socket: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ctlInfo = &struct {
|
||||
|
@ -83,8 +67,7 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
|
|||
)
|
||||
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
return nil, fmt.Errorf("error in unix.Syscall(unix.SYS_IOTL, ...): %v", err)
|
||||
return nil, fmt.Errorf("_CTLIOCGINFO: %v", errno)
|
||||
}
|
||||
|
||||
sc := sockaddrCtl{
|
||||
|
@ -105,148 +88,133 @@ func CreateTUN(name string) (ifce TUNDevice, err error) {
|
|||
)
|
||||
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
return nil, fmt.Errorf("error in unix.RawSyscall(unix.SYS_CONNECT, ...): %v", err)
|
||||
return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
|
||||
}
|
||||
|
||||
// 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)
|
||||
return CreateTUNFromFile(os.NewFile(uintptr(fd), ""))
|
||||
}
|
||||
|
||||
device := &NativeTUN{
|
||||
name: string(ifName.name[:ifNameSize-1 /* -1 is for \0 */]),
|
||||
f: os.NewFile(uintptr(fd), string(ifName.name[:])),
|
||||
func CreateTUNFromFile(file *os.File) (TUNDevice, error) {
|
||||
|
||||
tun := &NativeTun{
|
||||
fd: file,
|
||||
mtu: 1500,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
|
||||
// start listener
|
||||
_, err := tun.Name()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func(native *NativeTUN) {
|
||||
// TODO: Fix this very niave implementation
|
||||
// TODO: Fix this very naive implementation
|
||||
go func(tun *NativeTun) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
)
|
||||
|
||||
for ; ; time.Sleep(time.Second) {
|
||||
intr, err := net.InterfaceByName(device.name)
|
||||
intr, err := net.InterfaceByName(tun.name)
|
||||
if err != nil {
|
||||
native.errors <- err
|
||||
tun.errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
// Up / Down event
|
||||
up := (intr.Flags & net.FlagUp) != 0
|
||||
if up != statusUp && up {
|
||||
native.events <- TUNEventUp
|
||||
tun.events <- TUNEventUp
|
||||
}
|
||||
if up != statusUp && !up {
|
||||
native.events <- TUNEventDown
|
||||
tun.events <- TUNEventDown
|
||||
}
|
||||
statusUp = up
|
||||
|
||||
// MTU changes
|
||||
if intr.MTU != statusMTU {
|
||||
native.events <- TUNEventMTUUpdate
|
||||
tun.events <- TUNEventMTUUpdate
|
||||
}
|
||||
statusMTU = intr.MTU
|
||||
}
|
||||
}(device)
|
||||
}(tun)
|
||||
|
||||
// set default MTU
|
||||
err = tun.setMTU(DefaultMTU)
|
||||
|
||||
err = device.setMTU(DefaultMTU)
|
||||
|
||||
return device, err
|
||||
return tun, err
|
||||
}
|
||||
|
||||
var _ io.ReadWriteCloser = (*NativeTUN)(nil)
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
|
||||
func (t *NativeTUN) Events() chan TUNEvent {
|
||||
return t.events
|
||||
var ifName struct {
|
||||
name [16]byte
|
||||
}
|
||||
ifNameSize := uintptr(16)
|
||||
|
||||
_, _, errno := unix.Syscall6(
|
||||
unix.SYS_GETSOCKOPT,
|
||||
uintptr(tun.fd.Fd()),
|
||||
2, /* #define SYSPROTO_CONTROL 2 */
|
||||
2, /* #define UTUN_OPT_IFNAME 2 */
|
||||
uintptr(unsafe.Pointer(&ifName)),
|
||||
uintptr(unsafe.Pointer(&ifNameSize)), 0)
|
||||
|
||||
if errno != 0 {
|
||||
return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno)
|
||||
}
|
||||
|
||||
func (t *NativeTUN) 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)
|
||||
tun.name = string(ifName.name[:ifNameSize-1])
|
||||
return tun.name, nil
|
||||
}
|
||||
t.rBuf = t.rBuf[:len(to)+4]
|
||||
|
||||
n, err := t.f.Read(t.rBuf)
|
||||
copy(to, t.rBuf[4:])
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.fd
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
|
||||
buff = buff[offset-4:]
|
||||
n, err := tun.fd.Read(buff[:])
|
||||
if n < 4 {
|
||||
return 0, err
|
||||
}
|
||||
return n - 4, err
|
||||
}
|
||||
|
||||
func (t *NativeTUN) Write(from []byte) (int, error) {
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
if len(from) == 0 {
|
||||
return 0, unix.EIO
|
||||
}
|
||||
// reserve space for header
|
||||
|
||||
t.wMu.Lock()
|
||||
defer t.wMu.Unlock()
|
||||
buff = buff[offset-4:]
|
||||
|
||||
if cap(t.wBuf) < len(from)+4 {
|
||||
t.wBuf = make([]byte, len(from)+4)
|
||||
}
|
||||
t.wBuf = t.wBuf[:len(from)+4]
|
||||
// add packet information header
|
||||
|
||||
// determine the IP Family for the NULL L2 Header
|
||||
buff[0] = 0x00
|
||||
buff[1] = 0x00
|
||||
buff[2] = 0x00
|
||||
|
||||
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
|
||||
if buff[4]>>4 == ipv6.Version {
|
||||
buff[3] = unix.AF_INET6
|
||||
} else {
|
||||
return 0, errors.New("Unable to determine IP version from packet.")
|
||||
buff[3] = unix.AF_INET
|
||||
}
|
||||
|
||||
copy(t.wBuf[4:], from)
|
||||
// write
|
||||
|
||||
n, err := t.f.Write(t.wBuf)
|
||||
return n - 4, err
|
||||
return tun.fd.Write(buff)
|
||||
}
|
||||
|
||||
func (t *NativeTUN) 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 (tun *NativeTun) Close() error {
|
||||
return tun.fd.Close()
|
||||
}
|
||||
|
||||
func (t *NativeTUN) Name() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
func (t *NativeTUN) setMTU(n int) error {
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
|
@ -267,7 +235,7 @@ func (t *NativeTUN) setMTU(n int) error {
|
|||
// do ioctl call
|
||||
|
||||
var ifr [32]byte
|
||||
copy(ifr[:], t.name)
|
||||
copy(ifr[:], tun.name)
|
||||
binary.LittleEndian.PutUint32(ifr[16:20], uint32(n))
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
|
@ -277,13 +245,13 @@ func (t *NativeTUN) setMTU(n int) error {
|
|||
)
|
||||
|
||||
if errno != 0 {
|
||||
return fmt.Errorf("Failed to set MTU on %s", t.name)
|
||||
return fmt.Errorf("Failed to set MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *NativeTUN) MTU() (int, error) {
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
|
@ -302,7 +270,7 @@ func (t *NativeTUN) MTU() (int, error) {
|
|||
// do ioctl call
|
||||
|
||||
var ifr [64]byte
|
||||
copy(ifr[:], t.name)
|
||||
copy(ifr[:], tun.name)
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(fd),
|
||||
|
@ -310,7 +278,7 @@ func (t *NativeTUN) MTU() (int, error) {
|
|||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
if errno != 0 {
|
||||
return 0, fmt.Errorf("Failed to get MTU on %s", t.name)
|
||||
return 0, fmt.Errorf("Failed to get MTU on %s", tun.name)
|
||||
}
|
||||
|
||||
// convert result to signed 32-bit int
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
|
@ -44,23 +45,11 @@ func (l *UAPIListener) Addr() net.Addr {
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewUAPIListener(name string) (net.Listener, error) {
|
||||
func UAPIListen(name string, file *os.File) (net.Listener, error) {
|
||||
|
||||
// check if path exist
|
||||
// wrap file in listener
|
||||
|
||||
err := os.MkdirAll(socketDirectory, 077)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// open UNIX socket
|
||||
|
||||
socketPath := path.Join(
|
||||
socketDirectory,
|
||||
fmt.Sprintf(socketName, name),
|
||||
)
|
||||
|
||||
listener, err := net.Listen("unix", socketPath)
|
||||
listener, err := net.FileListener(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -73,6 +62,13 @@ func NewUAPIListener(name string) (net.Listener, error) {
|
|||
|
||||
// watch for deletion of socket
|
||||
|
||||
socketPath := path.Join(
|
||||
socketDirectory,
|
||||
fmt.Sprintf(socketName, name),
|
||||
)
|
||||
|
||||
// watch for deletion of socket
|
||||
|
||||
go func(l *UAPIListener) {
|
||||
for ; ; time.Sleep(time.Second) {
|
||||
if _, err := os.Stat(socketPath); os.IsNotExist(err) {
|
||||
|
@ -97,3 +93,56 @@ func NewUAPIListener(name string) (net.Listener, error) {
|
|||
|
||||
return uapi, nil
|
||||
}
|
||||
|
||||
func UAPIOpen(name string) (*os.File, error) {
|
||||
|
||||
// check if path exist
|
||||
|
||||
err := os.MkdirAll(socketDirectory, 0600)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// open UNIX socket
|
||||
|
||||
socketPath := path.Join(
|
||||
socketDirectory,
|
||||
fmt.Sprintf(socketName, name),
|
||||
)
|
||||
|
||||
addr, err := net.ResolveUnixAddr("unix", socketPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
listener, err := func() (*net.UnixListener, error) {
|
||||
|
||||
// initial connection attempt
|
||||
|
||||
listener, err := net.ListenUnix("unix", addr)
|
||||
if err == nil {
|
||||
return listener, nil
|
||||
}
|
||||
|
||||
// check if socket already active
|
||||
|
||||
_, err = net.Dial("unix", socketPath)
|
||||
if err == nil {
|
||||
return nil, errors.New("unix socket in use")
|
||||
}
|
||||
|
||||
// cleanup & attempt again
|
||||
|
||||
err = os.Remove(socketPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return net.ListenUnix("unix", addr)
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return listener.File()
|
||||
}
|
||||
|
|
19
warning_default.go
Normal file
19
warning_default.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
// +build !linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Warning() {
|
||||
fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
|
||||
fmt.Fprintln(os.Stderr, "W G")
|
||||
fmt.Fprintln(os.Stderr, "W This is alpha software. It will very likely not G")
|
||||
fmt.Fprintln(os.Stderr, "W do what it is supposed to do, and things may go G")
|
||||
fmt.Fprintln(os.Stderr, "W horribly wrong. You have been warned. Proceed G")
|
||||
fmt.Fprintln(os.Stderr, "W at your own risk. G")
|
||||
fmt.Fprintln(os.Stderr, "W G")
|
||||
fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
|
||||
}
|
39
warning_linux.go
Normal file
39
warning_linux.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Warning() {
|
||||
shouldQuit := os.Getenv("WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD") != "1"
|
||||
|
||||
fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
|
||||
fmt.Fprintln(os.Stderr, "W G")
|
||||
fmt.Fprintln(os.Stderr, "W This is alpha software. It will very likely not G")
|
||||
fmt.Fprintln(os.Stderr, "W do what it is supposed to do, and things may go G")
|
||||
fmt.Fprintln(os.Stderr, "W horribly wrong. You have been warned. Proceed G")
|
||||
fmt.Fprintln(os.Stderr, "W at your own risk. G")
|
||||
fmt.Fprintln(os.Stderr, "W G")
|
||||
fmt.Fprintln(os.Stderr, "W Furthermore, you are running this software on a G")
|
||||
fmt.Fprintln(os.Stderr, "W Linux kernel, which is probably unnecessary and G")
|
||||
fmt.Fprintln(os.Stderr, "W foolish. This is because the Linux kernel has G")
|
||||
fmt.Fprintln(os.Stderr, "W built-in first class support for WireGuard, and G")
|
||||
fmt.Fprintln(os.Stderr, "W this support is much more refined than this G")
|
||||
fmt.Fprintln(os.Stderr, "W program. For more information on installing the G")
|
||||
fmt.Fprintln(os.Stderr, "W kernel module, please visit: G")
|
||||
fmt.Fprintln(os.Stderr, "W https://www.wireguard.com/install G")
|
||||
if shouldQuit {
|
||||
fmt.Fprintln(os.Stderr, "W G")
|
||||
fmt.Fprintln(os.Stderr, "W If you still want to use this program, against G")
|
||||
fmt.Fprintln(os.Stderr, "W the sage advice here, please first export this G")
|
||||
fmt.Fprintln(os.Stderr, "W environment variable: G")
|
||||
fmt.Fprintln(os.Stderr, "W WG_I_PREFER_BUGGY_USERSPACE_TO_POLISHED_KMOD=1 G")
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "W G")
|
||||
fmt.Fprintln(os.Stderr, "WARNING WARNING WARNING WARNING WARNING WARNING WARNING")
|
||||
|
||||
if shouldQuit {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue