Files
sing-box-extended-mirror/protocol/direct/outbound.go
T

261 lines
8.6 KiB
Go
Raw Normal View History

2024-11-02 00:39:02 +08:00
package direct
2022-06-30 21:27:56 +08:00
import (
"context"
"net"
2022-08-23 21:07:35 +08:00
"net/netip"
"reflect"
2022-09-03 10:01:09 +08:00
"time"
2022-06-30 21:27:56 +08:00
"github.com/sagernet/sing-box/adapter"
2024-11-02 00:39:02 +08:00
"github.com/sagernet/sing-box/adapter/outbound"
2022-07-07 21:47:21 +08:00
"github.com/sagernet/sing-box/common/dialer"
2022-06-30 21:27:56 +08:00
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
2022-07-02 14:07:50 +08:00
"github.com/sagernet/sing-box/option"
2025-02-17 22:00:57 +08:00
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing-tun/ping"
"github.com/sagernet/sing/common"
2026-07-06 14:26:32 +08:00
"github.com/sagernet/sing/common/control"
2022-08-23 21:07:35 +08:00
E "github.com/sagernet/sing/common/exceptions"
2024-11-02 00:39:02 +08:00
"github.com/sagernet/sing/common/logger"
2022-07-08 23:03:57 +08:00
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
2026-06-03 10:37:53 +08:00
"github.com/sagernet/sing/service"
2022-06-30 21:27:56 +08:00
)
2024-11-02 00:39:02 +08:00
func RegisterOutbound(registry *outbound.Registry) {
outbound.Register[option.DirectOutboundOptions](registry, C.TypeDirect, NewOutbound)
}
2024-11-12 19:37:10 +08:00
var (
2026-07-19 17:50:02 +08:00
_ N.ParallelDialer = (*Outbound)(nil)
_ dialer.ParallelNetworkDialer = (*Outbound)(nil)
_ dialer.DirectDialer = (*Outbound)(nil)
_ adapter.FlowOutbound = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
2024-11-12 19:37:10 +08:00
)
2022-06-30 21:27:56 +08:00
2024-11-02 00:39:02 +08:00
type Outbound struct {
outbound.Adapter
2026-02-28 17:55:56 +08:00
ctx context.Context
logger logger.ContextLogger
2026-06-03 10:37:53 +08:00
network adapter.NetworkManager
2026-02-28 17:55:56 +08:00
dialer dialer.ParallelInterfaceDialer
domainStrategy C.DomainStrategy
fallbackDelay time.Duration
isEmpty bool
2026-06-03 10:37:53 +08:00
myAddresses common.TypedValue[[]netip.Prefix]
2026-07-06 14:26:32 +08:00
icmpPort *ping.Port
2022-06-30 21:27:56 +08:00
}
2024-11-02 00:39:02 +08:00
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
2022-09-21 15:32:32 +08:00
options.UDPFragmentDefault = true
2025-01-12 12:45:27 +08:00
if options.Detour != "" {
return nil, E.New("`detour` is not supported in direct context")
}
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
Context: ctx,
Options: options.DialerOptions,
RemoteIsDomain: true,
DirectOutbound: true,
})
2023-08-08 16:14:03 +08:00
if err != nil {
return nil, err
}
2024-11-02 00:39:02 +08:00
outbound := &Outbound{
2025-02-17 22:00:57 +08:00
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
ctx: ctx,
2025-01-12 12:45:27 +08:00
logger: logger,
2026-06-03 10:37:53 +08:00
network: service.FromContext[adapter.NetworkManager](ctx),
2025-01-12 12:45:27 +08:00
//nolint:staticcheck
2025-03-16 14:50:44 +08:00
domainStrategy: C.DomainStrategy(options.DomainStrategy),
2024-12-15 00:45:41 +08:00
fallbackDelay: time.Duration(options.FallbackDelay),
2025-01-12 12:45:27 +08:00
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
2026-02-28 17:55:56 +08:00
isEmpty: reflect.DeepEqual(options.DialerOptions, option.DialerOptions{UDPFragmentDefault: true}),
2022-08-23 21:07:35 +08:00
}
2024-11-23 22:34:02 +08:00
//nolint:staticcheck
2023-10-25 12:00:00 +08:00
if options.ProxyProtocol != 0 {
return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0")
2022-06-30 21:27:56 +08:00
}
2026-07-06 14:26:32 +08:00
if defaultDialer, isDefaultDialer := common.Cast[*dialer.DefaultDialer](outbound.dialer); isDefaultDialer {
outbound.icmpPort = ping.NewPort(ctx, logger, func(destination netip.Addr) control.Func {
return defaultDialer.DialerForICMPDestination(destination).Control
}, 0)
}
2022-08-23 21:07:35 +08:00
return outbound, nil
2022-06-30 21:27:56 +08:00
}
2026-06-03 10:37:53 +08:00
func (h *Outbound) Start(stage adapter.StartStage) error {
switch stage {
case adapter.StartStatePostStart, adapter.StartStateStarted:
2026-07-19 17:50:02 +08:00
if len(h.myAddresses.Load()) == 0 {
h.fetchMyAddresses()
}
2026-06-03 10:37:53 +08:00
}
return nil
}
func (h *Outbound) fetchMyAddresses() {
myInterfaceNames := h.network.InterfaceMonitor().MyInterfaces()
if len(myInterfaceNames) == 0 {
return
}
2026-07-19 17:50:02 +08:00
var (
myAddresses []netip.Prefix
found bool
)
2026-06-03 10:37:53 +08:00
for _, myInterfaceName := range myInterfaceNames {
myInterface, err := h.network.InterfaceFinder().ByName(myInterfaceName)
if err != nil {
continue
}
2026-07-19 17:50:02 +08:00
found = true
2026-06-03 10:37:53 +08:00
myAddresses = append(myAddresses, myInterface.Addresses...)
}
2026-07-19 17:50:02 +08:00
if !found {
return
}
2026-06-03 10:37:53 +08:00
h.myAddresses.Store(myAddresses)
}
2026-07-19 17:50:02 +08:00
func (h *Outbound) InterfaceUpdated() {
h.fetchMyAddresses()
if h.icmpPort != nil {
h.icmpPort.Close()
}
}
2026-06-03 10:37:53 +08:00
func (h *Outbound) isMyLoopbackAddress(addresses ...netip.Addr) bool {
for _, prefix := range h.myAddresses.Load() {
for _, address := range addresses {
if !C.IsDarwin && prefix.Addr() == address {
continue
}
if prefix.Contains(address) {
2026-06-03 10:37:53 +08:00
return true
}
}
}
return false
}
2024-11-02 00:39:02 +08:00
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
2026-06-03 10:37:53 +08:00
if h.isMyLoopbackAddress(destination.Addr) {
return nil, E.New("loopback connection to TUN range")
}
2024-10-27 07:45:15 +08:00
ctx, metadata := adapter.ExtendContext(ctx)
2024-11-02 00:39:02 +08:00
metadata.Outbound = h.Tag()
2022-07-07 23:36:32 +08:00
metadata.Destination = destination
2022-08-23 21:07:35 +08:00
network = N.NetworkName(network)
2022-06-30 21:27:56 +08:00
switch network {
2022-07-30 00:29:22 +08:00
case N.NetworkTCP:
2022-07-12 15:17:29 +08:00
h.logger.InfoContext(ctx, "outbound connection to ", destination)
2022-07-30 00:29:22 +08:00
case N.NetworkUDP:
2022-07-12 15:17:29 +08:00
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
2022-06-30 21:27:56 +08:00
}
2024-10-21 23:38:34 +08:00
return h.dialer.DialContext(ctx, network, destination)
2022-09-03 10:01:09 +08:00
}
2024-11-12 19:37:10 +08:00
func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
2026-06-03 10:37:53 +08:00
if h.isMyLoopbackAddress(destination.Addr) {
return nil, E.New("loopback connection to TUN range")
}
2024-11-12 19:37:10 +08:00
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination
2026-02-28 17:55:56 +08:00
h.logger.InfoContext(ctx, "outbound packet connection")
2024-11-12 19:37:10 +08:00
conn, err := h.dialer.ListenPacket(ctx, destination)
if err != nil {
return nil, err
}
return conn, nil
}
2026-07-08 11:14:42 +08:00
func (h *Outbound) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction {
if network == N.NetworkICMP && h.icmpPort != nil {
return adapter.PreMatchFlow
}
return adapter.PreMatchContinue
2026-07-06 14:26:32 +08:00
}
func (h *Outbound) PortAddresses() (netip.Addr, netip.Addr) {
return h.icmpPort.PortAddresses()
}
func (h *Outbound) PortMTU() uint32 {
return h.icmpPort.PortMTU()
}
func (h *Outbound) AttachReturn(returnPath tun.Return) error {
return h.icmpPort.AttachReturn(returnPath)
}
func (h *Outbound) DetachReturn(returnPath tun.Return) error {
return h.icmpPort.DetachReturn(returnPath)
}
func (h *Outbound) WritePackets(packets [][]byte) error {
return h.icmpPort.WritePackets(packets)
}
func (h *Outbound) Close() error {
if h.icmpPort != nil {
return h.icmpPort.Close()
2025-02-17 22:00:57 +08:00
}
2026-07-06 14:26:32 +08:00
return nil
2025-02-17 22:00:57 +08:00
}
2024-11-02 00:39:02 +08:00
func (h *Outbound) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
2026-06-03 10:37:53 +08:00
if h.isMyLoopbackAddress(destinationAddresses...) {
return nil, E.New("loopback connection to TUN range")
}
2024-10-27 07:45:15 +08:00
ctx, metadata := adapter.ExtendContext(ctx)
2024-11-02 00:39:02 +08:00
metadata.Outbound = h.Tag()
2022-09-03 10:01:09 +08:00
metadata.Destination = destination
network = N.NetworkName(network)
switch network {
case N.NetworkTCP:
h.logger.InfoContext(ctx, "outbound connection to ", destination)
case N.NetworkUDP:
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
}
2025-09-02 17:19:08 +08:00
return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, len(destinationAddresses) > 0 && destinationAddresses[0].Is6(), nil, nil, nil, h.fallbackDelay)
2022-06-30 21:27:56 +08:00
}
2024-12-15 00:45:41 +08:00
func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
2026-06-03 10:37:53 +08:00
if h.isMyLoopbackAddress(destinationAddresses...) {
return nil, E.New("loopback connection to TUN range")
}
2024-11-12 19:37:10 +08:00
ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag()
metadata.Destination = destination
network = N.NetworkName(network)
switch network {
case N.NetworkTCP:
h.logger.InfoContext(ctx, "outbound connection to ", destination)
case N.NetworkUDP:
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
}
2025-09-02 17:19:08 +08:00
return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, len(destinationAddresses) > 0 && destinationAddresses[0].Is6(), networkStrategy, networkType, fallbackNetworkType, fallbackDelay)
2024-11-12 19:37:10 +08:00
}
2024-12-15 00:45:41 +08:00
func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
2026-06-03 10:37:53 +08:00
if h.isMyLoopbackAddress(destinationAddresses...) {
return nil, netip.Addr{}, E.New("loopback connection to TUN range")
}
2023-10-25 12:00:00 +08:00
ctx, metadata := adapter.ExtendContext(ctx)
2024-11-02 00:39:02 +08:00
metadata.Outbound = h.Tag()
2022-07-07 23:36:32 +08:00
metadata.Destination = destination
2026-02-28 17:55:56 +08:00
h.logger.InfoContext(ctx, "outbound packet connection")
2024-11-13 19:05:28 +08:00
conn, newDestination, err := dialer.ListenSerialNetworkPacket(ctx, h.dialer, destination, destinationAddresses, networkStrategy, networkType, fallbackNetworkType, fallbackDelay)
2022-12-21 21:58:03 +08:00
if err != nil {
2024-11-12 19:37:10 +08:00
return nil, netip.Addr{}, err
2022-12-21 21:58:03 +08:00
}
2024-11-12 19:37:10 +08:00
return conn, newDestination, nil
2022-06-30 21:27:56 +08:00
}
func (h *Outbound) IsEmpty() bool {
return h.isEmpty
}