.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
/bin/*
|
||||
!/bin/.gitkeep
|
||||
.build
|
||||
.idea
|
||||
|
||||
**/*.log
|
||||
.DS_Store
|
||||
|
||||
10
cmd/cmd_service.go
Normal file
10
cmd/cmd_service.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var commandService = &cobra.Command{
|
||||
Use: "service",
|
||||
Short: "Sign box service",
|
||||
}
|
||||
12
cmd/cmd_service_install.go
Normal file
12
cmd/cmd_service_install.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hiddify/libcore/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var commandServiceInstall = &cobra.Command{
|
||||
Use: "install",
|
||||
Short: "install the service",
|
||||
Run: service.InstallService,
|
||||
}
|
||||
12
cmd/cmd_service_start.go
Normal file
12
cmd/cmd_service_start.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hiddify/libcore/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var commandServiceStart = &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Start a sign box instance",
|
||||
Run: service.StartService,
|
||||
}
|
||||
12
cmd/cmd_service_stop.go
Normal file
12
cmd/cmd_service_stop.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hiddify/libcore/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var commandServiceStop = &cobra.Command{
|
||||
Use: "stop",
|
||||
Short: "stop sign box",
|
||||
Run: service.StopService,
|
||||
}
|
||||
@@ -22,8 +22,17 @@ var mainCommand = &cobra.Command{
|
||||
}
|
||||
|
||||
func init() {
|
||||
mainCommand.AddCommand(commandService)
|
||||
|
||||
commandService.AddCommand(commandServiceStart)
|
||||
commandService.AddCommand(commandServiceStop)
|
||||
commandService.AddCommand(commandServiceInstall)
|
||||
|
||||
commandServiceStart.Flags().Int("port", 8080, "Webserver port number")
|
||||
|
||||
mainCommand.PersistentFlags().StringVarP(&workingDir, "directory", "D", "", "set working directory")
|
||||
mainCommand.PersistentFlags().BoolVarP(&disableColor, "disable-color", "", false, "disable color output")
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
102
global/command_client.go
Normal file
102
global/command_client.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
type CommandClientHandler struct {
|
||||
port int64
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) Connected() {
|
||||
cch.logger.Debug("CONNECTED")
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) Disconnected(message string) {
|
||||
cch.logger.Debug("DISCONNECTED: ", message)
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) ClearLog() {
|
||||
cch.logger.Debug("clear log")
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) WriteLog(message string) {
|
||||
cch.logger.Debug("log: ", message)
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) WriteStatus(message *libbox.StatusMessage) {
|
||||
msg, err := json.Marshal(
|
||||
map[string]int64{
|
||||
"connections-in": int64(message.ConnectionsIn),
|
||||
"connections-out": int64(message.ConnectionsOut),
|
||||
"uplink": message.Uplink,
|
||||
"downlink": message.Downlink,
|
||||
"uplink-total": message.UplinkTotal,
|
||||
"downlink-total": message.DownlinkTotal,
|
||||
},
|
||||
)
|
||||
cch.logger.Debug("Memory: ", libbox.FormatBytes(message.Memory), ", Goroutines: ", message.Goroutines)
|
||||
if err != nil {
|
||||
bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err))
|
||||
} else {
|
||||
bridge.SendStringToPort(cch.port, string(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) WriteGroups(message libbox.OutboundGroupIterator) {
|
||||
if message == nil {
|
||||
return
|
||||
}
|
||||
groups := []*OutboundGroup{}
|
||||
for message.HasNext() {
|
||||
group := message.Next()
|
||||
items := group.GetItems()
|
||||
groupItems := []*OutboundGroupItem{}
|
||||
for items.HasNext() {
|
||||
item := items.Next()
|
||||
groupItems = append(groupItems,
|
||||
&OutboundGroupItem{
|
||||
Tag: item.Tag,
|
||||
Type: item.Type,
|
||||
URLTestTime: item.URLTestTime,
|
||||
URLTestDelay: item.URLTestDelay,
|
||||
},
|
||||
)
|
||||
}
|
||||
groups = append(groups, &OutboundGroup{Tag: group.Tag, Type: group.Type, Selected: group.Selected, Items: groupItems})
|
||||
}
|
||||
response, err := json.Marshal(groups)
|
||||
if err != nil {
|
||||
bridge.SendStringToPort(cch.port, fmt.Sprintf("error: %e", err))
|
||||
} else {
|
||||
bridge.SendStringToPort(cch.port, string(response))
|
||||
}
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) InitializeClashMode(modeList libbox.StringIterator, currentMode string) {
|
||||
cch.logger.Debug("initial clash mode: ", currentMode)
|
||||
}
|
||||
|
||||
func (cch *CommandClientHandler) UpdateClashMode(newMode string) {
|
||||
cch.logger.Debug("update clash mode: ", newMode)
|
||||
}
|
||||
|
||||
type OutboundGroup struct {
|
||||
Tag string `json:"tag"`
|
||||
Type string `json:"type"`
|
||||
Selected string `json:"selected"`
|
||||
Items []*OutboundGroupItem `json:"items"`
|
||||
}
|
||||
|
||||
type OutboundGroupItem struct {
|
||||
Tag string `json:"tag"`
|
||||
Type string `json:"type"`
|
||||
URLTestTime int64 `json:"url-test-time"`
|
||||
URLTestDelay int32 `json:"url-test-delay"`
|
||||
}
|
||||
43
global/command_server.go
Normal file
43
global/command_server.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
var commandServer *libbox.CommandServer
|
||||
|
||||
type CommandServerHandler struct {
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) ServiceReload() error {
|
||||
csh.logger.Trace("Reloading service")
|
||||
propagateStatus(Starting)
|
||||
if commandServer != nil {
|
||||
commandServer.SetService(nil)
|
||||
commandServer = nil
|
||||
}
|
||||
if box != nil {
|
||||
box.Close()
|
||||
box = nil
|
||||
}
|
||||
return startService(true)
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) GetSystemProxyStatus() *libbox.SystemProxyStatus {
|
||||
csh.logger.Trace("Getting system proxy status")
|
||||
return &libbox.SystemProxyStatus{Available: true, Enabled: false}
|
||||
}
|
||||
|
||||
func (csh *CommandServerHandler) SetSystemProxyEnabled(isEnabled bool) error {
|
||||
csh.logger.Trace("Setting system proxy status, enabled? ", isEnabled)
|
||||
return csh.ServiceReload()
|
||||
}
|
||||
|
||||
func startCommandServer(logFactory log.Factory) error {
|
||||
logger := logFactory.NewLogger("[Command Server Handler]")
|
||||
logger.Trace("Starting command server")
|
||||
commandServer = libbox.NewCommandServer(&CommandServerHandler{logger: logger}, 300)
|
||||
return commandServer.Start()
|
||||
}
|
||||
55
global/commands.go
Normal file
55
global/commands.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
)
|
||||
|
||||
var (
|
||||
statusClient *libbox.CommandClient
|
||||
groupClient *libbox.CommandClient
|
||||
)
|
||||
|
||||
func StartCommand(command int32, port int64, logFactory log.Factory) error {
|
||||
switch command {
|
||||
case libbox.CommandStatus:
|
||||
statusClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{
|
||||
port: port,
|
||||
logger: logFactory.NewLogger("[Status Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandStatus,
|
||||
StatusInterval: 1000000000,
|
||||
},
|
||||
)
|
||||
return statusClient.Connect()
|
||||
case libbox.CommandGroup:
|
||||
groupClient = libbox.NewCommandClient(
|
||||
&CommandClientHandler{
|
||||
port: port,
|
||||
logger: logFactory.NewLogger("[Group Command Client]"),
|
||||
},
|
||||
&libbox.CommandClientOptions{
|
||||
Command: libbox.CommandGroup,
|
||||
StatusInterval: 1000000000,
|
||||
},
|
||||
)
|
||||
return groupClient.Connect()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StopCommand(command int32) error {
|
||||
switch command {
|
||||
case libbox.CommandStatus:
|
||||
err := statusClient.Disconnect()
|
||||
statusClient = nil
|
||||
return err
|
||||
case libbox.CommandGroup:
|
||||
err := groupClient.Disconnect()
|
||||
groupClient = nil
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
15
global/constant.go
Normal file
15
global/constant.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package global
|
||||
|
||||
const (
|
||||
Stopped = "Stopped"
|
||||
Starting = "Starting"
|
||||
Started = "Started"
|
||||
Stopping = "Stopping"
|
||||
)
|
||||
|
||||
const (
|
||||
EmptyConfiguration = "EmptyConfiguration"
|
||||
StartCommandServer = "StartCommandServer"
|
||||
CreateService = "CreateService"
|
||||
StartService = "StartService"
|
||||
)
|
||||
365
global/global.go
Normal file
365
global/global.go
Normal file
@@ -0,0 +1,365 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/hiddify/libcore/config"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var box *libbox.BoxService
|
||||
var configOptions *config.ConfigOptions
|
||||
var activeConfigPath *string
|
||||
var logFactory *log.Factory
|
||||
|
||||
func setup(baseDir string, workingDir string, tempDir string, statusPort int64, debug bool) error {
|
||||
Setup(baseDir, workingDir, tempDir)
|
||||
statusPropagationPort = statusPort
|
||||
|
||||
var defaultWriter io.Writer
|
||||
if !debug {
|
||||
defaultWriter = io.Discard
|
||||
}
|
||||
factory, err := log.New(
|
||||
log.Options{
|
||||
DefaultWriter: defaultWriter,
|
||||
BaseTime: time.Now(),
|
||||
Observable: false,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logFactory = &factory
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse(path string, tempPath string, debug bool) error {
|
||||
config, err := config.ParseConfig(tempPath, debug)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(path, config, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func changeConfigOptions(configOptionsJson string) error {
|
||||
configOptions = &config.ConfigOptions{}
|
||||
err := json.Unmarshal([]byte(configOptionsJson), configOptions)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateConfig(path string) (string, error) {
|
||||
config, err := generateConfigFromFile(path, *configOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func generateConfigFromFile(path string, configOpt config.ConfigOptions) (string, error) {
|
||||
os.Chdir(filepath.Dir(path))
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
options, err := parseConfig(string(content))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
config, err := config.BuildConfigJson(configOpt, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func start(configPath string, disableMemoryLimit bool) error {
|
||||
if status != Stopped {
|
||||
return nil
|
||||
}
|
||||
propagateStatus(Starting)
|
||||
|
||||
activeConfigPath = &configPath
|
||||
|
||||
libbox.SetMemoryLimit(!disableMemoryLimit)
|
||||
err := startService(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startService(delayStart bool) error {
|
||||
content, err := os.ReadFile(*activeConfigPath)
|
||||
if err != nil {
|
||||
return stopAndAlert(EmptyConfiguration, err)
|
||||
}
|
||||
options, err := parseConfig(string(content))
|
||||
if err != nil {
|
||||
return stopAndAlert(EmptyConfiguration, err)
|
||||
}
|
||||
os.Chdir(filepath.Dir(*activeConfigPath))
|
||||
var patchedOptions *option.Options
|
||||
patchedOptions, err = config.BuildConfig(*configOptions, options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error building config: %w", err)
|
||||
}
|
||||
|
||||
config.SaveCurrentConfig(sWorkingPath, *patchedOptions)
|
||||
|
||||
err = startCommandServer(*logFactory)
|
||||
if err != nil {
|
||||
return stopAndAlert(StartCommandServer, err)
|
||||
}
|
||||
|
||||
instance, err := NewService(*patchedOptions)
|
||||
if err != nil {
|
||||
return stopAndAlert(CreateService, err)
|
||||
}
|
||||
|
||||
if delayStart {
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
|
||||
err = instance.Start()
|
||||
if err != nil {
|
||||
return stopAndAlert(StartService, err)
|
||||
}
|
||||
box = instance
|
||||
commandServer.SetService(box)
|
||||
|
||||
propagateStatus(Started)
|
||||
return nil
|
||||
}
|
||||
|
||||
func stop() error {
|
||||
if status != Started {
|
||||
return nil
|
||||
}
|
||||
if box == nil {
|
||||
return errors.New("instance not found")
|
||||
}
|
||||
propagateStatus(Stopping)
|
||||
|
||||
commandServer.SetService(nil)
|
||||
err := box.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
box = nil
|
||||
|
||||
err = commandServer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandServer = nil
|
||||
propagateStatus(Stopped)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restart(configPath string, disableMemoryLimit bool) error {
|
||||
log.Debug("[Service] Restarting")
|
||||
|
||||
if status != Started {
|
||||
return nil
|
||||
}
|
||||
if box == nil {
|
||||
return errors.New("instance not found")
|
||||
}
|
||||
|
||||
err := stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
propagateStatus(Starting)
|
||||
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
activeConfigPath = &configPath
|
||||
libbox.SetMemoryLimit(!disableMemoryLimit)
|
||||
gErr := startService(false)
|
||||
if gErr != nil {
|
||||
return gErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startCommandClient(command int, port int64) error {
|
||||
err := StartCommand(int32(command), port, *logFactory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stopCommandClient(command int) error {
|
||||
err := StopCommand(int32(command))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func selectOutbound(groupTag string, outboundTag string) error {
|
||||
err := libbox.NewStandaloneCommandClient().SelectOutbound(groupTag, outboundTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func urlTest(groupTag string) error {
|
||||
err := libbox.NewStandaloneCommandClient().URLTest(groupTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StartServiceC(delayStart bool, content string) error {
|
||||
options, err := parseConfig(content)
|
||||
if err != nil {
|
||||
return stopAndAlert(EmptyConfiguration, err)
|
||||
}
|
||||
configOptions = &config.ConfigOptions{}
|
||||
patchedOptions, err := config.BuildConfig(*configOptions, options)
|
||||
|
||||
options = *patchedOptions
|
||||
|
||||
err = config.SaveCurrentConfig(sWorkingPath, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = startCommandServer(*logFactory)
|
||||
if err != nil {
|
||||
return stopAndAlert(StartCommandServer, err)
|
||||
}
|
||||
|
||||
instance, err := NewService(options)
|
||||
if err != nil {
|
||||
return stopAndAlert(CreateService, err)
|
||||
}
|
||||
|
||||
if delayStart {
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
}
|
||||
|
||||
err = instance.Start()
|
||||
if err != nil {
|
||||
return stopAndAlert(StartService, err)
|
||||
}
|
||||
box = instance
|
||||
commandServer.SetService(box)
|
||||
|
||||
propagateStatus(Started)
|
||||
return nil
|
||||
}
|
||||
|
||||
func StopService() error {
|
||||
if status != Started {
|
||||
return nil
|
||||
}
|
||||
if box == nil {
|
||||
return errors.New("instance not found")
|
||||
}
|
||||
|
||||
propagateStatus(Stopping)
|
||||
commandServer.SetService(nil)
|
||||
err := box.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
box = nil
|
||||
|
||||
err = commandServer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandServer = nil
|
||||
propagateStatus(Stopped)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetupC(baseDir string, workDir string, tempDir string, debug bool) error {
|
||||
err := os.MkdirAll("./bin", 600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll("./work", 600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll("./temp", 600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Setup(baseDir, workDir, tempDir)
|
||||
var defaultWriter io.Writer
|
||||
if !debug {
|
||||
defaultWriter = io.Discard
|
||||
}
|
||||
factory, err := log.New(
|
||||
log.Options{
|
||||
DefaultWriter: defaultWriter,
|
||||
BaseTime: time.Now(),
|
||||
Observable: false,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logFactory = &factory
|
||||
return nil
|
||||
}
|
||||
|
||||
func MakeConfig(Ipv6 bool, ServerPort int, StrictRoute bool, EndpointIndependentNat bool, Stack string) string {
|
||||
var ipv6 string
|
||||
if Ipv6 {
|
||||
ipv6 = " \"inet6_address\": \"fdfe:dcba:9876::1/126\",\n"
|
||||
} else {
|
||||
ipv6 = ""
|
||||
}
|
||||
base := "{\n \"inbounds\": [\n {\n \"type\": \"tun\",\n \"tag\": \"tun-in\",\n \"interface_name\": \"tun0\",\n \"inet4_address\": \"172.19.0.1/30\",\n" + ipv6 + " \"mtu\": 9000,\n \"auto_route\": true,\n \"strict_route\": " + fmt.Sprintf("%t", StrictRoute) + ",\n \"endpoint_independent_nat\": " + fmt.Sprintf("%t", EndpointIndependentNat) + ",\n \"stack\": \"" + Stack + "\"\n }],\n \"outbounds\": [\n {\n \"type\": \"socks\",\n \"tag\": \"socks-out\",\n \"server\": \"127.0.0.1\",\n \"server_port\": " + fmt.Sprintf("%d", ServerPort) + ",\n \"version\": \"5\"\n }\n ]\n}\n"
|
||||
return base
|
||||
}
|
||||
|
||||
func WriteParameters(Ipv6 bool, ServerPort int, StrictRoute bool, EndpointIndependentNat bool, Stack string) error {
|
||||
parameters := fmt.Sprintf("%t,%d,%t,%t,%s", Ipv6, ServerPort, StrictRoute, EndpointIndependentNat, Stack)
|
||||
err := os.WriteFile("bin/parameters.config", []byte(parameters), 600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func ReadParameters() (bool, int, bool, bool, string, error) {
|
||||
Data, err := os.ReadFile("bin/parameters.config")
|
||||
if err != nil {
|
||||
return false, 0, false, false, "", err
|
||||
}
|
||||
DataSlice := strings.Split(string(Data), ",")
|
||||
Ipv6, _ := strconv.ParseBool(DataSlice[0])
|
||||
ServerPort, _ := strconv.Atoi(DataSlice[1])
|
||||
StrictRoute, _ := strconv.ParseBool(DataSlice[2])
|
||||
EndpointIndependentNat, _ := strconv.ParseBool(DataSlice[3])
|
||||
stack := DataSlice[4]
|
||||
return Ipv6, ServerPort, StrictRoute, EndpointIndependentNat, stack, nil
|
||||
}
|
||||
18
global/parameters.go
Normal file
18
global/parameters.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package global
|
||||
|
||||
type Stack string
|
||||
|
||||
const (
|
||||
System Stack = "system"
|
||||
GVisor Stack = "gVisor"
|
||||
Mixed Stack = "mixed"
|
||||
LWIP Stack = "LWIP"
|
||||
)
|
||||
|
||||
type Parameters struct {
|
||||
Ipv6 bool
|
||||
ServerPort int
|
||||
StrictRoute bool
|
||||
EndpointIndependentNat bool
|
||||
Stack Stack
|
||||
}
|
||||
68
global/service.go
Normal file
68
global/service.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"runtime"
|
||||
runtimeDebug "runtime/debug"
|
||||
|
||||
B "github.com/sagernet/sing-box"
|
||||
"github.com/sagernet/sing-box/common/urltest"
|
||||
"github.com/sagernet/sing-box/experimental/libbox"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/filemanager"
|
||||
"github.com/sagernet/sing/service/pause"
|
||||
)
|
||||
|
||||
var (
|
||||
sWorkingPath string
|
||||
sTempPath string
|
||||
sUserID int
|
||||
sGroupID int
|
||||
)
|
||||
|
||||
func Setup(basePath string, workingPath string, tempPath string) {
|
||||
tcpConn := runtime.GOOS == "windows" //TODO add TVOS
|
||||
libbox.Setup(basePath, workingPath, tempPath, tcpConn)
|
||||
sWorkingPath = workingPath
|
||||
os.Chdir(sWorkingPath)
|
||||
sTempPath = tempPath
|
||||
sUserID = os.Getuid()
|
||||
sGroupID = os.Getgid()
|
||||
}
|
||||
|
||||
func NewService(options option.Options) (*libbox.BoxService, error) {
|
||||
runtimeDebug.FreeOSMemory()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx = filemanager.WithDefault(ctx, sWorkingPath, sTempPath, sUserID, sGroupID)
|
||||
urlTestHistoryStorage := urltest.NewHistoryStorage()
|
||||
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
|
||||
instance, err := B.New(B.Options{
|
||||
Context: ctx,
|
||||
Options: options,
|
||||
})
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, E.Cause(err, "create service")
|
||||
}
|
||||
runtimeDebug.FreeOSMemory()
|
||||
service := libbox.NewBoxService(
|
||||
ctx,
|
||||
cancel,
|
||||
instance,
|
||||
service.FromContext[pause.Manager](ctx),
|
||||
urlTestHistoryStorage,
|
||||
)
|
||||
return &service, nil
|
||||
}
|
||||
|
||||
func parseConfig(configContent string) (option.Options, error) {
|
||||
var options option.Options
|
||||
err := options.UnmarshalJSON([]byte(configContent))
|
||||
if err != nil {
|
||||
return option.Options{}, E.Cause(err, "decode config")
|
||||
}
|
||||
return options, nil
|
||||
}
|
||||
33
global/status.go
Normal file
33
global/status.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package global
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hiddify/libcore/bridge"
|
||||
)
|
||||
|
||||
var statusPropagationPort int64
|
||||
var status = Stopped
|
||||
|
||||
type StatusMessage struct {
|
||||
Status string `json:"status"`
|
||||
Alert *string `json:"alert"`
|
||||
Message *string `json:"message"`
|
||||
}
|
||||
|
||||
func propagateStatus(newStatus string) {
|
||||
status = newStatus
|
||||
|
||||
msg, _ := json.Marshal(StatusMessage{Status: status})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
}
|
||||
|
||||
func stopAndAlert(alert string, err error) error {
|
||||
status = Stopped
|
||||
message := err.Error()
|
||||
|
||||
msg, _ := json.Marshal(StatusMessage{Status: status, Alert: &alert, Message: &message})
|
||||
bridge.SendStringToPort(statusPropagationPort, string(msg))
|
||||
return nil
|
||||
}
|
||||
2
go.mod
2
go.mod
@@ -35,9 +35,11 @@ require (
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/kardianos/service v1.2.2 // indirect
|
||||
github.com/klauspost/compress v1.17.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||
github.com/libdns/alidns v1.0.3 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -49,6 +49,8 @@ github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5X
|
||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb h1:PGufWXXDq9yaev6xX1YQauaO1MV90e6Mpoq1I7Lz/VM=
|
||||
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=
|
||||
github.com/hiddify/hiddify-sing-box v1.7.9-0.20240126132136-307f29d4ab05 h1:Lu1VgoEDqQRMsEENwDVs+SMK16hLTie6DI+P8txZLMM=
|
||||
github.com/hiddify/hiddify-sing-box v1.7.9-0.20240126132136-307f29d4ab05/go.mod h1:B74zKdMcH3ZEmCi2OUqJTvEXCNtNQjivUEQ20y/5XQM=
|
||||
github.com/hiddify/ray2sing v0.0.0-20240126124612-8e00e77ec754 h1:OS1xPGAR34zQ2btXGa2ZVpI0nXQnkB6meI1hXkQvgJM=
|
||||
@@ -62,6 +64,8 @@ github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1
|
||||
github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
|
||||
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
@@ -233,7 +237,9 @@ golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
||||
76
service/service.go
Normal file
76
service/service.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/hiddify/libcore/global"
|
||||
"github.com/hiddify/libcore/web"
|
||||
"github.com/kardianos/service"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type hiddifyNext struct{}
|
||||
|
||||
var port int
|
||||
|
||||
func (m *hiddifyNext) Start(s service.Service) error {
|
||||
go m.run()
|
||||
return nil
|
||||
}
|
||||
func (m *hiddifyNext) Stop(s service.Service) error {
|
||||
err := global.StopService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *hiddifyNext) run() {
|
||||
web.StartWebServer(port)
|
||||
}
|
||||
func StartService(cmd *cobra.Command, args []string) {
|
||||
port, _ = cmd.Flags().GetInt("port")
|
||||
svcConfig := &service.Config{
|
||||
Name: "hiddify_next_core",
|
||||
DisplayName: "hiddify next core",
|
||||
Description: "@hiddify_com set this",
|
||||
}
|
||||
prg := &hiddifyNext{}
|
||||
svc, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
err = svc.Run()
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
func StopService(cmd *cobra.Command, args []string) {
|
||||
svcConfig := &service.Config{
|
||||
Name: "hiddify_next_core",
|
||||
DisplayName: "hiddify next core",
|
||||
Description: "@hiddify_com set this",
|
||||
}
|
||||
prg := &hiddifyNext{}
|
||||
svc, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
err = svc.Stop()
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
func InstallService(cmd *cobra.Command, args []string) {
|
||||
svcConfig := &service.Config{
|
||||
Name: "hiddify_next_core",
|
||||
DisplayName: "hiddify next core",
|
||||
Description: "@hiddify_com set this",
|
||||
}
|
||||
prg := &hiddifyNext{}
|
||||
svc, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
err = svc.Install()
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
91
utils/certificate_li.go
Normal file
91
utils/certificate_li.go
Normal file
@@ -0,0 +1,91 @@
|
||||
//go:build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GenerateCertificate(certPath, keyPath string, isServer bool) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(365 * 24 * time.Hour)
|
||||
|
||||
var keyUsage x509.KeyUsage
|
||||
var extKeyUsage []x509.ExtKeyUsage
|
||||
|
||||
if isServer {
|
||||
keyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
|
||||
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
} else {
|
||||
keyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
|
||||
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{Organization: []string{"Secure data transfer"}},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: keyUsage,
|
||||
ExtKeyUsage: extKeyUsage,
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
certFile, err := os.Create(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer certFile.Close()
|
||||
certFile.Chmod(600)
|
||||
pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
||||
|
||||
keyFile, err := os.Create(keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer keyFile.Close()
|
||||
privBytes, err := x509.MarshalECPrivateKey(priv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyFile.Chmod(600)
|
||||
pem.Encode(keyFile, &pem.Block{Type: "EC PRIVATE KEY", Bytes: privBytes})
|
||||
}
|
||||
|
||||
func LoadCertificate(certPath, keyPath string) tls.Certificate {
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cert
|
||||
}
|
||||
|
||||
func LoadClientCA(certPath string) *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
certPEM, err := ioutil.ReadFile(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pool.AppendCertsFromPEM(certPEM)
|
||||
return pool
|
||||
}
|
||||
92
utils/certificate_wi.go
Normal file
92
utils/certificate_wi.go
Normal file
@@ -0,0 +1,92 @@
|
||||
//go:build windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"github.com/hectane/go-acl"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GenerateCertificate(certPath, keyPath string, isServer bool) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(365 * 24 * time.Hour)
|
||||
|
||||
var keyUsage x509.KeyUsage
|
||||
var extKeyUsage []x509.ExtKeyUsage
|
||||
|
||||
if isServer {
|
||||
keyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
|
||||
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
} else {
|
||||
keyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
|
||||
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{Organization: []string{"Secure data transfer"}},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
KeyUsage: keyUsage,
|
||||
ExtKeyUsage: extKeyUsage,
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
certFile, err := os.Create(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer certFile.Close()
|
||||
acl.Chmod(certFile.Name(), 600)
|
||||
pem.Encode(certFile, &pem.Block{Type: "CERTIFICATE", Bytes: certDER})
|
||||
|
||||
keyFile, err := os.Create(keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer keyFile.Close()
|
||||
privBytes, err := x509.MarshalECPrivateKey(priv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
acl.Chmod(keyFile.Name(), 600)
|
||||
pem.Encode(keyFile, &pem.Block{Type: "EC PRIVATE KEY", Bytes: privBytes})
|
||||
}
|
||||
|
||||
func LoadCertificate(certPath, keyPath string) tls.Certificate {
|
||||
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cert
|
||||
}
|
||||
|
||||
func LoadClientCA(certPath string) *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
certPEM, err := ioutil.ReadFile(certPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pool.AppendCertsFromPEM(certPEM)
|
||||
return pool
|
||||
}
|
||||
123
web/web.go
Normal file
123
web/web.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/hiddify/libcore/global"
|
||||
"github.com/hiddify/libcore/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
serverCertPath = "cert/server-cert.pem"
|
||||
serverKeyPath = "cert/server-key.pem"
|
||||
clientCertPath = "cert/client-cert.pem"
|
||||
clientKeyPath = "cert/client-key.pem"
|
||||
)
|
||||
|
||||
func StartWebServer(Port int) {
|
||||
http.HandleFunc("/start", startHandler)
|
||||
http.HandleFunc("/stop", StopHandler)
|
||||
server := &http.Server{
|
||||
Addr: "127.0.0.1:" + fmt.Sprintf("%d", Port),
|
||||
TLSConfig: &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
Certificates: []tls.Certificate{utils.LoadCertificate(serverCertPath, serverKeyPath)},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: utils.LoadClientCA(clientCertPath),
|
||||
},
|
||||
}
|
||||
err := server.ListenAndServeTLS(serverCertPath, serverKeyPath)
|
||||
if err != nil {
|
||||
panic("Error: " + err.Error())
|
||||
}
|
||||
}
|
||||
func startHandler(w http.ResponseWriter, r *http.Request) {
|
||||
queryParams := r.URL.Query()
|
||||
Ipv6 := queryParams.Get("Ipv6")
|
||||
ServerPort := queryParams.Get("ServerPort")
|
||||
StrictRoute := queryParams.Get("StrictRoute")
|
||||
EndpointIndependentNat := queryParams.Get("EndpointIndependentNat")
|
||||
TheStack := queryParams.Get("Stack")
|
||||
|
||||
ipv6, err := strconv.ParseBool(Ipv6)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
serverPort, err := strconv.Atoi(ServerPort)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
strictRoute, err := strconv.ParseBool(StrictRoute)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
endpointIndependentNat, err := strconv.ParseBool(EndpointIndependentNat)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
theStack := GetStack(TheStack)
|
||||
if theStack == "UNKNOWN" {
|
||||
http.Error(w, fmt.Sprintf("Error: %s", "Stack is not valid"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
parameters := global.Parameters{Ipv6: ipv6, ServerPort: serverPort, StrictRoute: strictRoute, EndpointIndependentNat: endpointIndependentNat, Stack: GetStack(TheStack)}
|
||||
|
||||
err = global.WriteParameters(parameters.Ipv6, parameters.ServerPort, parameters.StrictRoute, parameters.EndpointIndependentNat, GetStringFromStack(parameters.Stack))
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = global.SetupC("./", "./work", "./tmp", false)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
err = global.StartServiceC(true, global.MakeConfig(parameters.Ipv6, parameters.ServerPort, parameters.StrictRoute, parameters.EndpointIndependentNat, GetStringFromStack(parameters.Stack)))
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
func StopHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err := global.StopService()
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
func GetStack(stack string) global.Stack {
|
||||
switch stack {
|
||||
case "system":
|
||||
return global.System
|
||||
case "gVisor":
|
||||
return global.GVisor
|
||||
case "mixed":
|
||||
return global.Mixed
|
||||
case "LWIP":
|
||||
return global.LWIP
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
func GetStringFromStack(stack global.Stack) string {
|
||||
switch stack {
|
||||
case global.System:
|
||||
return "system"
|
||||
case global.GVisor:
|
||||
return "gVisor"
|
||||
case global.Mixed:
|
||||
return "mixed"
|
||||
case global.LWIP:
|
||||
return "LWIP"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user