github.com/sagernet/sing-box@v1.9.0-rc.20/inbound/tun.go (about)

     1  package inbound
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/sagernet/sing-box/adapter"
    11  	"github.com/sagernet/sing-box/common/taskmonitor"
    12  	C "github.com/sagernet/sing-box/constant"
    13  	"github.com/sagernet/sing-box/experimental/libbox/platform"
    14  	"github.com/sagernet/sing-box/log"
    15  	"github.com/sagernet/sing-box/option"
    16  	"github.com/sagernet/sing-tun"
    17  	"github.com/sagernet/sing/common"
    18  	E "github.com/sagernet/sing/common/exceptions"
    19  	M "github.com/sagernet/sing/common/metadata"
    20  	N "github.com/sagernet/sing/common/network"
    21  	"github.com/sagernet/sing/common/ranges"
    22  )
    23  
    24  var _ adapter.Inbound = (*Tun)(nil)
    25  
    26  type Tun struct {
    27  	tag                    string
    28  	ctx                    context.Context
    29  	router                 adapter.Router
    30  	logger                 log.ContextLogger
    31  	inboundOptions         option.InboundOptions
    32  	tunOptions             tun.Options
    33  	endpointIndependentNat bool
    34  	udpTimeout             int64
    35  	stack                  string
    36  	tunIf                  tun.Tun
    37  	tunStack               tun.Stack
    38  	platformInterface      platform.Interface
    39  	platformOptions        option.TunPlatformOptions
    40  }
    41  
    42  func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions, platformInterface platform.Interface) (*Tun, error) {
    43  	tunMTU := options.MTU
    44  	if tunMTU == 0 {
    45  		tunMTU = 9000
    46  	}
    47  	var udpTimeout time.Duration
    48  	if options.UDPTimeout != 0 {
    49  		udpTimeout = time.Duration(options.UDPTimeout)
    50  	} else {
    51  		udpTimeout = C.UDPTimeout
    52  	}
    53  	includeUID := uidToRange(options.IncludeUID)
    54  	if len(options.IncludeUIDRange) > 0 {
    55  		var err error
    56  		includeUID, err = parseRange(includeUID, options.IncludeUIDRange)
    57  		if err != nil {
    58  			return nil, E.Cause(err, "parse include_uid_range")
    59  		}
    60  	}
    61  	excludeUID := uidToRange(options.ExcludeUID)
    62  	if len(options.ExcludeUIDRange) > 0 {
    63  		var err error
    64  		excludeUID, err = parseRange(excludeUID, options.ExcludeUIDRange)
    65  		if err != nil {
    66  			return nil, E.Cause(err, "parse exclude_uid_range")
    67  		}
    68  	}
    69  	return &Tun{
    70  		tag:            tag,
    71  		ctx:            ctx,
    72  		router:         router,
    73  		logger:         logger,
    74  		inboundOptions: options.InboundOptions,
    75  		tunOptions: tun.Options{
    76  			Name:                     options.InterfaceName,
    77  			MTU:                      tunMTU,
    78  			GSO:                      options.GSO,
    79  			Inet4Address:             options.Inet4Address,
    80  			Inet6Address:             options.Inet6Address,
    81  			AutoRoute:                options.AutoRoute,
    82  			StrictRoute:              options.StrictRoute,
    83  			IncludeInterface:         options.IncludeInterface,
    84  			ExcludeInterface:         options.ExcludeInterface,
    85  			Inet4RouteAddress:        options.Inet4RouteAddress,
    86  			Inet6RouteAddress:        options.Inet6RouteAddress,
    87  			Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress,
    88  			Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress,
    89  			IncludeUID:               includeUID,
    90  			ExcludeUID:               excludeUID,
    91  			IncludeAndroidUser:       options.IncludeAndroidUser,
    92  			IncludePackage:           options.IncludePackage,
    93  			ExcludePackage:           options.ExcludePackage,
    94  			InterfaceMonitor:         router.InterfaceMonitor(),
    95  			TableIndex:               2022,
    96  		},
    97  		endpointIndependentNat: options.EndpointIndependentNat,
    98  		udpTimeout:             int64(udpTimeout.Seconds()),
    99  		stack:                  options.Stack,
   100  		platformInterface:      platformInterface,
   101  		platformOptions:        common.PtrValueOrDefault(options.Platform),
   102  	}, nil
   103  }
   104  
   105  func uidToRange(uidList option.Listable[uint32]) []ranges.Range[uint32] {
   106  	return common.Map(uidList, func(uid uint32) ranges.Range[uint32] {
   107  		return ranges.NewSingle(uid)
   108  	})
   109  }
   110  
   111  func parseRange(uidRanges []ranges.Range[uint32], rangeList []string) ([]ranges.Range[uint32], error) {
   112  	for _, uidRange := range rangeList {
   113  		if !strings.Contains(uidRange, ":") {
   114  			return nil, E.New("missing ':' in range: ", uidRange)
   115  		}
   116  		subIndex := strings.Index(uidRange, ":")
   117  		if subIndex == 0 {
   118  			return nil, E.New("missing range start: ", uidRange)
   119  		} else if subIndex == len(uidRange)-1 {
   120  			return nil, E.New("missing range end: ", uidRange)
   121  		}
   122  		var start, end uint64
   123  		var err error
   124  		start, err = strconv.ParseUint(uidRange[:subIndex], 10, 32)
   125  		if err != nil {
   126  			return nil, E.Cause(err, "parse range start")
   127  		}
   128  		end, err = strconv.ParseUint(uidRange[subIndex+1:], 10, 32)
   129  		if err != nil {
   130  			return nil, E.Cause(err, "parse range end")
   131  		}
   132  		uidRanges = append(uidRanges, ranges.New(uint32(start), uint32(end)))
   133  	}
   134  	return uidRanges, nil
   135  }
   136  
   137  func (t *Tun) Type() string {
   138  	return C.TypeTun
   139  }
   140  
   141  func (t *Tun) Tag() string {
   142  	return t.tag
   143  }
   144  
   145  func (t *Tun) Start() error {
   146  	if C.IsAndroid && t.platformInterface == nil {
   147  		t.tunOptions.BuildAndroidRules(t.router.PackageManager(), t)
   148  	}
   149  	if t.tunOptions.Name == "" {
   150  		t.tunOptions.Name = tun.CalculateInterfaceName("")
   151  	}
   152  	var (
   153  		tunInterface tun.Tun
   154  		err          error
   155  	)
   156  	monitor := taskmonitor.New(t.logger, C.StartTimeout)
   157  	monitor.Start("open tun interface")
   158  	if t.platformInterface != nil {
   159  		tunInterface, err = t.platformInterface.OpenTun(&t.tunOptions, t.platformOptions)
   160  	} else {
   161  		tunInterface, err = tun.New(t.tunOptions)
   162  	}
   163  	monitor.Finish()
   164  	if err != nil {
   165  		return E.Cause(err, "configure tun interface")
   166  	}
   167  	t.logger.Trace("creating stack")
   168  	t.tunIf = tunInterface
   169  	var (
   170  		forwarderBindInterface bool
   171  		includeAllNetworks     bool
   172  	)
   173  	if t.platformInterface != nil {
   174  		forwarderBindInterface = true
   175  		includeAllNetworks = t.platformInterface.IncludeAllNetworks()
   176  	}
   177  	t.tunStack, err = tun.NewStack(t.stack, tun.StackOptions{
   178  		Context:                t.ctx,
   179  		Tun:                    tunInterface,
   180  		TunOptions:             t.tunOptions,
   181  		EndpointIndependentNat: t.endpointIndependentNat,
   182  		UDPTimeout:             t.udpTimeout,
   183  		Handler:                t,
   184  		Logger:                 t.logger,
   185  		ForwarderBindInterface: forwarderBindInterface,
   186  		InterfaceFinder:        t.router.InterfaceFinder(),
   187  		IncludeAllNetworks:     includeAllNetworks,
   188  	})
   189  	if err != nil {
   190  		return err
   191  	}
   192  	monitor.Start("initiating tun stack")
   193  	err = t.tunStack.Start()
   194  	monitor.Finish()
   195  	if err != nil {
   196  		return err
   197  	}
   198  	t.logger.Info("started at ", t.tunOptions.Name)
   199  	return nil
   200  }
   201  
   202  func (t *Tun) Close() error {
   203  	return common.Close(
   204  		t.tunStack,
   205  		t.tunIf,
   206  	)
   207  }
   208  
   209  func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error {
   210  	ctx = log.ContextWithNewID(ctx)
   211  	var metadata adapter.InboundContext
   212  	metadata.Inbound = t.tag
   213  	metadata.InboundType = C.TypeTun
   214  	metadata.Source = upstreamMetadata.Source
   215  	metadata.Destination = upstreamMetadata.Destination
   216  	metadata.InboundOptions = t.inboundOptions
   217  	t.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
   218  	t.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
   219  	err := t.router.RouteConnection(ctx, conn, metadata)
   220  	if err != nil {
   221  		t.NewError(ctx, err)
   222  	}
   223  	return nil
   224  }
   225  
   226  func (t *Tun) NewPacketConnection(ctx context.Context, conn N.PacketConn, upstreamMetadata M.Metadata) error {
   227  	ctx = log.ContextWithNewID(ctx)
   228  	var metadata adapter.InboundContext
   229  	metadata.Inbound = t.tag
   230  	metadata.InboundType = C.TypeTun
   231  	metadata.Source = upstreamMetadata.Source
   232  	metadata.Destination = upstreamMetadata.Destination
   233  	metadata.InboundOptions = t.inboundOptions
   234  	t.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
   235  	t.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
   236  	err := t.router.RoutePacketConnection(ctx, conn, metadata)
   237  	if err != nil {
   238  		t.NewError(ctx, err)
   239  	}
   240  	return nil
   241  }
   242  
   243  func (t *Tun) NewError(ctx context.Context, err error) {
   244  	NewError(t.logger, ctx, err)
   245  }