github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/experimental/libbox/service.go (about)

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