package tlsspoof import ( "net" "net/netip" "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" "golang.org/x/sys/unix" ) const PlatformSupported = true const ( // Values of enum { TCP_NO_QUEUE, TCP_RECV_QUEUE, TCP_SEND_QUEUE } from // include/net/tcp.h; not exported by golang.org/x/sys/unix. tcpRecvQueue = 1 tcpSendQueue = 2 ) type linuxSpoofer struct { method Method src netip.AddrPort dst netip.AddrPort rawFD int rawSockAddr unix.Sockaddr sendNext uint32 receiveNext uint32 timestamp uint32 } func newRawSpoofer(conn net.Conn, method Method) (rawSpoofer, error) { tcpConn, src, dst, err := tcpEndpoints(conn) if err != nil { return nil, err } fd, sockaddr, err := openLinuxRawSocket(dst) if err != nil { return nil, err } spoofer := &linuxSpoofer{ method: method, src: src, dst: dst, rawFD: fd, rawSockAddr: sockaddr, } err = spoofer.loadSequenceNumbers(tcpConn) if err != nil { unix.Close(fd) return nil, err } return spoofer, nil } func openLinuxRawSocket(dst netip.AddrPort) (int, unix.Sockaddr, error) { if dst.Addr().Is4() { return openIPv4RawSocket(dst) } fd, err := unix.Socket(unix.AF_INET6, unix.SOCK_RAW, unix.IPPROTO_TCP) if err != nil { return -1, nil, E.Cause(err, "open AF_INET6 SOCK_RAW") } err = unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_HDRINCL, 1) if err != nil { unix.Close(fd) return -1, nil, E.Cause(err, "set IPV6_HDRINCL") } // Linux raw IPv6 sockets interpret sin6_port as a nexthdr protocol number // (see raw(7)); any value other than 0 or the socket's IPPROTO_TCP causes // sendto to fail with EINVAL. The destination is already encoded in the // user-supplied IPv6 header under IPV6_HDRINCL. sockaddr := &unix.SockaddrInet6{Addr: dst.Addr().As16()} return fd, sockaddr, nil } // loadSequenceNumbers puts the socket briefly into TCP_REPAIR mode to read // snd_nxt and rcv_nxt from the kernel. TCP_REPAIR requires CAP_NET_ADMIN; // callers must run as root or grant both CAP_NET_RAW and CAP_NET_ADMIN. // // If the TCP_REPAIR_OFF revert fails, the socket would stay in TCP_REPAIR // state and subsequent Write() calls would silently buffer instead of sending. // Surface that error so callers can abort. func (s *linuxSpoofer) loadSequenceNumbers(tcpConn *net.TCPConn) error { return control.Conn(tcpConn, func(raw uintptr) (err error) { fd := int(raw) if s.method == MethodWrongTimestamp { timestamp, err := unix.GetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_TIMESTAMP) if err != nil { return E.Cause(err, "read timestamp") } s.timestamp = uint32(timestamp) } err = unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_REPAIR, unix.TCP_REPAIR_ON) if err != nil { return E.Cause(err, "enter TCP_REPAIR (need CAP_NET_ADMIN)") } defer func() { offErr := unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_REPAIR, unix.TCP_REPAIR_OFF) if err == nil && offErr != nil { err = E.Cause(offErr, "leave TCP_REPAIR") } }() err = unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_REPAIR_QUEUE, tcpSendQueue) if err != nil { return E.Cause(err, "select TCP_SEND_QUEUE") } sendSequence, err := unix.GetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_QUEUE_SEQ) if err != nil { return E.Cause(err, "read send queue sequence") } err = unix.SetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_REPAIR_QUEUE, tcpRecvQueue) if err != nil { return E.Cause(err, "select TCP_RECV_QUEUE") } receiveSequence, err := unix.GetsockoptInt(fd, unix.IPPROTO_TCP, unix.TCP_QUEUE_SEQ) if err != nil { return E.Cause(err, "read recv queue sequence") } s.sendNext = uint32(sendSequence) s.receiveNext = uint32(receiveSequence) return nil }) } func (s *linuxSpoofer) Inject(payload []byte) error { frame, err := buildSpoofFrame(s.method, s.src, s.dst, s.sendNext, s.receiveNext, s.timestamp, nil, payload) if err != nil { return err } err = unix.Sendto(s.rawFD, frame, 0, s.rawSockAddr) if err != nil { return E.Cause(err, "sendto raw socket") } return nil } func (s *linuxSpoofer) Close() error { if s.rawFD < 0 { return nil } err := unix.Close(s.rawFD) s.rawFD = -1 return err }