|
@@ -2,14 +2,11 @@ package redir
|
|
|
|
|
|
import (
|
|
|
"encoding/binary"
|
|
|
- "net"
|
|
|
"net/netip"
|
|
|
- "os"
|
|
|
- "strconv"
|
|
|
"syscall"
|
|
|
|
|
|
+ "github.com/sagernet/sing/common/control"
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
|
- F "github.com/sagernet/sing/common/format"
|
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
|
|
|
|
"golang.org/x/sys/unix"
|
|
@@ -32,6 +29,18 @@ func TProxy(fd uintptr, isIPv6 bool) error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
+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)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
|
|
controlMessages, err := unix.ParseSocketControlMessage(oob)
|
|
|
if err != nil {
|
|
@@ -46,79 +55,3 @@ func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
|
|
}
|
|
|
return netip.AddrPort{}, E.New("not found")
|
|
|
}
|
|
|
-
|
|
|
-func DialUDP(lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
|
|
|
- rSockAddr, err := udpAddrToSockAddr(rAddr)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- lSockAddr, err := udpAddrToSockAddr(lAddr)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- fd, err := syscall.Socket(udpAddrFamily(lAddr, rAddr), syscall.SOCK_DGRAM, 0)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
|
|
- syscall.Close(fd)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
|
|
|
- syscall.Close(fd)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- if err = syscall.Bind(fd, lSockAddr); err != nil {
|
|
|
- syscall.Close(fd)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- if err = syscall.Connect(fd, rSockAddr); err != nil {
|
|
|
- syscall.Close(fd)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- fdFile := os.NewFile(uintptr(fd), F.ToString("net-udp-dial-", rAddr))
|
|
|
- defer fdFile.Close()
|
|
|
-
|
|
|
- c, err := net.FileConn(fdFile)
|
|
|
- if err != nil {
|
|
|
- syscall.Close(fd)
|
|
|
- return nil, err
|
|
|
- }
|
|
|
-
|
|
|
- return c.(*net.UDPConn), nil
|
|
|
-}
|
|
|
-
|
|
|
-func udpAddrToSockAddr(addr *net.UDPAddr) (syscall.Sockaddr, error) {
|
|
|
- switch {
|
|
|
- case addr.IP.To4() != nil:
|
|
|
- ip := [4]byte{}
|
|
|
- copy(ip[:], addr.IP.To4())
|
|
|
-
|
|
|
- return &syscall.SockaddrInet4{Addr: ip, Port: addr.Port}, nil
|
|
|
-
|
|
|
- default:
|
|
|
- ip := [16]byte{}
|
|
|
- copy(ip[:], addr.IP.To16())
|
|
|
-
|
|
|
- zoneID, err := strconv.ParseUint(addr.Zone, 10, 32)
|
|
|
- if err != nil {
|
|
|
- zoneID = 0
|
|
|
- }
|
|
|
-
|
|
|
- return &syscall.SockaddrInet6{Addr: ip, Port: addr.Port, ZoneId: uint32(zoneID)}, nil
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-func udpAddrFamily(lAddr, rAddr *net.UDPAddr) int {
|
|
|
- if (lAddr == nil || lAddr.IP.To4() != nil) && (rAddr == nil || lAddr.IP.To4() != nil) {
|
|
|
- return syscall.AF_INET
|
|
|
- }
|
|
|
- return syscall.AF_INET6
|
|
|
-}
|