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
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()
@ -332,9 +328,13 @@ func StartMods() error {
return nil
}
// Check if the current user has root (administrator) rights
// and if not, ask and try to run as root
func requireAdminRights() {
// Check if the current user permissions are enough to run AdGuard Home
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 +343,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

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
}