| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- 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
- }
- 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)
- 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, 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
- }
|