From 323ace94fda2d86a4580e8854226886ff467c757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 30 Jun 2022 17:38:12 +0800 Subject: [PATCH] Trim repo --- common/debug/free.go | 11 - common/redir/mode.go | 9 - common/redir/redir_linux.go | 37 --- common/redir/redir_other.go | 13 - common/redir/tproxy_linux.go | 136 ---------- common/redir/tproxy_other.go | 30 --- common/rw/writev_windows.go | 10 +- go.mod | 2 - go.sum | 2 - protocol/http/{listener.go => handshake.go} | 32 ++- transport/mixed/listener.go | 158 ------------ transport/mixed/pac.go | 12 - transport/system/sockopt_linux.go | 14 -- transport/system/sockopt_other.go | 9 - transport/tcp/listener.go | 121 --------- transport/tcp/options.go | 11 - transport/udp/listener.go | 264 -------------------- transport/udp/options.go | 11 - 18 files changed, 33 insertions(+), 849 deletions(-) delete mode 100644 common/debug/free.go delete mode 100644 common/redir/mode.go delete mode 100644 common/redir/redir_linux.go delete mode 100644 common/redir/redir_other.go delete mode 100644 common/redir/tproxy_linux.go delete mode 100644 common/redir/tproxy_other.go rename protocol/http/{listener.go => handshake.go} (83%) delete mode 100644 transport/mixed/listener.go delete mode 100644 transport/mixed/pac.go delete mode 100644 transport/system/sockopt_linux.go delete mode 100644 transport/system/sockopt_other.go delete mode 100644 transport/tcp/listener.go delete mode 100644 transport/tcp/options.go delete mode 100644 transport/udp/listener.go delete mode 100644 transport/udp/options.go diff --git a/common/debug/free.go b/common/debug/free.go deleted file mode 100644 index 619819f..0000000 --- a/common/debug/free.go +++ /dev/null @@ -1,11 +0,0 @@ -package debug - -import ( - "runtime/debug" -) - -func Free() { - if Enabled { - debug.FreeOSMemory() - } -} diff --git a/common/redir/mode.go b/common/redir/mode.go deleted file mode 100644 index a265ab7..0000000 --- a/common/redir/mode.go +++ /dev/null @@ -1,9 +0,0 @@ -package redir - -type TransproxyMode uint8 - -const ( - ModeDisabled TransproxyMode = iota - ModeRedirect - ModeTProxy -) diff --git a/common/redir/redir_linux.go b/common/redir/redir_linux.go deleted file mode 100644 index abb1b1a..0000000 --- a/common/redir/redir_linux.go +++ /dev/null @@ -1,37 +0,0 @@ -package redir - -import ( - "net" - "net/netip" - "syscall" - - M "github.com/sagernet/sing/common/metadata" -) - -func GetOriginalDestination(conn net.Conn) (destination netip.AddrPort, err error) { - rawConn, err := conn.(syscall.Conn).SyscallConn() - if err != nil { - return - } - var rawFd uintptr - err = rawConn.Control(func(fd uintptr) { - rawFd = fd - }) - if err != nil { - return - } - const SO_ORIGINAL_DST = 80 - if conn.RemoteAddr().(*net.TCPAddr).IP.To4() != nil { - raw, err := syscall.GetsockoptIPv6Mreq(int(rawFd), syscall.IPPROTO_IP, SO_ORIGINAL_DST) - if err != nil { - return netip.AddrPort{}, err - } - return netip.AddrPortFrom(M.AddrFromIP(raw.Multiaddr[4:8]), uint16(raw.Multiaddr[2])<<8+uint16(raw.Multiaddr[3])), nil - } else { - raw, err := syscall.GetsockoptIPv6MTUInfo(int(rawFd), syscall.IPPROTO_IPV6, SO_ORIGINAL_DST) - if err != nil { - return netip.AddrPort{}, err - } - return netip.AddrPortFrom(M.AddrFromIP(raw.Addr.Addr[:]), raw.Addr.Port), nil - } -} diff --git a/common/redir/redir_other.go b/common/redir/redir_other.go deleted file mode 100644 index a24a270..0000000 --- a/common/redir/redir_other.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build !linux - -package redir - -import ( - "errors" - "net" - "net/netip" -) - -func GetOriginalDestination(conn net.Conn) (destination netip.AddrPort, err error) { - return netip.AddrPort{}, errors.New("unsupported platform") -} diff --git a/common/redir/tproxy_linux.go b/common/redir/tproxy_linux.go deleted file mode 100644 index 0984332..0000000 --- a/common/redir/tproxy_linux.go +++ /dev/null @@ -1,136 +0,0 @@ -package redir - -import ( - "encoding/binary" - "net" - "net/netip" - "os" - "strconv" - "syscall" - - 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" -) - -func TProxy(fd uintptr, isIPv6 bool) error { - err := syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) - if err != nil { - return err - } - if isIPv6 { - err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1) - } - return err -} - -func TProxyUDP(fd uintptr, isIPv6 bool) error { - err := syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1) - if err != nil { - return err - } - return syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1) -} - -func FWMark(fd uintptr, mark int) error { - return syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark) -} - -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") -} - -func DialUDP(network string, 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(network, 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(net string, lAddr, rAddr *net.UDPAddr) int { - switch net[len(net)-1] { - case '4': - return syscall.AF_INET - case '6': - return syscall.AF_INET6 - } - - if (lAddr == nil || lAddr.IP.To4() != nil) && (rAddr == nil || lAddr.IP.To4() != nil) { - return syscall.AF_INET - } - return syscall.AF_INET6 -} diff --git a/common/redir/tproxy_other.go b/common/redir/tproxy_other.go deleted file mode 100644 index 26778e6..0000000 --- a/common/redir/tproxy_other.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build !linux - -package redir - -import ( - "net" - "net/netip" - - E "github.com/sagernet/sing/common/exceptions" -) - -func TProxy(fd uintptr, isIPv6 bool) error { - return E.New("only available on linux") -} - -func TProxyUDP(fd uintptr, isIPv6 bool) error { - return E.New("only available on linux") -} - -func FWMark(fd uintptr, mark int) error { - return E.New("only available on linux") -} - -func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) { - return netip.AddrPort{}, E.New("only available on linux") -} - -func DialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) { - return nil, E.New("only available on linux") -} diff --git a/common/rw/writev_windows.go b/common/rw/writev_windows.go index d053450..724d4f4 100644 --- a/common/rw/writev_windows.go +++ b/common/rw/writev_windows.go @@ -1,16 +1,18 @@ package rw -import "golang.org/x/sys/windows" +import ( + "syscall" +) func WriteV(fd uintptr, data ...[]byte) (int, error) { var n uint32 - buffers := make([]*windows.WSABuf, len(data)) + buffers := make([]*syscall.WSABuf, len(data)) for i, buf := range data { - buffers[i] = &windows.WSABuf{ + buffers[i] = &syscall.WSABuf{ Len: uint32(len(buf)), Buf: &buf[0], } } - err := windows.WSASend(windows.Handle(fd), buffers[0], uint32(len(buffers)), &n, 0, nil, nil) + err := syscall.WSASend(syscall.Handle(fd), buffers[0], uint32(len(buffers)), &n, 0, nil, nil) return int(n), err } diff --git a/go.mod b/go.mod index d6bd075..219df77 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,3 @@ module github.com/sagernet/sing go 1.18 - -require golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b diff --git a/go.sum b/go.sum index a2987a2..e69de29 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +0,0 @@ -golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8= -golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/protocol/http/listener.go b/protocol/http/handshake.go similarity index 83% rename from protocol/http/listener.go rename to protocol/http/handshake.go index 96b6dd9..b0603d1 100644 --- a/protocol/http/listener.go +++ b/protocol/http/handshake.go @@ -1,6 +1,7 @@ package http import ( + std_bufio "bufio" "context" "encoding/base64" "net" @@ -10,6 +11,8 @@ import ( "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/auth" + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" M "github.com/sagernet/sing/common/metadata" @@ -19,7 +22,26 @@ import ( type Handler interface { N.TCPConnectionHandler N.UDPConnectionHandler - E.Handler +} + +func HandleConnection(ctx context.Context, conn net.Conn, authenticator auth.Authenticator, handler Handler, metadata M.Metadata) error { + reader := std_bufio.NewReader(conn) + request, err := http.ReadRequest(reader) + if err != nil { + return E.Cause(err, "read http request") + } + if reader.Buffered() > 0 { + _buffer := buf.StackNewSize(reader.Buffered()) + defer common.KeepAlive(_buffer) + buffer := common.Dup(_buffer) + defer buffer.Release() + _, err = buffer.ReadFullFrom(reader, reader.Buffered()) + if err != nil { + return err + } + conn = bufio.NewCachedConn(conn, buffer) + } + return HandleRequest(ctx, request, conn, authenticator, handler, metadata) } func HandleRequest(ctx context.Context, request *http.Request, conn net.Conn, authenticator auth.Authenticator, handler Handler, metadata M.Metadata) error { @@ -72,6 +94,7 @@ func HandleRequest(ctx context.Context, request *http.Request, conn net.Conn, au return responseWith(request, http.StatusBadRequest).Write(conn) } + var innerErr error if httpClient == nil { httpClient = &http.Client{ Transport: &http.Transport{ @@ -89,8 +112,8 @@ func HandleRequest(ctx context.Context, request *http.Request, conn net.Conn, au go func() { err := handler.NewConnection(ctx, right, metadata) if err != nil { + innerErr = err common.Close(left, right) - handler.HandleError(err) } }() return left, nil @@ -104,8 +127,7 @@ func HandleRequest(ctx context.Context, request *http.Request, conn net.Conn, au response, err := httpClient.Do(request) if err != nil { - handler.HandleError(err) - return responseWith(request, http.StatusBadGateway).Write(conn) + return common.AnyError(innerErr, err, responseWith(request, http.StatusBadGateway).Write(conn)) } removeHopByHopHeaders(response.Header) @@ -120,7 +142,7 @@ func HandleRequest(ctx context.Context, request *http.Request, conn net.Conn, au err = response.Write(conn) if err != nil { - return err + return common.AnyError(innerErr, err) } if !keepAlive { diff --git a/transport/mixed/listener.go b/transport/mixed/listener.go deleted file mode 100644 index e804901..0000000 --- a/transport/mixed/listener.go +++ /dev/null @@ -1,158 +0,0 @@ -package mixed - -import ( - std_bufio "bufio" - "context" - "io" - "net" - netHttp "net/http" - "net/netip" - "strings" - - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/auth" - "github.com/sagernet/sing/common/buf" - "github.com/sagernet/sing/common/bufio" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/redir" - "github.com/sagernet/sing/common/rw" - "github.com/sagernet/sing/common/udpnat" - "github.com/sagernet/sing/protocol/http" - "github.com/sagernet/sing/protocol/socks" - "github.com/sagernet/sing/protocol/socks/socks4" - "github.com/sagernet/sing/protocol/socks/socks5" - "github.com/sagernet/sing/transport/tcp" - "github.com/sagernet/sing/transport/udp" -) - -type Handler interface { - socks.Handler -} - -type Listener struct { - TCPListener *tcp.Listener - UDPListener *udp.Listener - bindAddr netip.Addr - handler Handler - authenticator auth.Authenticator - udpNat *udpnat.Service[netip.AddrPort] -} - -func NewListener(bind netip.AddrPort, authenticator auth.Authenticator, transproxy redir.TransproxyMode, udpTimeout int64, handler Handler) *Listener { - listener := &Listener{ - bindAddr: bind.Addr(), - handler: handler, - authenticator: authenticator, - } - - listener.TCPListener = tcp.NewTCPListener(bind, listener, tcp.WithTransproxyMode(transproxy)) - if transproxy == redir.ModeTProxy { - listener.UDPListener = udp.NewUDPListener(bind, listener, udp.WithTransproxyMode(transproxy)) - listener.udpNat = udpnat.New[netip.AddrPort](udpTimeout, handler) - } - return listener -} - -func (l *Listener) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { - if metadata.Destination.IsValid() { - return l.handler.NewConnection(ctx, conn, metadata) - } - headerType, err := rw.ReadByte(conn) - if err != nil { - return err - } - switch headerType { - case socks4.Version, socks5.Version: - return socks.HandleConnection0(ctx, conn, headerType, l.authenticator, l.handler, metadata) - } - - reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType}))) - request, err := http.ReadRequest(reader) - if err != nil { - return E.Cause(err, "read http request") - } - - if request.Method == "GET" && request.URL.Path == "/proxy.pac" { - content := newPAC(M.AddrPortFromNet(conn.LocalAddr())) - response := &netHttp.Response{ - StatusCode: 200, - Status: netHttp.StatusText(200), - Proto: request.Proto, - ProtoMajor: request.ProtoMajor, - ProtoMinor: request.ProtoMinor, - Header: netHttp.Header{ - "Content-Type": {"application/x-ns-proxy-autoconfig"}, - }, - ContentLength: int64(len(content)), - Body: io.NopCloser(strings.NewReader(content)), - } - err = response.Write(conn) - if err != nil { - return E.Cause(err, "write pac response") - } - return nil - } - - if reader.Buffered() > 0 { - _buffer := buf.StackNewSize(reader.Buffered()) - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - _, err = buffer.ReadFullFrom(reader, reader.Buffered()) - if err != nil { - return err - } - - conn = bufio.NewCachedConn(conn, buffer) - } - - return http.HandleRequest(ctx, request, conn, l.authenticator, l.handler, metadata) -} - -func (l *Listener) WriteIsThreadUnsafe() { -} - -func (l *Listener) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata M.Metadata) error { - l.udpNat.NewPacket(ctx, metadata.Source.AddrPort(), buffer, metadata, func(netConn N.PacketConn) N.PacketWriter { - return &tproxyPacketWriter{conn} - }) - return nil -} - -type tproxyPacketWriter struct { - source N.PacketConn -} - -func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - defer buffer.Release() - udpConn, err := redir.DialUDP("udp", destination.UDPAddr(), M.SocksaddrFromNet(w.source.LocalAddr()).UDPAddr()) - if err != nil { - return E.Cause(err, "tproxy udp write back") - } - defer udpConn.Close() - return common.Error(udpConn.Write(buffer.Bytes())) -} - -func (l *Listener) HandleError(err error) { - l.handler.HandleError(err) -} - -func (l *Listener) Start() error { - err := l.TCPListener.Start() - if err != nil { - return err - } - if l.UDPListener != nil { - err = l.UDPListener.Start() - } - return err -} - -func (l *Listener) Close() error { - return common.Close( - l.TCPListener, - l.UDPListener, - ) -} diff --git a/transport/mixed/pac.go b/transport/mixed/pac.go deleted file mode 100644 index 7835d25..0000000 --- a/transport/mixed/pac.go +++ /dev/null @@ -1,12 +0,0 @@ -package mixed - -import ( - "net/netip" -) - -func newPAC(proxyAddr netip.AddrPort) string { - return ` -function FindProxyForURL(url, host) { - return "SOCKS5 ` + proxyAddr.String() + `; PROXY ` + proxyAddr.String() + `"; -}` -} diff --git a/transport/system/sockopt_linux.go b/transport/system/sockopt_linux.go deleted file mode 100644 index 2f7335a..0000000 --- a/transport/system/sockopt_linux.go +++ /dev/null @@ -1,14 +0,0 @@ -package system - -import ( - "syscall" -) - -const ( - TCP_FASTOPEN = 23 - TCP_FASTOPEN_CONNECT = 30 -) - -func TCPFastOpen(fd uintptr) error { - return syscall.SetsockoptInt(int(fd), syscall.SOL_TCP, TCP_FASTOPEN_CONNECT, 1) -} diff --git a/transport/system/sockopt_other.go b/transport/system/sockopt_other.go deleted file mode 100644 index 804f39d..0000000 --- a/transport/system/sockopt_other.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !linux - -package system - -import "github.com/sagernet/sing/common/exceptions" - -func TCPFastOpen(fd uintptr) error { - return exceptions.New("only available on linux") -} diff --git a/transport/tcp/listener.go b/transport/tcp/listener.go deleted file mode 100644 index 3ae4a2d..0000000 --- a/transport/tcp/listener.go +++ /dev/null @@ -1,121 +0,0 @@ -package tcp - -import ( - "context" - "net" - "net/netip" - - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/debug" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/redir" -) - -type Handler interface { - N.TCPConnectionHandler - E.Handler -} - -type Listener struct { - bind netip.AddrPort - handler Handler - trans redir.TransproxyMode - lAddr *net.TCPAddr - *net.TCPListener -} - -func NewTCPListener(listen netip.AddrPort, handler Handler, options ...Option) *Listener { - listener := &Listener{ - bind: listen, - handler: handler, - } - for _, option := range options { - option(listener) - } - return listener -} - -func (l *Listener) Start() error { - tcpListener, err := net.ListenTCP(M.NetworkFromNetAddr("tcp", l.bind.Addr()), net.TCPAddrFromAddrPort(l.bind)) - if err != nil { - return err - } - if l.trans == redir.ModeTProxy { - l.lAddr = tcpListener.Addr().(*net.TCPAddr) - fd, err := common.GetFileDescriptor(tcpListener) - if err != nil { - return err - } - err = redir.TProxy(fd, l.bind.Addr().Is6()) - if err != nil { - return E.Cause(err, "configure tproxy") - } - } - l.TCPListener = tcpListener - go l.loop() - return nil -} - -func (l *Listener) Close() error { - if l == nil || l.TCPListener == nil { - return nil - } - return l.TCPListener.Close() -} - -func (l *Listener) loop() { - for { - tcpConn, err := l.AcceptTCP() - if err != nil { - l.handler.HandleError(E.New("tcp listener closed: ", err)) - l.Close() - return - } - metadata := M.Metadata{ - Source: M.SocksaddrFromNet(tcpConn.RemoteAddr()), - } - switch l.trans { - case redir.ModeRedirect: - destination, err := redir.GetOriginalDestination(tcpConn) - if err == nil { - metadata.Protocol = "redirect" - metadata.Destination = M.SocksaddrFromNetIP(destination) - } - case redir.ModeTProxy: - lAddr := tcpConn.LocalAddr().(*net.TCPAddr) - rAddr := tcpConn.RemoteAddr().(*net.TCPAddr) - - if lAddr.Port != l.lAddr.Port || !lAddr.IP.Equal(rAddr.IP) && !lAddr.IP.IsLoopback() && !lAddr.IP.IsPrivate() { - metadata.Protocol = "tproxy" - metadata.Destination = M.SocksaddrFromNet(lAddr) - } - } - go func() { - metadata.Protocol = "tcp" - hErr := l.handler.NewConnection(context.Background(), tcpConn, metadata) - if hErr != nil { - l.handler.HandleError(hErr) - } - debug.Free() - }() - } -} - -type Error struct { - Conn net.Conn - Cause error -} - -func (e *Error) Error() string { - return e.Cause.Error() -} - -func (e *Error) Unwrap() error { - return e.Cause -} - -func (e *Error) Close() error { - return common.Close(e.Conn) -} diff --git a/transport/tcp/options.go b/transport/tcp/options.go deleted file mode 100644 index 7d12a18..0000000 --- a/transport/tcp/options.go +++ /dev/null @@ -1,11 +0,0 @@ -package tcp - -import "github.com/sagernet/sing/common/redir" - -type Option func(*Listener) - -func WithTransproxyMode(mode redir.TransproxyMode) Option { - return func(listener *Listener) { - listener.trans = mode - } -} diff --git a/transport/udp/listener.go b/transport/udp/listener.go deleted file mode 100644 index b8a5fec..0000000 --- a/transport/udp/listener.go +++ /dev/null @@ -1,264 +0,0 @@ -package udp - -import ( - "context" - "net" - "net/netip" - "os" - "sync" - - "github.com/sagernet/sing/common" - "github.com/sagernet/sing/common/buf" - E "github.com/sagernet/sing/common/exceptions" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/redir" -) - -type Handler interface { - N.UDPHandler - E.Handler -} - -type Listener struct { - *net.UDPConn - handler Handler - bind netip.AddrPort - tproxy bool - forceAddr6 bool - access sync.RWMutex - closed chan struct{} - outbound chan *outboundPacket -} - -func (l *Listener) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) { - n, addr, err := l.ReadFromUDPAddrPort(buffer.FreeBytes()) - if err != nil { - return M.Socksaddr{}, err - } - buffer.Truncate(n) - return M.SocksaddrFromNetIP(addr), nil -} - -func (l *Listener) WriteIsThreadUnsafe() { -} - -func (l *Listener) loopBack() { - for { - select { - case packet := <-l.outbound: - err := l.writePacket(packet.buffer, packet.destination) - if err != nil && !E.IsClosed(err) { - l.handler.HandleError(E.New("udp write failed: ", err)) - } - continue - case <-l.closed: - } - for { - select { - case packet := <-l.outbound: - packet.buffer.Release() - default: - return - } - } - } -} - -type outboundPacket struct { - buffer *buf.Buffer - destination M.Socksaddr -} - -func (l *Listener) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - l.access.RLock() - defer l.access.RUnlock() - - select { - case <-l.closed: - return os.ErrClosed - default: - } - - l.outbound <- &outboundPacket{buffer, destination} - return nil -} - -func (l *Listener) writePacket(buffer *buf.Buffer, destination M.Socksaddr) error { - defer buffer.Release() - if destination.Family().IsFqdn() { - udpAddr, err := net.ResolveUDPAddr("udp", destination.String()) - if err != nil { - return err - } - return common.Error(l.UDPConn.WriteTo(buffer.Bytes(), udpAddr)) - } - if l.forceAddr6 && destination.Addr.Is4() { - destination.Addr = netip.AddrFrom16(destination.Addr.As16()) - } - return common.Error(l.UDPConn.WriteToUDPAddrPort(buffer.Bytes(), destination.AddrPort())) -} - -func NewUDPListener(listen netip.AddrPort, handler Handler, options ...Option) *Listener { - listener := &Listener{ - handler: handler, - bind: listen, - outbound: make(chan *outboundPacket), - closed: make(chan struct{}), - } - for _, option := range options { - option(listener) - } - return listener -} - -func (l *Listener) Start() error { - udpConn, err := net.ListenUDP(M.NetworkFromNetAddr("udp", l.bind.Addr()), net.UDPAddrFromAddrPort(l.bind)) - if err != nil { - return err - } - l.forceAddr6 = l.bind.Addr().Is6() - - if l.tproxy { - fd, err := common.GetFileDescriptor(udpConn) - if err != nil { - return err - } - err = redir.TProxy(fd, l.bind.Addr().Is6()) - if err != nil { - return E.Cause(err, "configure tproxy") - } - err = redir.TProxyUDP(fd, l.bind.Addr().Is6()) - if err != nil { - return E.Cause(err, "configure tproxy") - } - } - - l.UDPConn = udpConn - - if _, threadUnsafeHandler := common.Cast[N.ThreadUnsafeWriter](l.handler); threadUnsafeHandler { - go l.loopThreadSafe() - } else { - go l.loop() - } - - go l.loopBack() - return nil -} - -func (l *Listener) Close() error { - if l == nil || l.UDPConn == nil { - return nil - } - return l.UDPConn.Close() -} - -func (l *Listener) loop() { - defer close(l.closed) - - _buffer := buf.StackNewPacket() - defer common.KeepAlive(_buffer) - buffer := common.Dup(_buffer) - defer buffer.Release() - buffer.IncRef() - defer buffer.DecRef() - if !l.tproxy { - for { - buffer.Reset() - n, addr, err := l.ReadFromUDPAddrPort(buffer.FreeBytes()) - if err != nil { - l.handler.HandleError(E.New("udp listener closed: ", err)) - return - } - buffer.Truncate(n) - err = l.handler.NewPacket(context.Background(), l, buffer, M.Metadata{ - Protocol: "udp", - Source: M.SocksaddrFromNetIP(addr), - }) - if err != nil { - l.handler.HandleError(err) - } - } - } else { - _oob := make([]byte, 1024) - defer common.KeepAlive(_oob) - oob := common.Dup(_oob) - for { - buffer.Reset() - n, oobN, _, addr, err := l.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob) - if err != nil { - l.handler.HandleError(E.New("udp listener closed: ", err)) - return - } - buffer.Truncate(n) - destination, err := redir.GetOriginalDestinationFromOOB(oob[:oobN]) - if err != nil { - l.handler.HandleError(E.Cause(err, "get original destination")) - continue - } - buffer.Resize(buf.ReversedHeader, n) - err = l.handler.NewPacket(context.Background(), l, buffer, M.Metadata{ - Protocol: "tproxy", - Source: M.SocksaddrFromNetIP(addr), - Destination: M.SocksaddrFromNetIP(destination), - }) - if err != nil { - l.handler.HandleError(err) - } - } - } -} - -func (l *Listener) loopThreadSafe() { - defer close(l.closed) - - if !l.tproxy { - for { - buffer := buf.NewPacket() - n, addr, err := l.ReadFromUDPAddrPort(buffer.FreeBytes()) - if err != nil { - buffer.Release() - l.handler.HandleError(E.New("udp listener closed: ", err)) - return - } - buffer.Truncate(n) - err = l.handler.NewPacket(context.Background(), l, buffer, M.Metadata{ - Protocol: "udp", - Source: M.SocksaddrFromNetIP(addr), - }) - if err != nil { - buffer.Release() - l.handler.HandleError(err) - } - } - } else { - _oob := make([]byte, 1024) - defer common.KeepAlive(_oob) - oob := common.Dup(_oob) - for { - buffer := buf.NewPacket() - n, oobN, _, addr, err := l.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob) - if err != nil { - l.handler.HandleError(E.New("udp listener closed: ", err)) - return - } - buffer.Truncate(n) - destination, err := redir.GetOriginalDestinationFromOOB(oob[:oobN]) - if err != nil { - buffer.Release() - l.handler.HandleError(E.Cause(err, "get original destination")) - continue - } - buffer.Resize(buf.ReversedHeader, n) - err = l.handler.NewPacket(context.Background(), l, buffer, M.Metadata{ - Protocol: "tproxy", - Source: M.SocksaddrFromNetIP(addr), - Destination: M.SocksaddrFromNetIP(destination), - }) - if err != nil { - buffer.Release() - l.handler.HandleError(err) - } - } - } -} diff --git a/transport/udp/options.go b/transport/udp/options.go deleted file mode 100644 index 2dab220..0000000 --- a/transport/udp/options.go +++ /dev/null @@ -1,11 +0,0 @@ -package udp - -import "github.com/sagernet/sing/common/redir" - -type Option func(*Listener) - -func WithTransproxyMode(mode redir.TransproxyMode) Option { - return func(listener *Listener) { - listener.tproxy = mode == redir.ModeTProxy - } -}