diff --git a/conn/controlfns.go b/conn/controlfns.go index fe32871a8..4f7d90fa1 100644 --- a/conn/controlfns.go +++ b/conn/controlfns.go @@ -10,6 +10,13 @@ import ( "syscall" ) +// UDP socket read/write buffer size (7MB). The value of 7MB is chosen as it is +// the max supported by a default configuration of macOS. Some platforms will +// silently clamp the value to other maximums, such as linux clamping to +// net.core.{r,w}mem_max (see _linux.go for additional implementation that works +// around this limitation) +const socketBufferSize = 7 << 20 + // controlFn is the callback function signature from net.ListenConfig.Control. // It is used to apply platform specific configuration to the socket prior to // bind. diff --git a/conn/controlfns_linux.go b/conn/controlfns_linux.go index 9e26d9527..aff62456f 100644 --- a/conn/controlfns_linux.go +++ b/conn/controlfns_linux.go @@ -15,6 +15,21 @@ import ( func init() { controlFns = append(controlFns, + // Attempt to set the socket buffer size beyond net.core.{r,w}mem_max by + // using SO_*BUFFORCE. This requires CAP_NET_ADMIN, and is allowed here to + // fail silently - the result of failure is lower performance on very fast + // links or high latency links. + func(network, address string, c syscall.RawConn) error { + return c.Control(func(fd uintptr) { + // Set up to *mem_max + _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, socketBufferSize) + _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, socketBufferSize) + // Set beyond *mem_max if CAP_NET_ADMIN + _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, socketBufferSize) + _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, socketBufferSize) + }) + }, + // Enable receiving of the packet information (IP_PKTINFO for IPv4, // IPV6_PKTINFO for IPv6) that is used to implement sticky socket support. func(network, address string, c syscall.RawConn) error { diff --git a/conn/controlfns_unix.go b/conn/controlfns_unix.go index 9738c73d3..726ee5467 100644 --- a/conn/controlfns_unix.go +++ b/conn/controlfns_unix.go @@ -15,6 +15,15 @@ import ( func init() { controlFns = append(controlFns, + // Set SO_RCVBUF/SO_SNDBUF - this could be common with the _windows code except + // for the unfortunate type specificity of syscall.Handle. + func(network, address string, c syscall.RawConn) error { + return c.Control(func(fd uintptr) { + _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, socketBufferSize) + _ = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF, socketBufferSize) + }) + }, + func(network, address string, c syscall.RawConn) error { var err error if network == "udp6" { diff --git a/conn/controlfns_windows.go b/conn/controlfns_windows.go new file mode 100644 index 000000000..46cf03d87 --- /dev/null +++ b/conn/controlfns_windows.go @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2023 WireGuard LLC. All Rights Reserved. + */ + +package conn + +import "syscall" + +func init() { + controlFns = append(controlFns, + // Set SO_RCVBUF/SO_SNDBUF - this could be common with the _unix code except + // for the unfortunate type specificity of syscall.Handle. + func(network, address string, c syscall.RawConn) error { + return c.Control(func(fd uintptr) { + _ = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, socketBufferSize) + _ = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, socketBufferSize) + }) + }, + ) +}