*(home): do not require root privileges on the first run
Instead of requiring root privileges, we now check if AdGuard Home can bind to privileged ports. If it cannot, we suggest either running it with root privileges or grant CAP_NET_BIND_SERVICE capability. Please note, that on Windows we still require root access. Closes: #1699
This commit is contained in:
parent
49a92605b8
commit
b43223d302
60
home/home.go
60
home/home.go
|
@ -1,23 +1,19 @@
|
|||
package home
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
@ -172,7 +168,7 @@ func run(args options) {
|
|||
Context.firstRun = detectFirstRun()
|
||||
if Context.firstRun {
|
||||
log.Info("This is the first time AdGuard Home is launched")
|
||||
requireAdminRights()
|
||||
checkPermissions()
|
||||
}
|
||||
|
||||
initConfig()
|
||||
|
@ -334,7 +330,12 @@ func StartMods() error {
|
|||
|
||||
// Check if the current user has root (administrator) rights
|
||||
// and if not, ask and try to run as root
|
||||
func requireAdminRights() {
|
||||
func checkPermissions() {
|
||||
log.Info("Checking if AdGuard Home has necessary permissions")
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
// On Windows we need to have admin rights to run properly
|
||||
|
||||
admin, _ := util.HaveAdminRights()
|
||||
if //noinspection ALL
|
||||
admin || isdelve.Enabled {
|
||||
|
@ -343,27 +344,40 @@ func requireAdminRights() {
|
|||
return
|
||||
}
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.")
|
||||
|
||||
} else {
|
||||
log.Error("This is the first launch of AdGuard Home. You must run it as root.")
|
||||
|
||||
_, _ = io.WriteString(os.Stdout, "Do you want to start AdGuard Home as root user? [y/n] ")
|
||||
stdin := bufio.NewReader(os.Stdin)
|
||||
buf, _ := stdin.ReadString('\n')
|
||||
buf = strings.TrimSpace(buf)
|
||||
if buf != "y" {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cmd := exec.Command("sudo", os.Args...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
_ = cmd.Run()
|
||||
os.Exit(1)
|
||||
// We should check if AdGuard Home is able to bind to port 53
|
||||
ok, err := util.CanBindPort(53)
|
||||
|
||||
if ok {
|
||||
log.Info("AdGuard Home can bind to port 53")
|
||||
return
|
||||
}
|
||||
|
||||
if opErr, ok := err.(*net.OpError); ok {
|
||||
if sysErr, ok := opErr.Err.(*os.SyscallError); ok {
|
||||
if errno, ok := sysErr.Err.(syscall.Errno); ok && errno == syscall.EACCES {
|
||||
msg := `Permission check failed.
|
||||
|
||||
AdGuard Home is not allowed to bind to privileged ports (for instance, port 53).
|
||||
Please note, that this is crucial for a server to be able to use privileged ports.
|
||||
|
||||
You have two options:
|
||||
1. Run AdGuard Home with root privileges
|
||||
2. On Linux you can grant the CAP_NET_BIND_SERVICE capability:
|
||||
https://github.com/AdguardTeam/AdGuardHome/wiki/Getting-Started#running-without-superuser`
|
||||
|
||||
log.Fatal(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`AdGuard failed to bind to port 53 due to %v
|
||||
|
||||
Please note, that this is crucial for a DNS server to be able to use that port.`, err)
|
||||
|
||||
log.Info(msg)
|
||||
}
|
||||
|
||||
// Write PID to a file
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// CanBindPort - checks if we can bind to this port or not
|
||||
func CanBindPort(port int) (bool, error) {
|
||||
addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
l, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_ = l.Close()
|
||||
return true, nil
|
||||
}
|
Loading…
Reference in New Issue