From 0a07db9b3b430f0d932ef7c08ea756eafbb1b663 Mon Sep 17 00:00:00 2001 From: samwaf Date: Thu, 25 May 2023 09:46:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=90=8E=E5=8F=B0=E8=BF=90?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build-releases.bat | 2 +- go.mod | 1 + go.sum | 4 ++ main.go | 36 ++++++++++ vue/dist/index.html | 4 +- xdaemon/attr_default.go | 12 ++++ xdaemon/attr_windows.go | 12 ++++ xdaemon/daemon.go | 142 ++++++++++++++++++++++++++++++++++++++++ 编译说明.md | 2 +- 9 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 xdaemon/attr_default.go create mode 100644 xdaemon/attr_windows.go create mode 100644 xdaemon/daemon.go diff --git a/build-releases.bat b/build-releases.bat index e1f5427..67684e1 100644 --- a/build-releases.bat +++ b/build-releases.bat @@ -2,4 +2,4 @@ SET CGO_ENABLED=1 SET GOOS=windows SET GOARCH=amd64 SET GIN_MODE=release -go build -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20230329 -X SamWaf/global.GWAF_RELEASE_VERSION=100 -s -w" -o %cd%/release/SamWaf64.exe main.go && %cd%/upx/win64/upx -9 %cd%/release/SamWaf64.exe +go build -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20230525 -X SamWaf/global.GWAF_RELEASE_VERSION=100 -s -w" -o %cd%/release/SamWaf64.exe main.go && %cd%/upx/win64/upx -9 %cd%/release/SamWaf64.exe diff --git a/go.mod b/go.mod index cd48e34..02928e8 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/satori/go.uuid v1.2.0 github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.8.0 + github.com/takama/daemon v1.0.0 go.uber.org/zap v1.21.0 golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 golang.org/x/text v0.3.7 diff --git a/go.sum b/go.sum index 003fb25..25db398 100644 --- a/go.sum +++ b/go.sum @@ -232,6 +232,7 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -270,6 +271,8 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ= +github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= @@ -422,6 +425,7 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/main.go b/main.go index d8c5527..c964a96 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "SamWaf/utils/zlog" "SamWaf/wafenginecore" "SamWaf/waftask" + "SamWaf/xdaemon" "crypto/tls" dlp "github.com/bytedance/godlp" "github.com/go-co-op/gocron" @@ -20,6 +21,7 @@ import ( "log" "net/http" "os" + "os/exec" "runtime" "strconv" "syscall" @@ -27,6 +29,7 @@ import ( ) func main() { + rversion := "初始化系统 版本号:" + global.GWAF_RELEASE_VERSION_NAME + "(" + global.GWAF_RELEASE_VERSION + ")" if global.GWAF_RELEASE == "false" { rversion = rversion + " 调试版本" @@ -48,6 +51,39 @@ func main() { if err != nil { log.Fatal(err) } + // if received any kind of command, do it + if len(os.Args) > 1 { + command := os.Args[1] + switch command { + case "-d": + logFile := "./logs/daemon.log" + //启动一个子进程后主程序退出 + xdaemon.Background(logFile, true) + break + case "-c": + println("关闭") + if runtime.GOOS == "windows" { + c := exec.Command("taskkill.exe", "/f", "/im", "SamWaf.exe") + c.Start() + } else { + println("SamWaf -d") + } + break + case "-help": + if runtime.GOOS == "windows" { + println("SamWaf.exe -d 是后台运行 -c 是强制关闭 -help 是帮助说明") + } else { + println("SamWaf -d 是后台运行 -c 是强制关闭 -help 是帮助说明") + } + break + default: + println(command) + } + } + + //守护程序开始 + //xdaemon.DaemonProcess("GoTest.exe","./logs/damon.log") + /*runtime.GOMAXPROCS(1) // 限制 CPU 使用数,避免过载 runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪 runtime.SetBlockProfileRate(1) // 开启对阻塞操作的跟踪 diff --git a/vue/dist/index.html b/vue/dist/index.html index 77be315..9a77b4b 100644 --- a/vue/dist/index.html +++ b/vue/dist/index.html @@ -6,8 +6,8 @@ Sam网站应用级入侵防御系统后台(Web Application Firewall) - - + +
diff --git a/xdaemon/attr_default.go b/xdaemon/attr_default.go new file mode 100644 index 0000000..b8b31ae --- /dev/null +++ b/xdaemon/attr_default.go @@ -0,0 +1,12 @@ +//go:build !windows && !plan9 +// +build !windows,!plan9 + +package xdaemon + +import "syscall" + +func NewSysProcAttr() *syscall.SysProcAttr { + return &syscall.SysProcAttr{ + Setsid: true, + } +} diff --git a/xdaemon/attr_windows.go b/xdaemon/attr_windows.go new file mode 100644 index 0000000..66c3ff6 --- /dev/null +++ b/xdaemon/attr_windows.go @@ -0,0 +1,12 @@ +//go:build windows +// +build windows + +package xdaemon + +import "syscall" + +func NewSysProcAttr() *syscall.SysProcAttr { + return &syscall.SysProcAttr{ + HideWindow: true, + } +} diff --git a/xdaemon/daemon.go b/xdaemon/daemon.go new file mode 100644 index 0000000..95a3380 --- /dev/null +++ b/xdaemon/daemon.go @@ -0,0 +1,142 @@ +package xdaemon + +import ( + "fmt" + "log" + "os" + "os/exec" + "strconv" + "time" +) + +const ENV_NAME = "XW_DAEMON_IDX" + +//运行时调用background的次数 +var runIdx int = 0 + +//守护进程 +type Daemon struct { + LogFile string //日志文件, 记录守护进程和子进程的标准输出和错误输出. 若为空则不记录 + MaxCount int //循环重启最大次数, 若为0则无限重启 + MaxError int //连续启动失败或异常退出的最大次数, 超过此数, 守护进程退出, 不再重启子进程 + MinExitTime int64 //子进程正常退出的最小时间(秒). 小于此时间则认为是异常退出 +} + +// 把本身程序转化为后台运行(启动一个子进程, 然后自己退出) +// logFile 若不为空,子程序的标准输出和错误输出将记入此文件 +// isExit 启动子加进程后是否直接退出主程序, 若为false, 主程序返回*os.Process, 子程序返回 nil. 需自行判断处理 +func Background(logFile string, isExit bool) (*exec.Cmd, error) { + //判断子进程还是父进程 + runIdx++ + envIdx, err := strconv.Atoi(os.Getenv(ENV_NAME)) + if err != nil { + envIdx = 0 + } + if runIdx <= envIdx { //子进程, 退出 + return nil, nil + } + + //设置子进程环境变量 + env := os.Environ() + env = append(env, fmt.Sprintf("%s=%d", ENV_NAME, runIdx)) + + //启动子进程 + cmd, err := startProc(os.Args, env, logFile) + if err != nil { + log.Println(os.Getpid(), "启动子进程失败:", err) + return nil, err + } else { + //执行成功 + log.Println(os.Getpid(), ":", "启动子进程成功:", "->", cmd.Process.Pid, "\n ") + } + + if isExit { + os.Exit(0) + } + + return cmd, nil +} + +func NewDaemon(logFile string) *Daemon { + return &Daemon{ + LogFile: logFile, + MaxCount: 0, + MaxError: 3, + MinExitTime: 10, + } +} + +// 启动后台守护进程 +func (d *Daemon) Run() { + //启动一个守护进程后退出 + Background(d.LogFile, true) + + //守护进程启动一个子进程, 并循环监视 + var t int64 + count := 1 + errNum := 0 + for { + //daemon 信息描述 + dInfo := fmt.Sprintf("守护进程(pid:%d; count:%d/%d; errNum:%d/%d):", + os.Getpid(), count, d.MaxCount, errNum, d.MaxError) + if errNum > d.MaxError { + log.Println(dInfo, "启动子进程失败次数太多,退出") + os.Exit(1) + } + if d.MaxCount > 0 && count > d.MaxCount { + log.Println(dInfo, "重启次数太多退出") + os.Exit(0) + } + count++ + + t = time.Now().Unix() //启动时间戳 + cmd, err := Background(d.LogFile, false) + if err != nil { //启动失败 + log.Println(dInfo, "子进程启动失败;", "err:", err) + errNum++ + continue + } + + //子进程, + if cmd == nil { + log.Printf("子进程pid=%d: 开始运行...", os.Getpid()) + break + } + + //父进程: 等待子进程退出 + err = cmd.Wait() + dat := time.Now().Unix() - t //子进程运行秒数 + if dat < d.MinExitTime { //异常退出 + errNum++ + } else { //正常退出 + errNum = 0 + } + log.Printf("%s 监视到子进程(%d)退出, 共运行了%d秒: %v\n", dInfo, cmd.ProcessState.Pid(), dat, err) + } +} + +func startProc(args, env []string, logFile string) (*exec.Cmd, error) { + cmd := &exec.Cmd{ + Path: args[0], + Args: args, + Env: env, + SysProcAttr: NewSysProcAttr(), + } + + if logFile != "" { + stdout, err := os.OpenFile(logFile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + if err != nil { + log.Println(os.Getpid(), ": 打开日志文件错误:", err) + return nil, err + } + cmd.Stderr = stdout + cmd.Stdout = stdout + } + + err := cmd.Start() + if err != nil { + return nil, err + } + + return cmd, nil +} diff --git a/编译说明.md b/编译说明.md index 19f6594..e571ace 100644 --- a/编译说明.md +++ b/编译说明.md @@ -8,7 +8,7 @@ go-bindata-assetfs.exe -o=vue/vue.go -pkg=vue vue/dist/... # linux //生成普通发行版(未upx压缩的) -docker run --rm -v "$PWD":/media/sf_SamWaf -w /media/sf_SamWaf -e CGO_ENABLED=1 -e GOPROXY=https://goproxy.cn,direct golang:1.19 go build -v -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20230403 -X SamWaf/global.GWAF_RELEASE_VERSION=100 -s -w -extldflags "-static"" -o /media/sf_SamWaf/release/SamWafLinux64.exe main.go +docker run --rm -v "$PWD":/media/sf_SamWaf -w /media/sf_SamWaf -e CGO_ENABLED=1 -e GOPROXY=https://goproxy.cn,direct golang:1.19 go build -v -ldflags="-X SamWaf/global.GWAF_RELEASE=true -X SamWaf/global.GWAF_RELEASE_VERSION_NAME=20230525 -X SamWaf/global.GWAF_RELEASE_VERSION=100 -s -w -extldflags "-static"" -o /media/sf_SamWaf/release/SamWafLinux64.exe main.go //可调试的centos