github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/libbox/service.go (about)

     1  package libbox
     2  
     3  import (
     4  	"context"
     5  	"net/netip"
     6  	"os"
     7  	"runtime"
     8  	runtimeDebug "runtime/debug"
     9  	"syscall"
    10  	"time"
    11  
    12  	"github.com/sagernet/sing-box"
    13  	"github.com/sagernet/sing-box/adapter"
    14  	"github.com/sagernet/sing-box/common/process"
    15  	"github.com/sagernet/sing-box/common/urltest"
    16  	C "github.com/sagernet/sing-box/constant"
    17  	"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
    18  	"github.com/sagernet/sing-box/experimental/libbox/platform"
    19  	"github.com/sagernet/sing-box/log"
    20  	"github.com/sagernet/sing-box/option"
    21  	"github.com/sagernet/sing-tun"
    22  	"github.com/sagernet/sing/common"
    23  	"github.com/sagernet/sing/common/control"
    24  	E "github.com/sagernet/sing/common/exceptions"
    25  	"github.com/sagernet/sing/common/logger"
    26  	N "github.com/sagernet/sing/common/network"
    27  	"github.com/sagernet/sing/service"
    28  	"github.com/sagernet/sing/service/filemanager"
    29  	"github.com/sagernet/sing/service/pause"
    30  )
    31  
    32  type BoxService struct {
    33  	ctx                   context.Context
    34  	cancel                context.CancelFunc
    35  	instance              *box.Box
    36  	pauseManager          pause.Manager
    37  	urlTestHistoryStorage *urltest.HistoryStorage
    38  
    39  	servicePauseFields
    40  }
    41  
    42  func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
    43  	options, err := parseConfig(configContent)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	runtimeDebug.FreeOSMemory()
    48  	ctx, cancel := context.WithCancel(context.Background())
    49  	ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
    50  	urlTestHistoryStorage := urltest.NewHistoryStorage()
    51  	ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
    52  	platformWrapper := &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()}
    53  	instance, err := box.New(box.Options{
    54  		Context:           ctx,
    55  		Options:           options,
    56  		PlatformInterface: platformWrapper,
    57  		PlatformLogWriter: platformWrapper,
    58  	})
    59  	if err != nil {
    60  		cancel()
    61  		return nil, E.Cause(err, "create service")
    62  	}
    63  	runtimeDebug.FreeOSMemory()
    64  	return &BoxService{
    65  		ctx:                   ctx,
    66  		cancel:                cancel,
    67  		instance:              instance,
    68  		urlTestHistoryStorage: urlTestHistoryStorage,
    69  		pauseManager:          service.FromContext[pause.Manager](ctx),
    70  	}, nil
    71  }
    72  
    73  func (s *BoxService) Start() error {
    74  	return s.instance.Start()
    75  }
    76  
    77  func (s *BoxService) Close() error {
    78  	done := make(chan struct{})
    79  	defer close(done)
    80  	go func() {
    81  		select {
    82  		case <-done:
    83  			return
    84  		case <-time.After(C.FatalStopTimeout):
    85  			os.Exit(1)
    86  		}
    87  	}()
    88  	s.cancel()
    89  	s.urlTestHistoryStorage.Close()
    90  	return s.instance.Close()
    91  }
    92  
    93  func (s *BoxService) NeedWIFIState() bool {
    94  	return s.instance.Router().NeedWIFIState()
    95  }
    96  
    97  var (
    98  	_ platform.Interface = (*platformInterfaceWrapper)(nil)
    99  	_ log.PlatformWriter = (*platformInterfaceWrapper)(nil)
   100  )
   101  
   102  type platformInterfaceWrapper struct {
   103  	iif       PlatformInterface
   104  	useProcFS bool
   105  	router    adapter.Router
   106  }
   107  
   108  func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
   109  	w.router = router
   110  	return nil
   111  }
   112  
   113  func (w *platformInterfaceWrapper) UsePlatformAutoDetectInterfaceControl() bool {
   114  	return w.iif.UsePlatformAutoDetectInterfaceControl()
   115  }
   116  
   117  func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
   118  	return func(network, address string, conn syscall.RawConn) error {
   119  		return control.Raw(conn, func(fd uintptr) error {
   120  			return w.iif.AutoDetectInterfaceControl(int32(fd))
   121  		})
   122  	}
   123  }
   124  
   125  func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
   126  	if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
   127  		return nil, E.New("android: unsupported uid options")
   128  	}
   129  	if len(options.IncludeAndroidUser) > 0 {
   130  		return nil, E.New("android: unsupported android_user option")
   131  	}
   132  	routeRanges, err := options.BuildAutoRouteRanges(true)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	tunFd, err := w.iif.OpenTun(&tunOptions{options, routeRanges, platformOptions})
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	options.Name, err = getTunnelName(tunFd)
   141  	if err != nil {
   142  		return nil, E.Cause(err, "query tun name")
   143  	}
   144  	dupFd, err := dup(int(tunFd))
   145  	if err != nil {
   146  		return nil, E.Cause(err, "dup tun file descriptor")
   147  	}
   148  	options.FileDescriptor = dupFd
   149  	return tun.New(*options)
   150  }
   151  
   152  func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*process.Info, error) {
   153  	var uid int32
   154  	if w.useProcFS {
   155  		uid = procfs.ResolveSocketByProcSearch(network, source, destination)
   156  		if uid == -1 {
   157  			return nil, E.New("procfs: not found")
   158  		}
   159  	} else {
   160  		var ipProtocol int32
   161  		switch N.NetworkName(network) {
   162  		case N.NetworkTCP:
   163  			ipProtocol = syscall.IPPROTO_TCP
   164  		case N.NetworkUDP:
   165  			ipProtocol = syscall.IPPROTO_UDP
   166  		default:
   167  			return nil, E.New("unknown network: ", network)
   168  		}
   169  		var err error
   170  		uid, err = w.iif.FindConnectionOwner(ipProtocol, source.Addr().String(), int32(source.Port()), destination.Addr().String(), int32(destination.Port()))
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  	}
   175  	packageName, _ := w.iif.PackageNameByUid(uid)
   176  	return &process.Info{UserId: uid, PackageName: packageName}, nil
   177  }
   178  
   179  func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
   180  	return w.iif.UsePlatformDefaultInterfaceMonitor()
   181  }
   182  
   183  func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor {
   184  	return &platformDefaultInterfaceMonitor{
   185  		platformInterfaceWrapper: w,
   186  		defaultInterfaceIndex:    -1,
   187  		logger:                   logger,
   188  	}
   189  }
   190  
   191  func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
   192  	return w.iif.UsePlatformInterfaceGetter()
   193  }
   194  
   195  func (w *platformInterfaceWrapper) Interfaces() ([]control.Interface, error) {
   196  	interfaceIterator, err := w.iif.GetInterfaces()
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  	var interfaces []control.Interface
   201  	for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
   202  		interfaces = append(interfaces, control.Interface{
   203  			Index:     int(netInterface.Index),
   204  			MTU:       int(netInterface.MTU),
   205  			Name:      netInterface.Name,
   206  			Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
   207  		})
   208  	}
   209  	return interfaces, nil
   210  }
   211  
   212  func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
   213  	return w.iif.UnderNetworkExtension()
   214  }
   215  
   216  func (w *platformInterfaceWrapper) IncludeAllNetworks() bool {
   217  	return w.iif.IncludeAllNetworks()
   218  }
   219  
   220  func (w *platformInterfaceWrapper) ClearDNSCache() {
   221  	w.iif.ClearDNSCache()
   222  }
   223  
   224  func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
   225  	wifiState := w.iif.ReadWIFIState()
   226  	if wifiState == nil {
   227  		return adapter.WIFIState{}
   228  	}
   229  	return (adapter.WIFIState)(*wifiState)
   230  }
   231  
   232  func (w *platformInterfaceWrapper) DisableColors() bool {
   233  	return runtime.GOOS != "android"
   234  }
   235  
   236  func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) {
   237  	w.iif.WriteLog(message)
   238  }