mirror of
https://github.com/SagerNet/sing-tun.git
synced 2025-10-05 08:37:03 +08:00
Add ping client
This commit is contained in:
86
ping/socket_unix.go
Normal file
86
ping/socket_unix.go
Normal file
@@ -0,0 +1,86 @@
|
||||
//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
|
||||
}
|
Reference in New Issue
Block a user