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

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