sing-box/common/redir/tproxy_linux.go

58 lines
1.9 KiB
Go
Raw Normal View History

2022-07-15 00:42:02 +00:00
package redir
import (
"encoding/binary"
"net/netip"
"syscall"
2022-09-25 09:13:42 +00:00
"github.com/sagernet/sing/common/control"
2022-07-15 00:42:02 +00:00
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"golang.org/x/sys/unix"
)
func TProxy(fd uintptr, isIPv6 bool) error {
2022-07-22 08:18:56 +00:00
err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
if err == nil {
err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
2022-07-15 00:42:02 +00:00
}
2022-07-22 08:18:56 +00:00
if err == nil && isIPv6 {
2022-07-15 00:42:02 +00:00
err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
}
2022-07-22 08:18:56 +00:00
if err == nil {
err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1)
2022-07-15 00:42:02 +00:00
}
2022-07-22 08:18:56 +00:00
if err == nil && isIPv6 {
2022-07-15 00:42:02 +00:00
err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1)
}
2022-07-22 08:18:56 +00:00
return err
2022-07-15 00:42:02 +00:00
}
2022-09-25 09:13:42 +00:00
func TProxyWriteBack() control.Func {
return func(network, address string, conn syscall.RawConn) error {
return control.Raw(conn, func(fd uintptr) error {
if M.ParseSocksaddr(address).Addr.Is6() {
return syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
} else {
return syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
}
})
}
}
2022-07-15 00:42:02 +00:00
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
controlMessages, err := unix.ParseSocketControlMessage(oob)
if err != nil {
return netip.AddrPort{}, err
}
for _, message := range controlMessages {
if message.Header.Level == unix.SOL_IP && message.Header.Type == unix.IP_RECVORIGDSTADDR {
return netip.AddrPortFrom(M.AddrFromIP(message.Data[4:8]), binary.BigEndian.Uint16(message.Data[2:4])), nil
} else if message.Header.Level == unix.SOL_IPV6 && message.Header.Type == unix.IPV6_RECVORIGDSTADDR {
return netip.AddrPortFrom(M.AddrFromIP(message.Data[8:24]), binary.BigEndian.Uint16(message.Data[2:4])), nil
}
}
return netip.AddrPort{}, E.New("not found")
}