Files
sing-tun/ping/socket_unix.go
2025-08-23 16:43:33 +08:00

88 lines
2.1 KiB
Go

//go:build unix
package ping
import (
"net"
"net/netip"
"os"
"runtime"
"syscall"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"golang.org/x/sys/unix"
)
func connect(privileged bool, controlFunc control.Func, destination netip.Addr) (net.Conn, error) {
var (
network string
fd int
err error
)
if destination.Is4() {
network = "ip4:icmp"
if !privileged {
fd, err = unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, unix.IPPROTO_ICMP)
} else {
fd, err = unix.Socket(unix.AF_INET, unix.SOCK_RAW, unix.IPPROTO_ICMP)
}
} else {
network = "ip6:icmp"
if !privileged {
fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, unix.IPPROTO_ICMPV6)
} else {
fd, err = unix.Socket(unix.AF_INET6, unix.SOCK_RAW, unix.IPPROTO_ICMPV6)
}
}
if err != nil {
return nil, E.Cause(err, "socket()")
}
file := os.NewFile(uintptr(fd), "datagram-oriented icmp")
defer file.Close()
err = unix.Connect(fd, M.AddrPortToSockaddr(netip.AddrPortFrom(destination, 0)))
if err != nil {
return nil, E.Cause(err, "connect()")
}
if destination.Is4() && runtime.GOOS == "linux" {
//err = unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_RECVTOS, 1)
//if err != nil {
// return nil, err
//}
err = unix.SetsockoptInt(fd, unix.IPPROTO_IP, unix.IP_RECVTTL, 1)
if err != nil {
return nil, E.Cause(err, "setsockopt()")
}
}
if destination.Is6() {
err = unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_RECVHOPLIMIT, 1)
if err != nil {
return nil, E.Cause(err, "setsockopt()")
}
err = unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
if err != nil {
return nil, E.Cause(err, "setsockopt()")
}
}
conn, err := net.FileConn(file)
if err != nil {
return nil, err
}
if controlFunc != nil {
var syscallConn syscall.RawConn
syscallConn, err = conn.(syscall.Conn).SyscallConn()
if err != nil {
return nil, err
}
err = controlFunc(network, destination.String(), syscallConn)
if err != nil {
return nil, err
}
}
return conn, nil
}