mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-07 04:20:12 +02:00
chore(pmtud): remove calls to syscall in favor of unix and windows
- syscall is deprecated and is not kept up-to-date - each OS is inherently different hence the syscall being deprecated
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ linters:
|
|||||||
path: internal\/server\/.+\.go
|
path: internal\/server\/.+\.go
|
||||||
- linters:
|
- linters:
|
||||||
- ireturn
|
- ireturn
|
||||||
text: returns interface \(github\.com\/vishvananda\/netlink\.Link\)
|
text: returns interface \(golang\.org\/x\/sys\/unix\.Sockaddr\)
|
||||||
- linters:
|
- linters:
|
||||||
- ireturn
|
- ireturn
|
||||||
path: internal\/openvpn\/pkcs8\/descbc\.go
|
path: internal\/openvpn\/pkcs8\/descbc\.go
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
|
||||||
|
package constants
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
//nolint:revive
|
||||||
|
const (
|
||||||
|
SOCK_RAW = unix.SOCK_RAW
|
||||||
|
SOCK_STREAM = unix.SOCK_STREAM
|
||||||
|
AF_INET = unix.AF_INET
|
||||||
|
AF_INET6 = unix.AF_INET6
|
||||||
|
IPPROTO_TCP = unix.IPPROTO_TCP
|
||||||
|
EAGAIN = unix.EAGAIN
|
||||||
|
EWOULDBLOCK = unix.EWOULDBLOCK
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
const (
|
||||||
|
SOCK_RAW = windows.SOCK_RAW
|
||||||
|
SOCK_STREAM = windows.SOCK_STREAM
|
||||||
|
AF_INET = windows.AF_INET
|
||||||
|
AF_INET6 = windows.AF_INET6
|
||||||
|
IPPROTO_TCP = windows.IPPROTO_TCP
|
||||||
|
EAGAIN = windows.WSAEWOULDBLOCK
|
||||||
|
EWOULDBLOCK = windows.WSAEWOULDBLOCK
|
||||||
|
)
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package icmp
|
package icmp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setDontFragment(fd uintptr) (err error) {
|
func setDontFragment(fd uintptr) (err error) {
|
||||||
return syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP,
|
return unix.SetsockoptInt(int(fd), unix.IPPROTO_IP,
|
||||||
syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_PROBE)
|
unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_PROBE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package icmp
|
package icmp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setDontFragment(fd uintptr) (err error) {
|
func setDontFragment(fd uintptr) (err error) {
|
||||||
// https://docs.microsoft.com/en-us/troubleshoot/windows/win32/header-library-requirement-socket-ipproto-ip
|
// https://docs.microsoft.com/en-us/troubleshoot/windows/win32/header-library-requirement-socket-ipproto-ip
|
||||||
// #define IP_DONTFRAGMENT 14 /* don't fragment IP datagrams */
|
// #define IP_DONTFRAGMENT 14 /* don't fragment IP datagrams */
|
||||||
return syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IP, 14, 1)
|
return windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, 14, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package ip
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
)
|
)
|
||||||
@@ -19,7 +18,7 @@ func HeaderV4(srcIP, dstIP netip.Addr, payloadLength uint32) []byte {
|
|||||||
const flagsAndOffset uint16 = 0x4000 // DF bit set
|
const flagsAndOffset uint16 = 0x4000 // DF bit set
|
||||||
putUint16(ipHeader[6:], flagsAndOffset)
|
putUint16(ipHeader[6:], flagsAndOffset)
|
||||||
ipHeader[8] = 64 // ttl
|
ipHeader[8] = 64 // ttl
|
||||||
ipHeader[9] = syscall.IPPROTO_TCP
|
ipHeader[9] = constants.IPPROTO_TCP
|
||||||
srcIPBytes := srcIP.As4()
|
srcIPBytes := srcIP.As4()
|
||||||
copy(ipHeader[12:16], srcIPBytes[:])
|
copy(ipHeader[12:16], srcIPBytes[:])
|
||||||
dstIPBytes := dstIP.As4()
|
dstIPBytes := dstIP.As4()
|
||||||
@@ -51,7 +50,7 @@ func ipChecksum(header []byte) uint16 {
|
|||||||
|
|
||||||
// HeaderV6 makes an IPv6 header.
|
// HeaderV6 makes an IPv6 header.
|
||||||
// payloadLen is the length of the payload following the header.
|
// payloadLen is the length of the payload following the header.
|
||||||
// nextHeader can be byte([syscall.IPPROTO_TCP]) for example.
|
// nextHeader can be byte([constants.IPPROTO_TCP]) for example.
|
||||||
func HeaderV6(srcIP, dstIP netip.Addr,
|
func HeaderV6(srcIP, dstIP netip.Addr,
|
||||||
payloadLen uint16, nextHeader byte,
|
payloadLen uint16, nextHeader byte,
|
||||||
) []byte {
|
) []byte {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
package ip
|
package ip
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
func SetIPv4HeaderIncluded(fd int) error {
|
func SetIPv4HeaderIncluded(fd int) error {
|
||||||
return syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
|
return unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_HDRINCL, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package ip
|
package ip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetIPv4HeaderIncluded(handle syscall.Handle) error {
|
func SetIPv4HeaderIncluded(handle windows.Handle) error {
|
||||||
const ipHdrIncluded = windows.IP_HDRINCL
|
const ipHdrIncluded = windows.IP_HDRINCL
|
||||||
return syscall.SetsockoptInt(handle, syscall.IPPROTO_IP, ipHdrIncluded, 1)
|
return windows.SetsockoptInt(handle, windows.IPPROTO_IP, ipHdrIncluded, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package ip
|
package ip
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
func SetIPv6HeaderIncluded(fd int) error {
|
func SetIPv6HeaderIncluded(fd int) error {
|
||||||
const ipv6HdrIncluded = 36 // IPV6_HDRINCL
|
return unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_HDRINCL, 1)
|
||||||
return syscall.SetsockoptInt(fd, syscall.IPPROTO_IPV6, ipv6HdrIncluded, 1)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ip
|
package ip
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/windows"
|
||||||
|
|
||||||
func SetIPv6HeaderIncluded(fd syscall.Handle) error {
|
func SetIPv6HeaderIncluded(fd windows.Handle) error {
|
||||||
panic("windows does not allow an application to build IPv6 headers")
|
panic("windows does not allow an application to build IPv6 headers")
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-30
@@ -3,9 +3,9 @@ package ip
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/jsimonetti/rtnetlink"
|
"github.com/jsimonetti/rtnetlink"
|
||||||
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SrcAddr determines the appropriate source IP address to use when sending a packet to the
|
// SrcAddr determines the appropriate source IP address to use when sending a packet to the
|
||||||
@@ -35,9 +35,9 @@ func srcIP(dst netip.Addr) (netip.Addr, error) {
|
|||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
family := uint8(syscall.AF_INET)
|
family := uint8(constants.AF_INET)
|
||||||
if dst.Is6() {
|
if dst.Is6() {
|
||||||
family = syscall.AF_INET6
|
family = constants.AF_INET6
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request route to destination
|
// Request route to destination
|
||||||
@@ -71,53 +71,34 @@ func srcIP(dst netip.Addr) (netip.Addr, error) {
|
|||||||
// It doesn't actually listen on the port.
|
// It doesn't actually listen on the port.
|
||||||
// The cleanup function returned should be called to release the port when done.
|
// The cleanup function returned should be called to release the port when done.
|
||||||
func srcPort(srcAddr netip.Addr, proto int) (srcPort uint16, cleanup func(), err error) {
|
func srcPort(srcAddr netip.Addr, proto int) (srcPort uint16, cleanup func(), err error) {
|
||||||
family := syscall.AF_INET
|
family := constants.AF_INET
|
||||||
if srcAddr.Is6() {
|
if srcAddr.Is6() {
|
||||||
family = syscall.AF_INET6
|
family = constants.AF_INET6
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := syscall.Socket(family, syscall.SOCK_STREAM, proto)
|
fd, err := socket(family, constants.SOCK_STREAM, proto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("creating reservation socket: %w", err)
|
return 0, nil, fmt.Errorf("creating reservation socket: %w", err)
|
||||||
}
|
}
|
||||||
cleanup = func() {
|
cleanup = func() {
|
||||||
_ = syscall.Close(fd)
|
_ = closeSocket(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind to port 0 to get an ephemeral port
|
// Bind to port 0 to get an ephemeral port
|
||||||
const port = 0
|
const port = 0
|
||||||
var bindAddr syscall.Sockaddr
|
bindAddr := makeSockAddr(srcAddr, port)
|
||||||
if srcAddr.Is4() {
|
|
||||||
bindAddr = &syscall.SockaddrInet4{
|
|
||||||
Port: port,
|
|
||||||
Addr: srcAddr.As4(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bindAddr = &syscall.SockaddrInet6{
|
|
||||||
Port: port,
|
|
||||||
Addr: srcAddr.As16(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = syscall.Bind(fd, bindAddr)
|
err = bind(fd, bindAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return 0, nil, fmt.Errorf("binding reservation socket: %w", err)
|
return 0, nil, fmt.Errorf("binding reservation socket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sockAddr, err := syscall.Getsockname(fd)
|
srcPort, err = extractPortFromFD(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
return 0, nil, fmt.Errorf("getting bound socket name: %w", err)
|
return 0, nil, fmt.Errorf("extracting port from socket fd: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch typedSockAddr := sockAddr.(type) {
|
|
||||||
case *syscall.SockaddrInet4:
|
|
||||||
srcPort = uint16(typedSockAddr.Port) //nolint:gosec
|
|
||||||
case *syscall.SockaddrInet6:
|
|
||||||
srcPort = uint16(typedSockAddr.Port) //nolint:gosec
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unexpected sockaddr type: %T", typedSockAddr))
|
|
||||||
}
|
|
||||||
return srcPort, cleanup, nil
|
return srcPort, cleanup, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
|
||||||
|
package ip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func socket(domain int, typ int, proto int) (fd int, err error) {
|
||||||
|
return unix.Socket(domain, typ, proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeSocket(fd int) error {
|
||||||
|
return unix.Close(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bind(fd int, addr unix.Sockaddr) error {
|
||||||
|
return unix.Bind(fd, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSockAddr(ip netip.Addr, port uint16) unix.Sockaddr {
|
||||||
|
if ip.Is4() {
|
||||||
|
return &unix.SockaddrInet4{
|
||||||
|
Port: int(port),
|
||||||
|
Addr: ip.As4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &unix.SockaddrInet6{
|
||||||
|
Port: int(port),
|
||||||
|
Addr: ip.As16(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractPortFromFD(fd int) (uint16, error) {
|
||||||
|
sockAddr, err := unix.Getsockname(fd)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("getting sockname: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typedSockAddr := sockAddr.(type) {
|
||||||
|
case *unix.SockaddrInet4:
|
||||||
|
return uint16(typedSockAddr.Port), nil //nolint:gosec
|
||||||
|
case *unix.SockaddrInet6:
|
||||||
|
return uint16(typedSockAddr.Port), nil //nolint:gosec
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpected sockaddr type: %T", typedSockAddr))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package ip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func socket(domain int, typ int, proto int) (fd windows.Handle, err error) {
|
||||||
|
return windows.Socket(domain, typ, proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeSocket(fd windows.Handle) error {
|
||||||
|
return windows.Close(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func bind(fd windows.Handle, addr windows.Sockaddr) error {
|
||||||
|
return windows.Bind(fd, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSockAddr(ip netip.Addr, port uint16) windows.Sockaddr {
|
||||||
|
if ip.Is4() {
|
||||||
|
return &windows.SockaddrInet4{
|
||||||
|
Port: int(port),
|
||||||
|
Addr: ip.As4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &windows.SockaddrInet6{
|
||||||
|
Port: int(port),
|
||||||
|
Addr: ip.As16(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractPortFromFD(fd windows.Handle) (uint16, error) {
|
||||||
|
sockAddr, err := windows.Getsockname(fd)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("getting sockname: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typedSockAddr := sockAddr.(type) {
|
||||||
|
case *windows.SockaddrInet4:
|
||||||
|
return uint16(typedSockAddr.Port), nil //nolint:gosec
|
||||||
|
case *windows.SockaddrInet6:
|
||||||
|
return uint16(typedSockAddr.Port), nil //nolint:gosec
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unexpected sockaddr type: %T", typedSockAddr))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/test"
|
"github.com/qdm12/gluetun/internal/pmtud/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ func PathMTUDiscover(ctx context.Context, addrPort netip.AddrPort,
|
|||||||
tests[i] = testUnit{mtu: mtusToTest[i]}
|
tests[i] = testUnit{mtu: mtusToTest[i]}
|
||||||
}
|
}
|
||||||
|
|
||||||
family := syscall.AF_INET
|
family := constants.AF_INET
|
||||||
if addrPort.Addr().Is6() {
|
if addrPort.Addr().Is6() {
|
||||||
family = syscall.AF_INET6
|
family = constants.AF_INET6
|
||||||
}
|
}
|
||||||
fd, stop, err := startRawSocket(family)
|
fd, stop, err := startRawSocket(family)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/ip"
|
"github.com/qdm12/gluetun/internal/pmtud/ip"
|
||||||
@@ -67,7 +66,7 @@ func createPacket(src, dst netip.AddrPort,
|
|||||||
ipHeader = ip.HeaderV4(src.Addr(), dst.Addr(), payloadLength)
|
ipHeader = ip.HeaderV4(src.Addr(), dst.Addr(), payloadLength)
|
||||||
} else {
|
} else {
|
||||||
ipHeader = ip.HeaderV6(src.Addr(), dst.Addr(),
|
ipHeader = ip.HeaderV6(src.Addr(), dst.Addr(),
|
||||||
uint16(payloadLength), byte(syscall.IPPROTO_TCP)) //nolint:gosec
|
uint16(payloadLength), byte(constants.IPPROTO_TCP)) //nolint:gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpHeader := makeTCPHeader(src.Port(), dst.Port(), seq, ack, flags)
|
tcpHeader := makeTCPHeader(src.Port(), dst.Port(), seq, ack, flags)
|
||||||
|
|||||||
@@ -5,32 +5,31 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/ip"
|
"github.com/qdm12/gluetun/internal/pmtud/ip"
|
||||||
)
|
)
|
||||||
|
|
||||||
func startRawSocket(family int) (fd fileDescriptor, stop func(), err error) {
|
func startRawSocket(family int) (fd fileDescriptor, stop func(), err error) {
|
||||||
fdPlatform, err := syscall.Socket(family, syscall.SOCK_RAW, syscall.IPPROTO_TCP)
|
fdPlatform, err := socket(family, constants.SOCK_RAW, constants.IPPROTO_TCP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, fmt.Errorf("creating raw socket: %w", err)
|
return 0, nil, fmt.Errorf("creating raw socket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if family == syscall.AF_INET {
|
if family == constants.AF_INET {
|
||||||
err = ip.SetIPv4HeaderIncluded(fdPlatform)
|
err = ip.SetIPv4HeaderIncluded(fdPlatform)
|
||||||
} else {
|
} else {
|
||||||
err = ip.SetIPv6HeaderIncluded(fdPlatform)
|
err = ip.SetIPv6HeaderIncluded(fdPlatform)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = syscall.Close(fdPlatform)
|
_ = closeSocket(fdPlatform)
|
||||||
return 0, nil, fmt.Errorf("setting header option on raw socket: %w", err)
|
return 0, nil, fmt.Errorf("setting header option on raw socket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow sending packets larger than cached PMTU (for PMTUD probing)
|
// Allow sending packets larger than cached PMTU (for PMTUD probing)
|
||||||
err = setMTUDiscovery(fdPlatform)
|
err = setMTUDiscovery(fdPlatform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = syscall.Close(fdPlatform)
|
_ = closeSocket(fdPlatform)
|
||||||
return 0, nil, fmt.Errorf("setting IP_MTU_DISCOVER: %w", err)
|
return 0, nil, fmt.Errorf("setting IP_MTU_DISCOVER: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,12 +38,12 @@ func startRawSocket(family int) (fd fileDescriptor, stop func(), err error) {
|
|||||||
// which would cause things to hang indefinitely.
|
// which would cause things to hang indefinitely.
|
||||||
err = setNonBlock(fdPlatform)
|
err = setNonBlock(fdPlatform)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = syscall.Close(fdPlatform)
|
_ = closeSocket(fdPlatform)
|
||||||
return 0, nil, fmt.Errorf("setting non-blocking mode: %w", err)
|
return 0, nil, fmt.Errorf("setting non-blocking mode: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
stop = func() {
|
stop = func() {
|
||||||
_ = syscall.Close(fdPlatform)
|
_ = closeSocket(fdPlatform)
|
||||||
}
|
}
|
||||||
return fileDescriptor(fdPlatform), stop, nil
|
return fileDescriptor(fdPlatform), stop, nil
|
||||||
}
|
}
|
||||||
@@ -61,7 +60,7 @@ var (
|
|||||||
func runTest(ctx context.Context, fd fileDescriptor,
|
func runTest(ctx context.Context, fd fileDescriptor,
|
||||||
tracker *tracker, dst netip.AddrPort, mtu uint32,
|
tracker *tracker, dst netip.AddrPort, mtu uint32,
|
||||||
) error {
|
) error {
|
||||||
const proto = syscall.IPPROTO_TCP
|
const proto = constants.IPPROTO_TCP
|
||||||
src, cleanup, err := ip.SrcAddr(dst, proto)
|
src, cleanup, err := ip.SrcAddr(dst, proto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting source address: %w", err)
|
return fmt.Errorf("getting source address: %w", err)
|
||||||
@@ -137,19 +136,6 @@ func runTest(ctx context.Context, fd fileDescriptor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeSockAddr(addr netip.AddrPort) syscall.Sockaddr {
|
|
||||||
if addr.Addr().Is4() {
|
|
||||||
return &syscall.SockaddrInet4{
|
|
||||||
Port: int(addr.Port()),
|
|
||||||
Addr: addr.Addr().As4(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &syscall.SockaddrInet6{
|
|
||||||
Port: int(addr.Port()),
|
|
||||||
Addr: addr.Addr().As16(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errTCPPacketNotRST = errors.New("TCP packet is not an RST")
|
var errTCPPacketNotRST = errors.New("TCP packet is not an RST")
|
||||||
|
|
||||||
func handleRSTReply(ctx context.Context, fd fileDescriptor, ch <-chan []byte,
|
func handleRSTReply(ctx context.Context, fd fileDescriptor, ch <-chan []byte,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import "syscall"
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
func setMTUDiscovery(fd int) error {
|
func setMTUDiscovery(fd int) error {
|
||||||
return syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_MTU_DISCOVER, syscall.IP_PMTUDISC_PROBE)
|
return unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_PROBE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -5,15 +7,16 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/netlink"
|
"github.com/qdm12/gluetun/internal/netlink"
|
||||||
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
"github.com/qdm12/gluetun/internal/routing"
|
"github.com/qdm12/gluetun/internal/routing"
|
||||||
"github.com/qdm12/log"
|
"github.com/qdm12/log"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_runTest(t *testing.T) {
|
func Test_runTest(t *testing.T) {
|
||||||
@@ -30,7 +33,7 @@ func Test_runTest(t *testing.T) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(t.Context())
|
ctx, cancel := context.WithCancel(t.Context())
|
||||||
|
|
||||||
const family = syscall.AF_INET
|
const family = constants.AF_INET
|
||||||
fd, stop, err := startRawSocket(family)
|
fd, stop, err := startRawSocket(family)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -158,33 +161,33 @@ func findDefaultIPv4RouteMTU(netlinker *netlink.NetLink) (mtu uint32, err error)
|
|||||||
func reserveClosedPort(t *testing.T) (port uint16) {
|
func reserveClosedPort(t *testing.T) (port uint16) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
|
fd, err := unix.Socket(constants.AF_INET, constants.SOCK_STREAM, constants.IPPROTO_TCP)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
err := syscall.Close(fd)
|
err := unix.Close(fd)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
addr := &syscall.SockaddrInet4{
|
addr := &unix.SockaddrInet4{
|
||||||
Port: 0,
|
Port: 0,
|
||||||
Addr: [4]byte{127, 0, 0, 1},
|
Addr: [4]byte{127, 0, 0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = syscall.Bind(fd, addr)
|
err = unix.Bind(fd, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = syscall.Close(fd)
|
_ = unix.Close(fd)
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sockAddr, err := syscall.Getsockname(fd)
|
sockAddr, err := unix.Getsockname(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = syscall.Close(fd)
|
_ = unix.Close(fd)
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sockAddr4, ok := sockAddr.(*syscall.SockaddrInet4)
|
sockAddr4, ok := sockAddr.(*unix.SockaddrInet4)
|
||||||
if !ok {
|
if !ok {
|
||||||
_ = syscall.Close(fd)
|
_ = unix.Close(fd)
|
||||||
t.Fatal("not an IPv4 address")
|
t.Fatal("not an IPv4 address")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,26 +3,49 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileDescriptor is a platform-independent type for socket file descriptors.
|
// fileDescriptor is a platform-independent type for socket file descriptors.
|
||||||
type fileDescriptor int
|
type fileDescriptor int
|
||||||
|
|
||||||
func sendTo(fd fileDescriptor, p []byte, flags int, to syscall.Sockaddr) (err error) {
|
func socket(domain int, typ int, proto int) (fd int, err error) {
|
||||||
return syscall.Sendto(int(fd), p, flags, to)
|
return unix.Socket(domain, typ, proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeSocket(fd int) error {
|
||||||
|
return unix.Close(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendTo(fd fileDescriptor, p []byte, flags int, to unix.Sockaddr) (err error) {
|
||||||
|
return unix.Sendto(int(fd), p, flags, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setSocketTimeout(fd fileDescriptor, timeout time.Duration) (err error) {
|
func setSocketTimeout(fd fileDescriptor, timeout time.Duration) (err error) {
|
||||||
timeval := syscall.NsecToTimeval(timeout.Nanoseconds())
|
timeval := unix.NsecToTimeval(timeout.Nanoseconds())
|
||||||
return syscall.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &timeval)
|
return unix.SetsockoptTimeval(int(fd), unix.SOL_SOCKET, unix.SO_RCVTIMEO, &timeval)
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvFrom(fd fileDescriptor, p []byte, flags int) (n int, from syscall.Sockaddr, err error) {
|
func recvFrom(fd fileDescriptor, p []byte, flags int) (n int, from unix.Sockaddr, err error) {
|
||||||
return syscall.Recvfrom(int(fd), p, flags)
|
return unix.Recvfrom(int(fd), p, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNonBlock(fd int) error {
|
func setNonBlock(fd int) error {
|
||||||
return syscall.SetNonblock(fd, true)
|
return unix.SetNonblock(fd, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSockAddr(addr netip.AddrPort) unix.Sockaddr {
|
||||||
|
if addr.Addr().Is4() {
|
||||||
|
return &unix.SockaddrInet4{
|
||||||
|
Port: int(addr.Port()),
|
||||||
|
Addr: addr.Addr().As4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &unix.SockaddrInet6{
|
||||||
|
Port: int(addr.Port()),
|
||||||
|
Addr: addr.Addr().As16(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,58 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fileDescriptor syscall.Handle
|
type fileDescriptor windows.Handle
|
||||||
|
|
||||||
func sendTo(fd fileDescriptor, p []byte, flags int, to syscall.Sockaddr) (err error) {
|
func socket(domain int, typ int, proto int) (fd windows.Handle, err error) {
|
||||||
return syscall.Sendto(syscall.Handle(fd), p, flags, to)
|
return windows.Socket(domain, typ, proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeSocket(fd windows.Handle) error {
|
||||||
|
return windows.Close(fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendTo(fd fileDescriptor, p []byte, flags int, to windows.Sockaddr) (err error) {
|
||||||
|
return windows.Sendto(windows.Handle(fd), p, flags, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setSocketTimeout(fd fileDescriptor, timeout time.Duration) (err error) {
|
func setSocketTimeout(fd fileDescriptor, timeout time.Duration) (err error) {
|
||||||
timeval := int(timeout.Milliseconds())
|
timeval := int(timeout.Milliseconds())
|
||||||
return syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, windows.SO_RCVTIMEO, timeval)
|
return windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVTIMEO, timeval)
|
||||||
}
|
}
|
||||||
|
|
||||||
func recvFrom(fd fileDescriptor, p []byte, flags int) (n int, from syscall.Sockaddr, err error) {
|
func recvFrom(fd fileDescriptor, p []byte, flags int) (n int, from windows.Sockaddr, err error) {
|
||||||
return syscall.Recvfrom(syscall.Handle(fd), p, flags)
|
return windows.Recvfrom(windows.Handle(fd), p, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMTUDiscovery(fd syscall.Handle) error {
|
func setMTUDiscovery(fd windows.Handle) error {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setNonBlock(fd syscall.Handle) error {
|
func setNonBlock(fd windows.Handle) error {
|
||||||
// Windows: Use ioctlsocket with FIONBIO
|
// Windows: Use ioctlsocket with FIONBIO
|
||||||
var arg uint32 = 1 // 1 to enable non-blocking mode
|
var arg uint32 = 1 // 1 to enable non-blocking mode
|
||||||
var bytesReturned uint32
|
var bytesReturned uint32
|
||||||
const FIONBIO = 0x8004667e
|
const FIONBIO = 0x8004667e
|
||||||
return syscall.WSAIoctl(fd, FIONBIO, (*byte)(unsafe.Pointer(&arg)),
|
return windows.WSAIoctl(fd, FIONBIO, (*byte)(unsafe.Pointer(&arg)),
|
||||||
uint32(unsafe.Sizeof(arg)), nil, 0, &bytesReturned, nil, 0)
|
uint32(unsafe.Sizeof(arg)), nil, 0, &bytesReturned, nil, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeSockAddr(addr netip.AddrPort) windows.Sockaddr {
|
||||||
|
if addr.Addr().Is4() {
|
||||||
|
return &windows.SockaddrInet4{
|
||||||
|
Port: int(addr.Port()),
|
||||||
|
Addr: addr.Addr().As4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &windows.SockaddrInet6{
|
||||||
|
Port: int(addr.Port()),
|
||||||
|
Addr: addr.Addr().As16(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
"github.com/qdm12/gluetun/internal/pmtud/constants"
|
||||||
@@ -80,8 +79,7 @@ func (t *tracker) listen(ctx context.Context) error {
|
|||||||
n, _, err := recvFrom(t.fd, reply, 0)
|
n, _, err := recvFrom(t.fd, reply, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, syscall.EAGAIN),
|
case errors.Is(err, constants.EAGAIN), errors.Is(err, constants.EWOULDBLOCK):
|
||||||
errors.Is(err, syscall.EWOULDBLOCK):
|
|
||||||
pollSleep(ctx)
|
pollSleep(ctx)
|
||||||
continue
|
continue
|
||||||
case ctx.Err() != nil:
|
case ctx.Err() != nil:
|
||||||
|
|||||||
Reference in New Issue
Block a user