github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/outbound/default.go (about)

     1  package outbound
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"net/netip"
     7  	"os"
     8  	"time"
     9  
    10  	"github.com/inazumav/sing-box/adapter"
    11  	C "github.com/inazumav/sing-box/constant"
    12  	"github.com/inazumav/sing-box/log"
    13  	"github.com/inazumav/sing-box/option"
    14  	"github.com/sagernet/sing/common"
    15  	"github.com/sagernet/sing/common/buf"
    16  	"github.com/sagernet/sing/common/bufio"
    17  	"github.com/sagernet/sing/common/canceler"
    18  	E "github.com/sagernet/sing/common/exceptions"
    19  	N "github.com/sagernet/sing/common/network"
    20  )
    21  
    22  type myOutboundAdapter struct {
    23  	protocol     string
    24  	network      []string
    25  	router       adapter.Router
    26  	logger       log.ContextLogger
    27  	tag          string
    28  	dependencies []string
    29  }
    30  
    31  func (a *myOutboundAdapter) Type() string {
    32  	return a.protocol
    33  }
    34  
    35  func (a *myOutboundAdapter) Tag() string {
    36  	return a.tag
    37  }
    38  
    39  func (a *myOutboundAdapter) Network() []string {
    40  	return a.network
    41  }
    42  
    43  func (a *myOutboundAdapter) Dependencies() []string {
    44  	return a.dependencies
    45  }
    46  
    47  func (a *myOutboundAdapter) NewError(ctx context.Context, err error) {
    48  	NewError(a.logger, ctx, err)
    49  }
    50  
    51  func withDialerDependency(options option.DialerOptions) []string {
    52  	if options.Detour != "" {
    53  		return []string{options.Detour}
    54  	}
    55  	return nil
    56  }
    57  
    58  func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
    59  	ctx = adapter.WithContext(ctx, &metadata)
    60  	var outConn net.Conn
    61  	var err error
    62  	if len(metadata.DestinationAddresses) > 0 {
    63  		outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses)
    64  	} else {
    65  		outConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination)
    66  	}
    67  	if err != nil {
    68  		return N.HandshakeFailure(conn, err)
    69  	}
    70  	return CopyEarlyConn(ctx, conn, outConn)
    71  }
    72  
    73  func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error {
    74  	ctx = adapter.WithContext(ctx, &metadata)
    75  	var outConn net.Conn
    76  	var err error
    77  	if len(metadata.DestinationAddresses) > 0 {
    78  		outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses)
    79  	} else if metadata.Destination.IsFqdn() {
    80  		var destinationAddresses []netip.Addr
    81  		destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn)
    82  		if err != nil {
    83  			return N.HandshakeFailure(conn, err)
    84  		}
    85  		outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, destinationAddresses)
    86  	} else {
    87  		outConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination)
    88  	}
    89  	if err != nil {
    90  		return N.HandshakeFailure(conn, err)
    91  	}
    92  	return CopyEarlyConn(ctx, conn, outConn)
    93  }
    94  
    95  func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
    96  	ctx = adapter.WithContext(ctx, &metadata)
    97  	var outConn net.PacketConn
    98  	var destinationAddress netip.Addr
    99  	var err error
   100  	if len(metadata.DestinationAddresses) > 0 {
   101  		outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses)
   102  	} else {
   103  		outConn, err = this.ListenPacket(ctx, metadata.Destination)
   104  	}
   105  	if err != nil {
   106  		return N.HandshakeFailure(conn, err)
   107  	}
   108  	if destinationAddress.IsValid() {
   109  		if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
   110  			natConn.UpdateDestination(destinationAddress)
   111  		}
   112  	}
   113  	switch metadata.Protocol {
   114  	case C.ProtocolSTUN:
   115  		ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
   116  	case C.ProtocolQUIC:
   117  		ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout)
   118  	case C.ProtocolDNS:
   119  		ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout)
   120  	}
   121  	return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
   122  }
   123  
   124  func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error {
   125  	ctx = adapter.WithContext(ctx, &metadata)
   126  	var outConn net.PacketConn
   127  	var destinationAddress netip.Addr
   128  	var err error
   129  	if len(metadata.DestinationAddresses) > 0 {
   130  		outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses)
   131  	} else if metadata.Destination.IsFqdn() {
   132  		var destinationAddresses []netip.Addr
   133  		destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn)
   134  		if err != nil {
   135  			return N.HandshakeFailure(conn, err)
   136  		}
   137  		outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, destinationAddresses)
   138  	} else {
   139  		outConn, err = this.ListenPacket(ctx, metadata.Destination)
   140  	}
   141  	if err != nil {
   142  		return N.HandshakeFailure(conn, err)
   143  	}
   144  	if destinationAddress.IsValid() {
   145  		if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded {
   146  			natConn.UpdateDestination(destinationAddress)
   147  		}
   148  	}
   149  	switch metadata.Protocol {
   150  	case C.ProtocolSTUN:
   151  		ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout)
   152  	case C.ProtocolQUIC:
   153  		ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout)
   154  	case C.ProtocolDNS:
   155  		ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout)
   156  	}
   157  	return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
   158  }
   159  
   160  func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error {
   161  	if cachedReader, isCached := conn.(N.CachedReader); isCached {
   162  		payload := cachedReader.ReadCached()
   163  		if payload != nil && !payload.IsEmpty() {
   164  			_, err := serverConn.Write(payload.Bytes())
   165  			if err != nil {
   166  				return err
   167  			}
   168  			return bufio.CopyConn(ctx, conn, serverConn)
   169  		}
   170  	}
   171  	if earlyConn, isEarlyConn := common.Cast[N.EarlyConn](serverConn); isEarlyConn && earlyConn.NeedHandshake() {
   172  		payload := buf.NewPacket()
   173  		err := conn.SetReadDeadline(time.Now().Add(C.ReadPayloadTimeout))
   174  		if err != os.ErrInvalid {
   175  			if err != nil {
   176  				return err
   177  			}
   178  			_, err = payload.ReadOnceFrom(conn)
   179  			if err != nil && !E.IsTimeout(err) {
   180  				return E.Cause(err, "read payload")
   181  			}
   182  			err = conn.SetReadDeadline(time.Time{})
   183  			if err != nil {
   184  				payload.Release()
   185  				return err
   186  			}
   187  		}
   188  		_, err = serverConn.Write(payload.Bytes())
   189  		if err != nil {
   190  			return N.HandshakeFailure(conn, err)
   191  		}
   192  		payload.Release()
   193  	}
   194  	return bufio.CopyConn(ctx, conn, serverConn)
   195  }
   196  
   197  func NewError(logger log.ContextLogger, ctx context.Context, err error) {
   198  	common.Close(err)
   199  	if E.IsClosedOrCanceled(err) {
   200  		logger.DebugContext(ctx, "connection closed: ", err)
   201  		return
   202  	}
   203  	logger.ErrorContext(ctx, err)
   204  }