package outbound import ( "context" "net" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) var _ adapter.Outbound = (*Direct)(nil) type Direct struct { myOutboundAdapter dialer N.Dialer overrideOption int overrideDestination M.Socksaddr } func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) *Direct { outbound := &Direct{ myOutboundAdapter: myOutboundAdapter{ protocol: C.TypeDirect, logger: logger, tag: tag, network: []string{C.NetworkTCP, C.NetworkUDP}, }, dialer: dialer.NewOutbound(router, options.OutboundDialerOptions), } if options.OverrideAddress != "" && options.OverridePort != 0 { outbound.overrideOption = 1 outbound.overrideDestination = M.ParseSocksaddrHostPort(options.OverrideAddress, options.OverridePort) } else if options.OverrideAddress != "" { outbound.overrideOption = 2 outbound.overrideDestination = M.ParseSocksaddrHostPort(options.OverrideAddress, options.OverridePort) } else if options.OverridePort != 0 { outbound.overrideOption = 3 outbound.overrideDestination = M.Socksaddr{Port: options.OverridePort} } return outbound } func (h *Direct) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { ctx, metadata := adapter.AppendContext(ctx) metadata.Outbound = h.tag metadata.Destination = destination switch h.overrideOption { case 1: destination = h.overrideDestination case 2: newDestination := h.overrideDestination newDestination.Port = destination.Port destination = newDestination case 3: destination.Port = h.overrideDestination.Port } switch network { case C.NetworkTCP: h.logger.InfoContext(ctx, "outbound connection to ", destination) case C.NetworkUDP: h.logger.InfoContext(ctx, "outbound packet connection to ", destination) } return h.dialer.DialContext(ctx, network, destination) } func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { ctx, metadata := adapter.AppendContext(ctx) metadata.Outbound = h.tag metadata.Destination = destination h.logger.InfoContext(ctx, "outbound packet connection") return h.dialer.ListenPacket(ctx, destination) } func (h *Direct) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { ctx = adapter.WithContext(ctx, &metadata) outConn, err := h.DialContext(ctx, C.NetworkTCP, metadata.Destination) if err != nil { return err } return bufio.CopyConn(ctx, conn, outConn) } func (h *Direct) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { return NewPacketConnection(ctx, h, conn, metadata) }