From 778097c5fdeb1dec94f4cfc6443d08f92d9db0ba Mon Sep 17 00:00:00 2001 From: Eugene Burkov Date: Mon, 30 Nov 2020 16:40:33 +0300 Subject: [PATCH] all: add sysutil package --- CHANGELOG.md | 4 +- internal/home/control_update.go | 9 +--- internal/home/home.go | 7 ++-- internal/home/service.go | 3 +- internal/{util => sysutil}/os_freebsd.go | 19 ++++++--- internal/sysutil/os_linux.go | 41 +++++++++++++++++++ internal/{util => sysutil}/os_unix.go | 19 ++++++--- internal/{util => sysutil}/os_windows.go | 16 +++++++- .../syslog_others.go => sysutil/syslog.go} | 7 ++-- internal/{util => sysutil}/syslog_windows.go | 6 ++- 10 files changed, 101 insertions(+), 30 deletions(-) rename internal/{util => sysutil}/os_freebsd.go (52%) create mode 100644 internal/sysutil/os_linux.go rename internal/{util => sysutil}/os_unix.go (50%) rename internal/{util => sysutil}/os_windows.go (55%) rename internal/{util/syslog_others.go => sysutil/syslog.go} (54%) rename internal/{util => sysutil}/syslog_windows.go (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdd806a0fb7..3170b04fca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,12 +26,14 @@ and this project adheres to ### Changed -- Make the mobileconfig HTTP API more robust and predictable, add parameters and +- Updating and relaunching policy is now OS-dependent ([#2231]). +- Made the mobileconfig HTTP API more robust and predictable, add parameters and improve error response ([#2358]). - Improved HTTP requests handling and timeouts. ([#2343]). - Our snap package now uses the `core20` image as its base [#2306]. - Various internal improvements ([#2271], [#2297]). +[#2231]: https://github.com/AdguardTeam/AdGuardHome/issues/2231 [#2271]: https://github.com/AdguardTeam/AdGuardHome/issues/2271 [#2297]: https://github.com/AdguardTeam/AdGuardHome/issues/2297 [#2306]: https://github.com/AdguardTeam/AdGuardHome/issues/2306 diff --git a/internal/home/control_update.go b/internal/home/control_update.go index 2ab5d6a2026..dcf428b9956 100644 --- a/internal/home/control_update.go +++ b/internal/home/control_update.go @@ -10,8 +10,8 @@ import ( "strings" "syscall" + "github.com/AdguardTeam/AdGuardHome/internal/sysutil" "github.com/AdguardTeam/AdGuardHome/internal/update" - "github.com/AdguardTeam/AdGuardHome/internal/util" "github.com/AdguardTeam/golibs/log" ) @@ -104,12 +104,7 @@ func getVersionResp(info update.VersionInfo) []byte { tlsConf.PortDNSOverQUIC < 1024)) || config.BindPort < 1024 || config.DNS.Port < 1024) { - // On UNIX, if we're running under a regular user, - // but with CAP_NET_BIND_SERVICE set on a binary file, - // and we're listening on ports <1024, - // we won't be able to restart after we replace the binary file, - // because we'll lose CAP_NET_BIND_SERVICE capability. - canUpdate, _ = util.HaveAdminRights() + canUpdate, _ = sysutil.CanBindPrivilegedPorts() } ret["can_autoupdate"] = canUpdate } diff --git a/internal/home/home.go b/internal/home/home.go index 82f5ccf4050..a4be016fc54 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -26,6 +26,7 @@ import ( "github.com/AdguardTeam/AdGuardHome/internal/dnsforward" "github.com/AdguardTeam/AdGuardHome/internal/querylog" "github.com/AdguardTeam/AdGuardHome/internal/stats" + "github.com/AdguardTeam/AdGuardHome/internal/sysutil" "github.com/AdguardTeam/AdGuardHome/internal/update" "github.com/AdguardTeam/AdGuardHome/internal/util" "github.com/AdguardTeam/golibs/log" @@ -222,7 +223,7 @@ func setupConfig(args options) { if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") && config.RlimitNoFile != 0 { - util.SetRlimit(config.RlimitNoFile) + sysutil.SetRlimit(config.RlimitNoFile) } // override bind host/port from the console @@ -376,7 +377,7 @@ func checkPermissions() { if runtime.GOOS == "windows" { // On Windows we need to have admin rights to run properly - admin, _ := util.HaveAdminRights() + admin, _ := sysutil.HaveAdminRights() if admin { return } @@ -493,7 +494,7 @@ func configureLogger(args options) { if ls.LogFile == configSyslog { // Use syslog where it is possible and eventlog on Windows - err := util.ConfigureSyslog(serviceName) + err := sysutil.ConfigureSyslog(serviceName) if err != nil { log.Fatalf("cannot initialize syslog: %s", err) } diff --git a/internal/home/service.go b/internal/home/service.go index fa86f943f4a..aa2436349db 100644 --- a/internal/home/service.go +++ b/internal/home/service.go @@ -9,6 +9,7 @@ import ( "strings" "syscall" + "github.com/AdguardTeam/AdGuardHome/internal/sysutil" "github.com/AdguardTeam/AdGuardHome/internal/util" "github.com/AdguardTeam/golibs/log" "github.com/kardianos/service" @@ -109,7 +110,7 @@ func sendSigReload() { log.Error("Can't read PID file %s: %s", pidfile, err) return } - err = util.SendProcessSignal(pid, syscall.SIGHUP) + err = sysutil.SendProcessSignal(pid, syscall.SIGHUP) if err != nil { log.Error("Can't send signal to PID %d: %s", pid, err) return diff --git a/internal/util/os_freebsd.go b/internal/sysutil/os_freebsd.go similarity index 52% rename from internal/util/os_freebsd.go rename to internal/sysutil/os_freebsd.go index 042e83fe793..532b1e0688a 100644 --- a/internal/util/os_freebsd.go +++ b/internal/sysutil/os_freebsd.go @@ -1,6 +1,7 @@ -// +build freebsd +//+build freebsd -package util +// Package sysutil contains utilities for functions requiring system calls. +package sysutil import ( "os" @@ -9,8 +10,14 @@ import ( "github.com/AdguardTeam/golibs/log" ) -// Set user-specified limit of how many fd's we can use -// https://github.com/AdguardTeam/AdGuardHome/internal/issues/659 +// CanBindPrivilegedPorts checks if current process can bind to privileged +// ports. +func CanBindPrivilegedPorts() (can bool, err error) { + return HaveAdminRights() +} + +// SetRlimit sets user-specified limit of how many fd's we can use +// https://github.com/AdguardTeam/AdGuardHome/internal/issues/659. func SetRlimit(val uint) { var rlim syscall.Rlimit rlim.Max = int64(val) @@ -21,12 +28,12 @@ func SetRlimit(val uint) { } } -// Check if the current user has root (administrator) rights +// HaveAdminRights checks if the current user has root (administrator) rights. func HaveAdminRights() (bool, error) { return os.Getuid() == 0, nil } -// SendProcessSignal - send signal to a process +// SendProcessSignal sends signal to a process. func SendProcessSignal(pid int, sig syscall.Signal) error { return syscall.Kill(pid, sig) } diff --git a/internal/sysutil/os_linux.go b/internal/sysutil/os_linux.go new file mode 100644 index 00000000000..450aca4b44c --- /dev/null +++ b/internal/sysutil/os_linux.go @@ -0,0 +1,41 @@ +//+build linux + +// Package sysutil contains utilities for functions requiring system calls. +package sysutil + +import ( + "os" + "syscall" + + "github.com/AdguardTeam/golibs/log" + "golang.org/x/sys/unix" +) + +// CanBindPrivilegedPorts checks if current process can bind to privileged +// ports. +func CanBindPrivilegedPorts() (can bool, err error) { + cnbs, err := unix.PrctlRetInt(unix.PR_CAP_AMBIENT, unix.PR_CAP_AMBIENT_IS_SET, unix.CAP_NET_BIND_SERVICE, 0, 0) + return cnbs == 1, err +} + +// SetRlimit sets user-specified limit of how many fd's we can use +// https://github.com/AdguardTeam/AdGuardHome/internal/issues/659. +func SetRlimit(val uint) { + var rlim syscall.Rlimit + rlim.Max = uint64(val) + rlim.Cur = uint64(val) + err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlim) + if err != nil { + log.Error("Setrlimit() failed: %v", err) + } +} + +// HaveAdminRights checks if the current user has root (administrator) rights. +func HaveAdminRights() (bool, error) { + return os.Getuid() == 0, nil +} + +// SendProcessSignal sends signal to a process. +func SendProcessSignal(pid int, sig syscall.Signal) error { + return syscall.Kill(pid, sig) +} diff --git a/internal/util/os_unix.go b/internal/sysutil/os_unix.go similarity index 50% rename from internal/util/os_unix.go rename to internal/sysutil/os_unix.go index 53557566971..56404919148 100644 --- a/internal/util/os_unix.go +++ b/internal/sysutil/os_unix.go @@ -1,6 +1,7 @@ -// +build aix darwin dragonfly linux netbsd openbsd solaris +//+build aix darwin dragonfly netbsd openbsd solaris -package util +// Package sysutil contains utilities for functions requiring system calls. +package sysutil import ( "os" @@ -9,8 +10,14 @@ import ( "github.com/AdguardTeam/golibs/log" ) -// Set user-specified limit of how many fd's we can use -// https://github.com/AdguardTeam/AdGuardHome/internal/issues/659 +// CanBindPrivilegedPorts checks if current process can bind to privileged +// ports. +func CanBindPrivilegedPorts() (can bool, err error) { + return HaveAdminRights() +} + +// SetRlimit sets user-specified limit of how many fd's we can use +// https://github.com/AdguardTeam/AdGuardHome/internal/issues/659. func SetRlimit(val uint) { var rlim syscall.Rlimit rlim.Max = uint64(val) @@ -21,12 +28,12 @@ func SetRlimit(val uint) { } } -// Check if the current user has root (administrator) rights +// HaveAdminRights checks if the current user has root (administrator) rights. func HaveAdminRights() (bool, error) { return os.Getuid() == 0, nil } -// SendProcessSignal - send signal to a process +// SendProcessSignal sends signal to a process. func SendProcessSignal(pid int, sig syscall.Signal) error { return syscall.Kill(pid, sig) } diff --git a/internal/util/os_windows.go b/internal/sysutil/os_windows.go similarity index 55% rename from internal/util/os_windows.go rename to internal/sysutil/os_windows.go index 2a3742fa987..86f049f2042 100644 --- a/internal/util/os_windows.go +++ b/internal/sysutil/os_windows.go @@ -1,4 +1,7 @@ -package util +//+build windows + +// Package sysutil contains utilities for functions requiring system calls. +package sysutil import ( "fmt" @@ -7,10 +10,18 @@ import ( "golang.org/x/sys/windows" ) -// Set user-specified limit of how many fd's we can use +// CanBindPrivilegedPorts checks if current process can bind to privileged +// ports. +func CanBindPrivilegedPorts() (can bool, err error) { + return HaveAdminRights() +} + +// SetRlimit sets user-specified limit of how many fd's we can use +// https://github.com/AdguardTeam/AdGuardHome/internal/issues/659. func SetRlimit(val uint) { } +// HaveAdminRights checks if the current user has root (administrator) rights. func HaveAdminRights() (bool, error) { var token windows.Token h := windows.CurrentProcess() @@ -32,6 +43,7 @@ func HaveAdminRights() (bool, error) { return true, nil } +// SendProcessSignal sends signal to a process. func SendProcessSignal(pid int, sig syscall.Signal) error { return fmt.Errorf("not supported on Windows") } diff --git a/internal/util/syslog_others.go b/internal/sysutil/syslog.go similarity index 54% rename from internal/util/syslog_others.go rename to internal/sysutil/syslog.go index f4ad9119cb2..a1e4749f395 100644 --- a/internal/util/syslog_others.go +++ b/internal/sysutil/syslog.go @@ -1,13 +1,14 @@ -// +build !windows,!nacl,!plan9 +//+build !windows,!nacl,!plan9 -package util +// Package sysutil contains utilities for functions requiring system calls. +package sysutil import ( "log" "log/syslog" ) -// ConfigureSyslog reroutes standard logger output to syslog +// ConfigureSyslog reroutes standard logger output to syslog. func ConfigureSyslog(serviceName string) error { w, err := syslog.New(syslog.LOG_NOTICE|syslog.LOG_USER, serviceName) if err != nil { diff --git a/internal/util/syslog_windows.go b/internal/sysutil/syslog_windows.go similarity index 85% rename from internal/util/syslog_windows.go rename to internal/sysutil/syslog_windows.go index 30ee7815246..a118af2bebf 100644 --- a/internal/util/syslog_windows.go +++ b/internal/sysutil/syslog_windows.go @@ -1,4 +1,7 @@ -package util +//+build windows nacl plan9 + +// Package sysutil contains utilities for functions requiring system calls. +package sysutil import ( "log" @@ -17,6 +20,7 @@ func (w *eventLogWriter) Write(b []byte) (int, error) { return len(b), w.el.Info(1, string(b)) } +// ConfigureSyslog reroutes standard logger output to syslog. func ConfigureSyslog(serviceName string) error { // Note that the eventlog src is the same as the service name // Otherwise, we will get "the description for event id cannot be found" warning in every log record