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 }