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 }