Merge : *(home): do not require root privileges on the first run

* commit '7b2cc51e35bfb725f02e91cb991ddd099b81ee0c':
  fix function comment
  *(home): do not require root privileges on the first run
This commit is contained in:
Andrey Meshkov 2020-06-23 18:24:00 +03:00
commit 7d93457154
2 changed files with 64 additions and 30 deletions

View File

@ -1,23 +1,19 @@
package home package home
import ( import (
"bufio"
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"os/exec"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"sync" "sync"
"syscall" "syscall"
"time" "time"
@ -172,7 +168,7 @@ func run(args options) {
Context.firstRun = detectFirstRun() Context.firstRun = detectFirstRun()
if Context.firstRun { if Context.firstRun {
log.Info("This is the first time AdGuard Home is launched") log.Info("This is the first time AdGuard Home is launched")
requireAdminRights() checkPermissions()
} }
initConfig() initConfig()
@ -332,9 +328,13 @@ func StartMods() error {
return nil return nil
} }
// Check if the current user has root (administrator) rights // Check if the current user permissions are enough to run AdGuard Home
// and if not, ask and try to run as root func checkPermissions() {
func requireAdminRights() { 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() admin, _ := util.HaveAdminRights()
if //noinspection ALL if //noinspection ALL
admin || isdelve.Enabled { admin || isdelve.Enabled {
@ -343,27 +343,40 @@ func requireAdminRights() {
return return
} }
if runtime.GOOS == "windows" {
log.Fatal("This is the first launch of AdGuard Home. You must run it as Administrator.") 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...) // We should check if AdGuard Home is able to bind to port 53
cmd.Stdin = os.Stdin ok, err := util.CanBindPort(53)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr if ok {
_ = cmd.Run() log.Info("AdGuard Home can bind to port 53")
os.Exit(1) 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 // Write PID to a file

21
util/net.go Normal file
View 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
}