Fix tls spoof raw socket routing on Linux

This commit is contained in:
世界 committed 2026-10-23 19:57:03 +08:00
1 parent e8e595c645
commit 9073ef8290
1 file changed
+41
+41
View File
@@ -39,6 +39,13 @@ func newRawSpoofer(conn net.Conn, method Method) (rawSpoofer, error) {
if err != nil {
return nil, err
}
err = control.Conn(tcpConn, func(raw uintptr) error {
return inheritRouting(fd, int(raw), src)
})
if err != nil {
unix.Close(fd)
return nil, err
}
spoofer := &linuxSpoofer{
method: method,
src: src,
@@ -75,6 +82,40 @@ func openLinuxRawSocket(dst netip.AddrPort) (int, unix.Sockaddr, error) {
return fd, sockaddr, nil
}
// Linux routes IP_HDRINCL packets by the raw socket's bound device, mark and
// bound address (raw_sendmsg), not by the addresses in the supplied header.
func inheritRouting(rawSocket, tcpSocket int, src netip.AddrPort) error {
bindInterface, err := unix.GetsockoptString(tcpSocket, unix.SOL_SOCKET, unix.SO_BINDTODEVICE)
if err != nil {
return E.Cause(err, "read SO_BINDTODEVICE")
}
if bindInterface != "" {
err = unix.BindToDevice(rawSocket, bindInterface)
if err != nil {
return E.Cause(err, "bind raw socket to interface ", bindInterface)
}
}
routingMark, err := unix.GetsockoptInt(tcpSocket, unix.SOL_SOCKET, unix.SO_MARK)
if err != nil {
return E.Cause(err, "read SO_MARK")
}
if routingMark != 0 {
err = unix.SetsockoptInt(rawSocket, unix.SOL_SOCKET, unix.SO_MARK, routingMark)
if err != nil {
return E.Cause(err, "set raw socket SO_MARK")
}
}
if src.Addr().Is4() {
err = unix.Bind(rawSocket, &unix.SockaddrInet4{Addr: src.Addr().As4()})
} else {
err = unix.Bind(rawSocket, &unix.SockaddrInet6{Addr: src.Addr().As16()})
}
if err != nil {
return E.Cause(err, "bind raw socket to ", src.Addr())
}
return 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.