diff --git a/internal/aghnet/net.go b/internal/aghnet/net.go index b8c8c05e..3e553100 100644 --- a/internal/aghnet/net.go +++ b/internal/aghnet/net.go @@ -80,6 +80,11 @@ func CanBindPrivilegedPorts() (can bool, err error) { return canBindPrivilegedPorts() } +// AcquirePermissions tries to acquire permissions to bind to privileged ports. +func AcquirePermissions() (err error) { + return acquirePermissions() +} + // NetInterface represents an entry of network interfaces map. type NetInterface struct { // Addresses are the network interface addresses. diff --git a/internal/aghnet/net_bsd.go b/internal/aghnet/net_bsd.go index 94a27a6d..fec54112 100644 --- a/internal/aghnet/net_bsd.go +++ b/internal/aghnet/net_bsd.go @@ -7,3 +7,7 @@ import "github.com/AdguardTeam/AdGuardHome/internal/aghos" func canBindPrivilegedPorts() (can bool, err error) { return aghos.HaveAdminRights() } + +func acquirePermissions() (err error) { + return nil +} diff --git a/internal/aghnet/net_linux.go b/internal/aghnet/net_linux.go index cb9678b1..8e5f9aee 100644 --- a/internal/aghnet/net_linux.go +++ b/internal/aghnet/net_linux.go @@ -23,17 +23,17 @@ const dhcpcdConf = "etc/dhcpcd.conf" func canBindPrivilegedPorts() (can bool, err error) { res, err := unix.PrctlRetInt( - unix.PR_CAP_AMBIENT, - unix.PR_CAP_AMBIENT_RAISE, + unix.PR_CAPBSET_READ, unix.CAP_NET_BIND_SERVICE, 0, 0, + 0, ) if err != nil { if errors.Is(err, unix.EINVAL) { // Older versions of Linux kernel do not support this. Print a // warning and check admin rights. - log.Info("warning: cannot check capability cap_net_bind_service: %s", err) + log.Info("warning: cannot check cap_net_bind_service: %s", err) } else { return false, err } @@ -45,6 +45,21 @@ func canBindPrivilegedPorts() (can bool, err error) { return res == 1 || adm, nil } +func acquirePermissions() (err error) { + _, err = unix.PrctlRetInt( + unix.PR_CAP_AMBIENT, + unix.PR_CAP_AMBIENT_RAISE, + unix.CAP_NET_BIND_SERVICE, + 0, + 0, + ) + if err != nil { + return fmt.Errorf("raising cap_net_bind_service: %w", err) + } + + return nil +} + // dhcpcdStaticConfig checks if interface is configured by /etc/dhcpcd.conf to // have a static IP. func (n interfaceName) dhcpcdStaticConfig(r io.Reader) (subsources []string, cont bool, err error) { diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go index 1a17ab4d..b18354ae 100644 --- a/internal/aghnet/net_windows.go +++ b/internal/aghnet/net_windows.go @@ -43,3 +43,7 @@ func closePortChecker(c io.Closer) (err error) { func isAddrInUse(err syscall.Errno) (ok bool) { return errors.Is(err, windows.WSAEADDRINUSE) } + +func acquirePermissions() (err error) { + return nil +} diff --git a/internal/home/home.go b/internal/home/home.go index 2fb74b3c..f559fb09 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -570,14 +570,21 @@ func startMods() (err error) { func checkPermissions() { log.Info("Checking if AdGuard Home has necessary permissions") - if ok, err := aghnet.CanBindPrivilegedPorts(); !ok || err != nil { - log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.") + err := aghnet.AcquirePermissions() + if err != nil { + log.Debug("acquiring necessary permissions: %s", err) + + var ok bool + if ok, err = aghnet.CanBindPrivilegedPorts(); !ok || err != nil { + log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.") + } } // We should check if AdGuard Home is able to bind to port 53 - err := aghnet.CheckPort("tcp", netip.AddrPortFrom(netutil.IPv4Localhost(), defaultPortDNS)) + err = aghnet.CheckPort("tcp", netip.AddrPortFrom(netutil.IPv4Localhost(), defaultPortDNS)) if err != nil { if errors.Is(err, os.ErrPermission) { + log.Debug("checking permissions via binding: %v", err) log.Fatal(`Permission check failed. AdGuard Home is not allowed to bind to privileged ports (for instance, port 53).