mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
62 lines
1.9 KiB
Go
62 lines
1.9 KiB
Go
package netenv
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
// Windows specific constants for the WSAIoctl interface.
|
|
const ( //nolint:golint
|
|
SIO_RCVALL = syscall.IOC_IN | syscall.IOC_VENDOR | 1
|
|
|
|
RCVALL_OFF = 0
|
|
RCVALL_ON = 1
|
|
RCVALL_SOCKETLEVELONLY = 2
|
|
RCVALL_IPLEVEL = 3
|
|
)
|
|
|
|
func newICMPListener(address string) (net.PacketConn, error) {
|
|
// This is an attempt to work around the problem described here:
|
|
// https://github.com/golang/go/issues/38427
|
|
|
|
// First, get the correct local interface address, as SIO_RCVALL can't be set on a 0.0.0.0 listeners.
|
|
dialedConn, err := net.Dial("ip4:icmp", address)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to dial: %s", err)
|
|
}
|
|
localAddr := dialedConn.LocalAddr()
|
|
dialedConn.Close()
|
|
|
|
// Configure the setup routine in order to extract the socket handle.
|
|
var socketHandle syscall.Handle
|
|
cfg := net.ListenConfig{
|
|
Control: func(network, address string, c syscall.RawConn) error {
|
|
return c.Control(func(s uintptr) {
|
|
socketHandle = syscall.Handle(s)
|
|
})
|
|
},
|
|
}
|
|
|
|
// Bind to interface.
|
|
conn, err := cfg.ListenPacket(context.Background(), "ip4:icmp", localAddr.String())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set socket option to receive all packets, such as ICMP error messages.
|
|
// This is somewhat dirty, as there is guarantee that socketHandle is still valid.
|
|
// WARNING: The Windows Firewall might just drop the incoming packets you might want to receive.
|
|
unused := uint32(0) // Documentation states that this is unused, but WSAIoctl fails without it.
|
|
flag := uint32(RCVALL_IPLEVEL)
|
|
size := uint32(unsafe.Sizeof(flag))
|
|
err = syscall.WSAIoctl(socketHandle, SIO_RCVALL, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &unused, nil, 0)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to set socket to listen to all packests: %s", os.NewSyscallError("WSAIoctl", err))
|
|
}
|
|
|
|
return conn, nil
|
|
}
|