new: move running admin service to core
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,3 +5,5 @@
|
|||||||
|
|
||||||
**/*.log
|
**/*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
**/*.syso
|
||||||
Binary file not shown.
4
cmd.bat
Normal file
4
cmd.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@echo off
|
||||||
|
set TAGS=with_gvisor,with_quic,with_wireguard,with_ech,with_utls,with_clash_api,with_grpc
|
||||||
|
@REM set TAGS=with_dhcp,with_low_memory,with_conntrack
|
||||||
|
go run --tags %TAGS% ./cmd %*
|
||||||
38
config/admin_service_cmd_runner.go
Normal file
38
config/admin_service_cmd_runner.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExecuteCmd(executablePath, args string) (string, error) {
|
||||||
|
err := execCmdImp([]string{"gksu", executablePath, args})
|
||||||
|
if err == nil {
|
||||||
|
return "Ok", nil
|
||||||
|
}
|
||||||
|
err := execCmdImp([]string{"pkexec", executablePath, args})
|
||||||
|
if err == nil {
|
||||||
|
return "Ok", nil
|
||||||
|
}
|
||||||
|
err := execCmdImp([]string{"/bin/sh", "-c", "sudo " + executablePath + " " + args})
|
||||||
|
if err == nil {
|
||||||
|
return "Ok", nil
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func execCmdImp(cmd []string) error {
|
||||||
|
cmd := exec.Command(cmd[0], cmd[1:])
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
fmt.Printf("Running command: %v", cmd.String())
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Printf("Error: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
28
config/admin_service_cmd_runner_windows.go
Normal file
28
config/admin_service_cmd_runner_windows.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExecuteCmd(exe string, args string) (string, error) {
|
||||||
|
verb := "runas"
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
|
verbPtr, _ := syscall.UTF16PtrFromString(verb)
|
||||||
|
exePtr, _ := syscall.UTF16PtrFromString(exe)
|
||||||
|
cwdPtr, _ := syscall.UTF16PtrFromString(cwd)
|
||||||
|
argPtr, _ := syscall.UTF16PtrFromString(args)
|
||||||
|
|
||||||
|
var showCmd int32 = 1 //SW_NORMAL
|
||||||
|
|
||||||
|
err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
116
config/admin_service_commander.go
Normal file
116
config/admin_service_commander.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
dns "github.com/sagernet/sing-dns"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
serviceURL = "http://localhost:18020"
|
||||||
|
startEndpoint = "/start"
|
||||||
|
stopEndpoint = "/stop"
|
||||||
|
)
|
||||||
|
|
||||||
|
func isSupportedOS() bool {
|
||||||
|
return runtime.GOOS == "windows" || runtime.GOOS == "linux"
|
||||||
|
}
|
||||||
|
func ActivateTunnelService(opt ConfigOptions) (bool, error) {
|
||||||
|
if !isSupportedOS() {
|
||||||
|
return false, E.New("Unsupported OS: " + runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
go startTunnelRequest(opt, true)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeactivateTunnelService() (bool, error) {
|
||||||
|
if !isSupportedOS() {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
go stopTunnelRequest()
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startTunnelRequest(opt ConfigOptions, installService bool) (bool, error) {
|
||||||
|
params := map[string]interface{}{
|
||||||
|
"Ipv6": opt.IPv6Mode == option.DomainStrategy(dns.DomainStrategyUseIPv4),
|
||||||
|
"ServerPort": opt.InboundOptions.MixedPort,
|
||||||
|
"StrictRoute": opt.InboundOptions.StrictRoute,
|
||||||
|
"EndpointIndependentNat": true,
|
||||||
|
"Stack": opt.InboundOptions.TUNStack,
|
||||||
|
}
|
||||||
|
|
||||||
|
values := url.Values{}
|
||||||
|
for key, value := range params {
|
||||||
|
values.Add(key, fmt.Sprint(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
url := fmt.Sprintf("%s%s?%s", serviceURL, startEndpoint, values.Encode())
|
||||||
|
fmt.Printf("URL: %s\n", url)
|
||||||
|
response, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
if installService {
|
||||||
|
return runTunnelService(opt)
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
fmt.Printf("Response Code: %d %s. Response Body: %s Error:%v\n", response.StatusCode, response.Status, body, err)
|
||||||
|
if err != nil || response.StatusCode != http.StatusOK {
|
||||||
|
return false, fmt.Errorf("Unexpected Status Code: %d %s. Response Body: %s error:%v", response.StatusCode, response.Status, body, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopTunnelRequest() (bool, error) {
|
||||||
|
response, err := http.Get(serviceURL + stopEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("HTTP Request Error: %v", err)
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
fmt.Printf("Response Code: %d %s. Response Body: %s Error:%v\n", response.StatusCode, response.Status, body, err)
|
||||||
|
if err != nil || response.StatusCode != http.StatusOK {
|
||||||
|
return false, fmt.Errorf("Unexpected Status Code: %d %s. Response Body: %s error:%v", response.StatusCode, response.Status, body, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTunnelService(opt ConfigOptions) (bool, error) {
|
||||||
|
executablePath := getTunnelServicePath()
|
||||||
|
|
||||||
|
out, err := ExecuteCmd(executablePath, "install")
|
||||||
|
fmt.Println("Shell command executed:", out, err)
|
||||||
|
return startTunnelRequest(opt, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTunnelServicePath() string {
|
||||||
|
var fullPath string
|
||||||
|
binFolder := filepath.Dir(os.Args[0])
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
fullPath = "HiddifyService.exe"
|
||||||
|
case "darwin":
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
fullPath = "HiddifyService"
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(binFolder, fullPath)
|
||||||
|
}
|
||||||
@@ -135,40 +135,42 @@ func BuildConfig(opt ConfigOptions, input option.Options) (*option.Options, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opt.EnableTun {
|
if opt.EnableTun {
|
||||||
tunInbound := option.Inbound{
|
if ok, _ := ActivateTunnelService(opt); !ok {
|
||||||
Type: C.TypeTun,
|
tunInbound := option.Inbound{
|
||||||
Tag: InboundTUNTag,
|
Type: C.TypeTun,
|
||||||
TunOptions: option.TunInboundOptions{
|
Tag: InboundTUNTag,
|
||||||
Stack: opt.TUNStack,
|
TunOptions: option.TunInboundOptions{
|
||||||
MTU: opt.MTU,
|
Stack: opt.TUNStack,
|
||||||
AutoRoute: true,
|
MTU: opt.MTU,
|
||||||
StrictRoute: opt.StrictRoute,
|
AutoRoute: true,
|
||||||
EndpointIndependentNat: true,
|
StrictRoute: opt.StrictRoute,
|
||||||
InboundOptions: option.InboundOptions{
|
EndpointIndependentNat: true,
|
||||||
SniffEnabled: true,
|
InboundOptions: option.InboundOptions{
|
||||||
SniffOverrideDestination: true,
|
SniffEnabled: true,
|
||||||
DomainStrategy: inboundDomainStrategy,
|
SniffOverrideDestination: true,
|
||||||
|
DomainStrategy: inboundDomainStrategy,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
switch opt.IPv6Mode {
|
||||||
|
case option.DomainStrategy(dns.DomainStrategyUseIPv4):
|
||||||
|
tunInbound.TunOptions.Inet4Address = []netip.Prefix{
|
||||||
|
netip.MustParsePrefix("172.19.0.1/28"),
|
||||||
|
}
|
||||||
|
case option.DomainStrategy(dns.DomainStrategyUseIPv6):
|
||||||
|
tunInbound.TunOptions.Inet6Address = []netip.Prefix{
|
||||||
|
netip.MustParsePrefix("fdfe:dcba:9876::1/126"),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
tunInbound.TunOptions.Inet4Address = []netip.Prefix{
|
||||||
|
netip.MustParsePrefix("172.19.0.1/28"),
|
||||||
|
}
|
||||||
|
tunInbound.TunOptions.Inet6Address = []netip.Prefix{
|
||||||
|
netip.MustParsePrefix("fdfe:dcba:9876::1/126"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options.Inbounds = append(options.Inbounds, tunInbound)
|
||||||
}
|
}
|
||||||
switch opt.IPv6Mode {
|
|
||||||
case option.DomainStrategy(dns.DomainStrategyUseIPv4):
|
|
||||||
tunInbound.TunOptions.Inet4Address = []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("172.19.0.1/28"),
|
|
||||||
}
|
|
||||||
case option.DomainStrategy(dns.DomainStrategyUseIPv6):
|
|
||||||
tunInbound.TunOptions.Inet6Address = []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("fdfe:dcba:9876::1/126"),
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
tunInbound.TunOptions.Inet4Address = []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("172.19.0.1/28"),
|
|
||||||
}
|
|
||||||
tunInbound.TunOptions.Inet6Address = []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("fdfe:dcba:9876::1/126"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
options.Inbounds = append(options.Inbounds, tunInbound)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
options.Inbounds = append(
|
options.Inbounds = append(
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func SaveCurrentConfig(path string, options option.Options) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p, err := filepath.Abs(filepath.Join(path, "current-config.json"))
|
p, err := filepath.Abs(path)
|
||||||
fmt.Printf("Saving config to %v %+v\n", p, err)
|
fmt.Printf("Saving config to %v %+v\n", p, err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ func startService(delayStart bool) error {
|
|||||||
return fmt.Errorf("error building config: %w", err)
|
return fmt.Errorf("error building config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SaveCurrentConfig(sWorkingPath, *patchedOptions)
|
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "current-config.json"), *patchedOptions)
|
||||||
|
|
||||||
err = startCommandServer(*logFactory)
|
err = startCommandServer(*logFactory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -188,6 +188,7 @@ func stop() (CErr *C.char) {
|
|||||||
defer config.DeferPanicToError("stop", func(err error) {
|
defer config.DeferPanicToError("stop", func(err error) {
|
||||||
CErr = C.CString(err.Error())
|
CErr = C.CString(err.Error())
|
||||||
})
|
})
|
||||||
|
config.DeactivateTunnelService()
|
||||||
|
|
||||||
if status != Started {
|
if status != Started {
|
||||||
return C.CString("")
|
return C.CString("")
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func startService(delayStart bool) error {
|
|||||||
return fmt.Errorf("error building config: %w", err)
|
return fmt.Errorf("error building config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SaveCurrentConfig(sWorkingPath, *patchedOptions)
|
config.SaveCurrentConfig(filepath.Join(sWorkingPath, "tunnel-current-config.json"), *patchedOptions)
|
||||||
|
|
||||||
err = startCommandServer(*logFactory)
|
err = startCommandServer(*logFactory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -248,11 +248,11 @@ func StartServiceC(delayStart bool, content string) error {
|
|||||||
|
|
||||||
// options = *patchedOptions
|
// options = *patchedOptions
|
||||||
|
|
||||||
err = config.SaveCurrentConfig(sWorkingPath, options)
|
// config.SaveCurrentConfig(filepath.Join(sWorkingPath, "custom-current-config.json"), options)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
fmt.Printf("Error in saving config: %v\n", err)
|
// fmt.Printf("Error in saving config: %v\n", err)
|
||||||
return err
|
// return err
|
||||||
}
|
// }
|
||||||
|
|
||||||
// err = startCommandServer(*logFactory)
|
// err = startCommandServer(*logFactory)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -18,6 +18,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
berty.tech/go-libtor v1.0.385 // indirect
|
berty.tech/go-libtor v1.0.385 // indirect
|
||||||
github.com/ajg/form v1.5.1 // indirect
|
github.com/ajg/form v1.5.1 // indirect
|
||||||
|
github.com/akavel/rsrc v0.10.2 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.6 // indirect
|
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||||
github.com/caddyserver/certmagic v0.20.0 // indirect
|
github.com/caddyserver/certmagic v0.20.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.7 // indirect
|
github.com/cloudflare/circl v1.3.7 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -2,6 +2,8 @@ berty.tech/go-libtor v1.0.385 h1:RWK94C3hZj6Z2GdvePpHJLnWYobFr3bY/OdUJ5aoEXw=
|
|||||||
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+fJEw=
|
||||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
|
github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
|
||||||
|
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
|
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
|
||||||
|
|||||||
Reference in New Issue
Block a user