Replace manual signal handling in runDaemon() with kardianos/service for cross-platform service lifecycle (Start/Stop/Run). Add daemon start/stop/restart subcommands using service.Control(), and improve status detection with s.Status() plus socket-check fallback. Custom macOS install logic (dscl, sudoers, pf, plist generation) is unchanged — only the runtime lifecycle is delegated to the library.
82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"github.com/kardianos/service"
|
|
)
|
|
|
|
// program implements the kardianos/service.Interface for greywall daemon
|
|
// lifecycle management. It delegates actual work to the Server type.
|
|
type program struct {
|
|
server *Server
|
|
socketPath string
|
|
tun2socksPath string
|
|
debug bool
|
|
}
|
|
|
|
// NewProgram creates a new program instance for use with kardianos/service.
|
|
func NewProgram(socketPath, tun2socksPath string, debug bool) *program {
|
|
return &program{
|
|
socketPath: socketPath,
|
|
tun2socksPath: tun2socksPath,
|
|
debug: debug,
|
|
}
|
|
}
|
|
|
|
// Start is called by kardianos/service when the service starts. It verifies
|
|
// the tun2socks binary exists, creates and starts the Server. The accept loop
|
|
// already runs in a goroutine, so this returns immediately.
|
|
func (p *program) Start(_ service.Service) error {
|
|
if _, err := os.Stat(p.tun2socksPath); err != nil {
|
|
return fmt.Errorf("tun2socks binary not found at %s (run 'sudo greywall daemon install' first)", p.tun2socksPath)
|
|
}
|
|
|
|
Logf("Starting daemon (tun2socks=%s, socket=%s)", p.tun2socksPath, p.socketPath)
|
|
|
|
p.server = NewServer(p.socketPath, p.tun2socksPath, p.debug)
|
|
if err := p.server.Start(); err != nil {
|
|
return fmt.Errorf("failed to start daemon server: %w", err)
|
|
}
|
|
|
|
Logf("Daemon started, listening on %s", p.socketPath)
|
|
return nil
|
|
}
|
|
|
|
// Stop is called by kardianos/service when the service stops.
|
|
func (p *program) Stop(_ service.Service) error {
|
|
if p.server == nil {
|
|
return nil
|
|
}
|
|
|
|
Logf("Stopping daemon")
|
|
if err := p.server.Stop(); err != nil {
|
|
Logf("Shutdown error: %v", err)
|
|
return err
|
|
}
|
|
|
|
Logf("Daemon stopped")
|
|
return nil
|
|
}
|
|
|
|
// NewServiceConfig returns a kardianos/service config matching the existing
|
|
// LaunchDaemon setup. The Name matches LaunchDaemonLabel so service.Control()
|
|
// can find and manage the already-installed service.
|
|
func NewServiceConfig() *service.Config {
|
|
return &service.Config{
|
|
Name: LaunchDaemonLabel,
|
|
DisplayName: "Greywall Daemon",
|
|
Description: "Greywall transparent network sandboxing daemon",
|
|
Arguments: []string{"daemon", "run"},
|
|
}
|
|
}
|
|
|
|
// DefaultTun2socksPath returns the expected tun2socks binary path based on
|
|
// the install directory and current architecture.
|
|
func DefaultTun2socksPath() string {
|
|
return filepath.Join(InstallLibDir, "tun2socks-darwin-"+runtime.GOARCH)
|
|
}
|