mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-22 08:31:30 +00:00
Refine tproxy write back
This commit is contained in:
parent
17b5f031f1
commit
cbab86ae38
|
@ -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
|
||||
}
|
||||
|
|
|
@ -3,19 +3,20 @@
|
|||
package redir
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"github.com/sagernet/sing/common/control"
|
||||
)
|
||||
|
||||
func TProxy(fd uintptr, isIPv6 bool) error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
func TProxyWriteBack() control.Func {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
||||
return netip.AddrPort{}, os.ErrInvalid
|
||||
}
|
||||
|
||||
func DialUDP(lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
|
|
@ -86,12 +86,13 @@ func (t *TProxy) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.B
|
|||
}
|
||||
metadata.Destination = M.SocksaddrFromNetIP(destination)
|
||||
t.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
|
||||
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), &tproxyPacketWriter{source: natConn}
|
||||
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), &tproxyPacketWriter{ctx: ctx, source: natConn}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type tproxyPacketWriter struct {
|
||||
ctx context.Context
|
||||
source N.PacketConn
|
||||
destination M.Socksaddr
|
||||
conn *net.UDPConn
|
||||
|
@ -99,25 +100,30 @@ type tproxyPacketWriter struct {
|
|||
|
||||
func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
defer buffer.Release()
|
||||
var udpConn *net.UDPConn
|
||||
if w.destination == destination {
|
||||
if w.conn != nil {
|
||||
udpConn = w.conn
|
||||
destination = destination.Unwrap()
|
||||
if !w.destination.Addr.IsValid() {
|
||||
w.destination = destination
|
||||
} else if w.destination == destination && w.conn != nil {
|
||||
_, err := w.conn.WriteToUDPAddrPort(buffer.Bytes(), M.AddrPortFromNet(w.source.LocalAddr()))
|
||||
if err == nil {
|
||||
w.conn = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if udpConn == nil {
|
||||
var err error
|
||||
udpConn, err = redir.DialUDP(destination.UDPAddr(), M.SocksaddrFromNet(w.source.LocalAddr()).UDPAddr())
|
||||
var listener net.ListenConfig
|
||||
listener.Control = control.Append(listener.Control, control.ReuseAddr())
|
||||
listener.Control = control.Append(listener.Control, redir.TProxyWriteBack())
|
||||
packetConn, err := listener.ListenPacket(w.ctx, "udp", destination.String())
|
||||
if err != nil {
|
||||
return E.Cause(err, "tproxy udp write back")
|
||||
return err
|
||||
}
|
||||
udpConn := packetConn.(*net.UDPConn)
|
||||
if w.destination == destination {
|
||||
w.conn = udpConn
|
||||
} else {
|
||||
defer udpConn.Close()
|
||||
}
|
||||
}
|
||||
return common.Error(udpConn.Write(buffer.Bytes()))
|
||||
return common.Error(udpConn.WriteToUDPAddrPort(buffer.Bytes(), M.AddrPortFromNet(w.source.LocalAddr())))
|
||||
}
|
||||
|
||||
func (w *tproxyPacketWriter) Close() error {
|
||||
|
|
Loading…
Reference in a new issue