From b8e85267cf22528a96cefba5f86bac5958ce0c58 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 3 Mar 2019 05:01:06 +0100 Subject: [PATCH] boundif: introduce API for socket binding --- device/boundif_android.go | 34 ++++++++++++++++++++++++ device/boundif_darwin.go | 44 ++++++++++++++++++++++++++++++ device/boundif_windows.go | 56 +++++++++++++++++++++++++++++++++++++++ device/conn_default.go | 14 +++++----- device/conn_linux.go | 20 +++++++------- device/mark_default.go | 2 +- device/mark_unix.go | 2 +- device/peer.go | 4 +-- 8 files changed, 155 insertions(+), 21 deletions(-) create mode 100644 device/boundif_android.go create mode 100644 device/boundif_darwin.go create mode 100644 device/boundif_windows.go diff --git a/device/boundif_android.go b/device/boundif_android.go new file mode 100644 index 0000000..ecc9331 --- /dev/null +++ b/device/boundif_android.go @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package device + +func (device *Device) PeekLookAtSocketFd4() (fd int, err error) { + sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn() + if err != nil { + return + } + err = sysconn.Control(func(f uintptr) { + fd = int(f) + }) + if err != nil { + return + } + return +} + +func (device *Device) PeekLookAtSocketFd6() (fd int, err error) { + sysconn, err := device.net.bind.(*nativeBind).ipv6.SyscallConn() + if err != nil { + return + } + err = sysconn.Control(func(f uintptr) { + fd = int(f) + }) + if err != nil { + return + } + return +} diff --git a/device/boundif_darwin.go b/device/boundif_darwin.go new file mode 100644 index 0000000..b3d10ba --- /dev/null +++ b/device/boundif_darwin.go @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package device + +import ( + "golang.org/x/sys/unix" +) + +func (device *Device) BindSocketToInterface4(interfaceIndex uint32) error { + sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn() + if err != nil { + return nil + } + err2 := sysconn.Control(func(fd uintptr) { + err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, int(interfaceIndex)) + }) + if err2 != nil { + return err2 + } + if err != nil { + return err + } + return nil +} + +func (device *Device) BindSocketToInterface6(interfaceIndex uint32) error { + sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn() + if err != nil { + return nil + } + err2 := sysconn.Control(func(fd uintptr) { + err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, int(interfaceIndex)) + }) + if err2 != nil { + return err2 + } + if err != nil { + return err + } + return nil +} \ No newline at end of file diff --git a/device/boundif_windows.go b/device/boundif_windows.go new file mode 100644 index 0000000..00631cb --- /dev/null +++ b/device/boundif_windows.go @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package device + +import ( + "encoding/binary" + "golang.org/x/sys/windows" + "unsafe" +) + +const ( + sockoptIP_UNICAST_IF = 31 + sockoptIPV6_UNICAST_IF = 31 +) + +func (device *Device) BindSocketToInterface4(interfaceIndex uint32) error { + /* MSDN says for IPv4 this needs to be in net byte order, so that it's like an IP address with leading zeros. */ + bytes := make([]byte, 4) + binary.BigEndian.PutUint32(bytes, interfaceIndex) + interfaceIndex = *(*uint32)(unsafe.Pointer(&bytes[0])) + + sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn() + if err != nil { + return err + } + err2 := sysconn.Control(func(fd uintptr) { + err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, sockoptIP_UNICAST_IF, int(interfaceIndex)) + }) + if err2 != nil { + return err2 + } + if err != nil { + return err + } + return nil +} + +func (device *Device) BindSocketToInterface6(interfaceIndex uint32) error { + sysconn, err := device.net.bind.(*nativeBind).ipv6.SyscallConn() + if err != nil { + return err + } + err2 := sysconn.Control(func(fd uintptr) { + err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, sockoptIPV6_UNICAST_IF, int(interfaceIndex)) + }) + if err2 != nil { + return err2 + } + if err != nil { + return err + } + return nil +} \ No newline at end of file diff --git a/device/conn_default.go b/device/conn_default.go index 8a86719..820bb96 100644 --- a/device/conn_default.go +++ b/device/conn_default.go @@ -20,14 +20,14 @@ import ( * See conn_linux.go for an implementation on the linux platform. */ -type NativeBind struct { +type nativeBind struct { ipv4 *net.UDPConn ipv6 *net.UDPConn } type NativeEndpoint net.UDPAddr -var _ Bind = (*NativeBind)(nil) +var _ Bind = (*nativeBind)(nil) var _ Endpoint = (*NativeEndpoint)(nil) func CreateEndpoint(s string) (Endpoint, error) { @@ -100,7 +100,7 @@ func extractErrno(err error) error { func CreateBind(uport uint16, device *Device) (Bind, uint16, error) { var err error - var bind NativeBind + var bind nativeBind port := int(uport) @@ -119,7 +119,7 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) { return &bind, uint16(port), nil } -func (bind *NativeBind) Close() error { +func (bind *nativeBind) Close() error { var err1, err2 error if bind.ipv4 != nil { err1 = bind.ipv4.Close() @@ -133,7 +133,7 @@ func (bind *NativeBind) Close() error { return err2 } -func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) { +func (bind *nativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) { if bind.ipv4 == nil { return 0, nil, syscall.EAFNOSUPPORT } @@ -144,7 +144,7 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) { return n, (*NativeEndpoint)(endpoint), err } -func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) { +func (bind *nativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) { if bind.ipv6 == nil { return 0, nil, syscall.EAFNOSUPPORT } @@ -152,7 +152,7 @@ func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) { return n, (*NativeEndpoint)(endpoint), err } -func (bind *NativeBind) Send(buff []byte, endpoint Endpoint) error { +func (bind *nativeBind) Send(buff []byte, endpoint Endpoint) error { var err error nend := endpoint.(*NativeEndpoint) if nend.IP.To4() != nil { diff --git a/device/conn_linux.go b/device/conn_linux.go index 49949d5..6a8520e 100644 --- a/device/conn_linux.go +++ b/device/conn_linux.go @@ -63,7 +63,7 @@ func (endpoint *NativeEndpoint) dst6() *unix.SockaddrInet6 { return (*unix.SockaddrInet6)(unsafe.Pointer(&endpoint.dst[0])) } -type NativeBind struct { +type nativeBind struct { sock4 int sock6 int netlinkSock int @@ -72,7 +72,7 @@ type NativeBind struct { } var _ Endpoint = (*NativeEndpoint)(nil) -var _ Bind = (*NativeBind)(nil) +var _ Bind = (*nativeBind)(nil) func CreateEndpoint(s string) (Endpoint, error) { var end NativeEndpoint @@ -127,9 +127,9 @@ func createNetlinkRouteSocket() (int, error) { } -func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) { +func CreateBind(port uint16, device *Device) (*nativeBind, uint16, error) { var err error - var bind NativeBind + var bind nativeBind var newPort uint16 bind.netlinkSock, err = createNetlinkRouteSocket() @@ -176,7 +176,7 @@ func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) { return &bind, port, nil } -func (bind *NativeBind) SetMark(value uint32) error { +func (bind *nativeBind) SetMark(value uint32) error { if bind.sock6 != -1 { err := unix.SetsockoptInt( bind.sock6, @@ -213,7 +213,7 @@ func closeUnblock(fd int) error { return unix.Close(fd) } -func (bind *NativeBind) Close() error { +func (bind *nativeBind) Close() error { var err1, err2, err3 error if bind.sock6 != -1 { err1 = closeUnblock(bind.sock6) @@ -232,7 +232,7 @@ func (bind *NativeBind) Close() error { return err3 } -func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) { +func (bind *nativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) { var end NativeEndpoint if bind.sock6 == -1 { return 0, nil, syscall.EAFNOSUPPORT @@ -245,7 +245,7 @@ func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) { return n, &end, err } -func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) { +func (bind *nativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) { var end NativeEndpoint if bind.sock4 == -1 { return 0, nil, syscall.EAFNOSUPPORT @@ -258,7 +258,7 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) { return n, &end, err } -func (bind *NativeBind) Send(buff []byte, end Endpoint) error { +func (bind *nativeBind) Send(buff []byte, end Endpoint) error { nend := end.(*NativeEndpoint) if !nend.isV6 { if bind.sock4 == -1 { @@ -592,7 +592,7 @@ func receive6(sock int, buff []byte, end *NativeEndpoint) (int, error) { return size, nil } -func (bind *NativeBind) routineRouteListener(device *Device) { +func (bind *nativeBind) routineRouteListener(device *Device) { type peerEndpointPtr struct { peer *Peer endpoint *Endpoint diff --git a/device/mark_default.go b/device/mark_default.go index 76b1015..7de2524 100644 --- a/device/mark_default.go +++ b/device/mark_default.go @@ -7,6 +7,6 @@ package device -func (bind *NativeBind) SetMark(mark uint32) error { +func (bind *nativeBind) SetMark(mark uint32) error { return nil } diff --git a/device/mark_unix.go b/device/mark_unix.go index ee64cc9..a791c71 100644 --- a/device/mark_unix.go +++ b/device/mark_unix.go @@ -25,7 +25,7 @@ func init() { } } -func (bind *NativeBind) SetMark(mark uint32) error { +func (bind *nativeBind) SetMark(mark uint32) error { var operr error if fwmarkIoctl == 0 { return nil diff --git a/device/peer.go b/device/peer.go index af3ef9d..815dff4 100644 --- a/device/peer.go +++ b/device/peer.go @@ -258,10 +258,10 @@ func (peer *Peer) Stop() { peer.ZeroAndFlushAll() } -var roamingDisabled bool +var RoamingDisabled bool func (peer *Peer) SetEndpointFromPacket(endpoint Endpoint) { - if roamingDisabled { + if RoamingDisabled { return } peer.Lock()