sing-box/experimental/libbox/service.go

239 lines
6.8 KiB
Go
Raw Normal View History

2022-10-25 04:55:00 +00:00
package libbox
import (
"context"
"net/netip"
"os"
2023-11-15 05:05:33 +00:00
"runtime"
2023-08-12 11:33:43 +00:00
runtimeDebug "runtime/debug"
2022-10-25 04:55:00 +00:00
"syscall"
"time"
2022-10-25 04:55:00 +00:00
"github.com/sagernet/sing-box"
2023-04-18 06:04:09 +00:00
"github.com/sagernet/sing-box/adapter"
2022-10-25 04:55:00 +00:00
"github.com/sagernet/sing-box/common/process"
2023-07-02 08:45:30 +00:00
"github.com/sagernet/sing-box/common/urltest"
C "github.com/sagernet/sing-box/constant"
2022-10-25 04:55:00 +00:00
"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
"github.com/sagernet/sing-box/experimental/libbox/platform"
2023-11-15 05:05:33 +00:00
"github.com/sagernet/sing-box/log"
2023-02-28 11:02:27 +00:00
"github.com/sagernet/sing-box/option"
2022-10-25 04:55:00 +00:00
"github.com/sagernet/sing-tun"
2023-04-18 06:04:09 +00:00
"github.com/sagernet/sing/common"
2022-10-25 04:55:00 +00:00
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
2023-07-23 06:42:19 +00:00
"github.com/sagernet/sing/common/logger"
2022-10-25 04:55:00 +00:00
N "github.com/sagernet/sing/common/network"
2023-07-02 08:45:30 +00:00
"github.com/sagernet/sing/service"
2023-04-21 09:29:00 +00:00
"github.com/sagernet/sing/service/filemanager"
2023-08-07 09:46:51 +00:00
"github.com/sagernet/sing/service/pause"
2022-10-25 04:55:00 +00:00
)
type BoxService struct {
ctx context.Context
cancel context.CancelFunc
instance *box.Box
pauseManager pause.Manager
urlTestHistoryStorage *urltest.HistoryStorage
servicePauseFields
2022-10-25 04:55:00 +00:00
}
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
options, err := parseConfig(configContent)
if err != nil {
return nil, err
}
2023-08-12 11:33:43 +00:00
runtimeDebug.FreeOSMemory()
2022-10-25 04:55:00 +00:00
ctx, cancel := context.WithCancel(context.Background())
2023-07-29 00:37:10 +00:00
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
urlTestHistoryStorage := urltest.NewHistoryStorage()
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
2023-11-15 05:05:33 +00:00
platformWrapper := &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()}
2023-04-03 10:24:20 +00:00
instance, err := box.New(box.Options{
Context: ctx,
Options: options,
2023-11-15 05:05:33 +00:00
PlatformInterface: platformWrapper,
PlatformLogWriter: platformWrapper,
2023-04-03 10:24:20 +00:00
})
2022-10-25 04:55:00 +00:00
if err != nil {
cancel()
return nil, E.Cause(err, "create service")
}
2023-08-12 11:33:43 +00:00
runtimeDebug.FreeOSMemory()
2022-10-25 04:55:00 +00:00
return &BoxService{
ctx: ctx,
cancel: cancel,
instance: instance,
urlTestHistoryStorage: urlTestHistoryStorage,
2023-12-16 07:40:14 +00:00
pauseManager: service.FromContext[pause.Manager](ctx),
2022-10-25 04:55:00 +00:00
}, nil
}
func (s *BoxService) Start() error {
return s.instance.Start()
}
func (s *BoxService) Close() error {
done := make(chan struct{})
defer close(done)
go func() {
select {
case <-done:
return
2024-04-02 15:07:26 +00:00
case <-time.After(C.FatalStopTimeout):
os.Exit(1)
}
}()
2022-10-25 04:55:00 +00:00
s.cancel()
s.urlTestHistoryStorage.Close()
2022-10-25 04:55:00 +00:00
return s.instance.Close()
}
func (s *BoxService) NeedWIFIState() bool {
return s.instance.Router().NeedWIFIState()
}
2023-11-15 05:05:33 +00:00
var (
_ platform.Interface = (*platformInterfaceWrapper)(nil)
_ log.PlatformWriter = (*platformInterfaceWrapper)(nil)
)
2022-10-25 04:55:00 +00:00
type platformInterfaceWrapper struct {
iif PlatformInterface
useProcFS bool
2023-04-18 06:04:09 +00:00
router adapter.Router
}
func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
w.router = router
return nil
2022-10-25 04:55:00 +00:00
}
func (w *platformInterfaceWrapper) UsePlatformAutoDetectInterfaceControl() bool {
return w.iif.UsePlatformAutoDetectInterfaceControl()
}
2022-10-25 04:55:00 +00:00
func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
return func(network, address string, conn syscall.RawConn) error {
return control.Raw(conn, func(fd uintptr) error {
return w.iif.AutoDetectInterfaceControl(int32(fd))
})
}
}
func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error) {
2022-10-25 04:55:00 +00:00
if len(options.IncludeUID) > 0 || len(options.ExcludeUID) > 0 {
return nil, E.New("android: unsupported uid options")
}
if len(options.IncludeAndroidUser) > 0 {
return nil, E.New("android: unsupported android_user option")
}
routeRanges, err := options.BuildAutoRouteRanges(true)
if err != nil {
return nil, err
}
tunFd, err := w.iif.OpenTun(&tunOptions{options, routeRanges, platformOptions})
2022-10-25 04:55:00 +00:00
if err != nil {
return nil, err
}
options.Name, err = getTunnelName(tunFd)
if err != nil {
return nil, E.Cause(err, "query tun name")
}
2023-04-07 13:10:16 +00:00
dupFd, err := dup(int(tunFd))
2023-03-13 11:47:00 +00:00
if err != nil {
return nil, E.Cause(err, "dup tun file descriptor")
}
options.FileDescriptor = dupFd
return tun.New(*options)
2022-10-25 04:55:00 +00:00
}
2023-04-18 06:04:09 +00:00
func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
return w.iif.UsePlatformDefaultInterfaceMonitor()
}
2023-07-23 06:42:19 +00:00
func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor {
2023-04-18 06:04:09 +00:00
return &platformDefaultInterfaceMonitor{
platformInterfaceWrapper: w,
defaultInterfaceIndex: -1,
2023-07-23 06:42:19 +00:00
logger: logger,
2023-04-18 06:04:09 +00:00
}
}
func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
return w.iif.UsePlatformInterfaceGetter()
}
2024-04-12 01:24:49 +00:00
func (w *platformInterfaceWrapper) Interfaces() ([]control.Interface, error) {
2023-04-18 06:04:09 +00:00
interfaceIterator, err := w.iif.GetInterfaces()
if err != nil {
return nil, err
}
2024-04-12 01:24:49 +00:00
var interfaces []control.Interface
2023-04-18 06:04:09 +00:00
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
2024-04-12 01:24:49 +00:00
interfaces = append(interfaces, control.Interface{
2023-04-18 06:04:09 +00:00
Index: int(netInterface.Index),
MTU: int(netInterface.MTU),
Name: netInterface.Name,
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
})
}
return interfaces, nil
}
func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
return w.iif.UnderNetworkExtension()
}
2024-05-07 12:34:24 +00:00
func (w *platformInterfaceWrapper) IncludeAllNetworks() bool {
return w.iif.IncludeAllNetworks()
}
func (w *platformInterfaceWrapper) ClearDNSCache() {
w.iif.ClearDNSCache()
}
2023-11-15 05:05:33 +00:00
func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
wifiState := w.iif.ReadWIFIState()
if wifiState == nil {
return adapter.WIFIState{}
}
return (adapter.WIFIState)(*wifiState)
}
2024-06-11 13:16:33 +00:00
func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*process.Info, error) {
var uid int32
if w.useProcFS {
uid = procfs.ResolveSocketByProcSearch(network, source, destination)
if uid == -1 {
return nil, E.New("procfs: not found")
}
} else {
var ipProtocol int32
switch N.NetworkName(network) {
case N.NetworkTCP:
ipProtocol = syscall.IPPROTO_TCP
case N.NetworkUDP:
ipProtocol = syscall.IPPROTO_UDP
default:
return nil, E.New("unknown network: ", network)
}
var err error
uid, err = w.iif.FindConnectionOwner(ipProtocol, source.Addr().String(), int32(source.Port()), destination.Addr().String(), int32(destination.Port()))
if err != nil {
return nil, err
}
}
packageName, _ := w.iif.PackageNameByUid(uid)
return &process.Info{UserId: uid, PackageName: packageName}, nil
}
2023-11-15 05:05:33 +00:00
func (w *platformInterfaceWrapper) DisableColors() bool {
return runtime.GOOS != "android"
}
func (w *platformInterfaceWrapper) WriteMessage(level log.Level, message string) {
w.iif.WriteLog(message)
}