Fix #1069 install: check static ip

Squashed commit of the following:

commit 57466233cb
Merge: 2df5f281 867bf545
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Feb 13 18:39:15 2020 +0300

    Merge branch 'master' into 1069-install-static-ip

commit 2df5f281c4
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Feb 13 18:35:54 2020 +0300

    *: lang fix

commit b4649a6b27
Merge: c2785253 f61d5f0f
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Feb 13 16:47:30 2020 +0300

    *(home): fixed issues with setting static IP on Mac

commit c27852537d
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Feb 13 14:14:30 2020 +0300

    +(dhcpd): added static IP for MacOS

commit f61d5f0f85
Author: Ildar Kamalov <i.kamalov@adguard.com>
Date:   Thu Feb 13 14:13:35 2020 +0300

    + client: show confirm before setting static IP

commit 7afa16fbe7
Author: Ildar Kamalov <i.kamalov@adguard.com>
Date:   Thu Feb 13 13:51:52 2020 +0300

    - client: fix text

commit 019bff0851
Author: Ildar Kamalov <i.kamalov@adguard.com>
Date:   Thu Feb 13 13:49:16 2020 +0300

    - client: pass all params to the check_config request

commit 194bed72f5
Author: Andrey Meshkov <am@adguard.com>
Date:   Wed Feb 12 17:12:16 2020 +0300

    *: fix home_test

commit 9359f6b55f
Merge: ae299058 c5ca2a77
Author: Andrey Meshkov <am@adguard.com>
Date:   Wed Feb 12 15:54:54 2020 +0300

    Merge with master

commit ae2990582d
Author: Andrey Meshkov <am@adguard.com>
Date:   Wed Feb 12 15:53:36 2020 +0300

    *(global): refactoring - moved runtime properties to Context

commit d8d48c5386
Author: Andrey Meshkov <am@adguard.com>
Date:   Wed Feb 12 15:04:25 2020 +0300

    *(dhcpd): refactoring, use dhcpd/network_utils where possible

commit 8d039c572f
Author: Ildar Kamalov <i.kamalov@adguard.com>
Date:   Fri Feb 7 18:37:39 2020 +0300

    - client: fix button position

commit 26c47e59dd
Author: Ildar Kamalov <i.kamalov@adguard.com>
Date:   Fri Feb 7 18:08:56 2020 +0300

    - client: fix static ip description

commit cb12babc46
Author: Andrey Meshkov <am@adguard.com>
Date:   Fri Feb 7 17:08:39 2020 +0300

    *: lower log level for some commands

commit d9001ff848
Author: Andrey Meshkov <am@adguard.com>
Date:   Fri Feb 7 16:17:59 2020 +0300

    *(documentation): updated openapi

commit 1d213d53c8
Merge: 8406d7d2 80861860
Author: Andrey Meshkov <am@adguard.com>
Date:   Fri Feb 7 15:16:46 2020 +0300

    *: merge with master

commit 8406d7d288
Author: Ildar Kamalov <i.kamalov@adguard.com>
Date:   Fri Jan 31 16:52:22 2020 +0300

    - client: fix locales

commit fb476b0117
Author: Simon Zolin <s.zolin@adguard.com>
Date:   Fri Jan 31 13:29:03 2020 +0300

    linter

commit 84b5708e71
Author: Simon Zolin <s.zolin@adguard.com>
Date:   Fri Jan 31 13:27:53 2020 +0300

    linter

commit 143a86a28a
Author: Simon Zolin <s.zolin@adguard.com>
Date:   Fri Jan 31 13:26:47 2020 +0300

    linter

... and 7 more commits
This commit is contained in:
Andrey Meshkov
2020-02-13 18:42:07 +03:00
parent 867bf5457f
commit 7a3eda02ce
38 changed files with 1319 additions and 781 deletions

View File

@@ -20,6 +20,10 @@ import (
"syscall"
"time"
"github.com/AdguardTeam/AdGuardHome/util"
"github.com/joomcode/errorx"
"github.com/AdguardTeam/AdGuardHome/isdelve"
"github.com/AdguardTeam/AdGuardHome/dhcpd"
@@ -49,6 +53,9 @@ const versionCheckPeriod = time.Hour * 8
// Global context
type homeContext struct {
// Modules
// --
clients clientsContainer // per-client-settings module
stats stats.Stats // statistics module
queryLog querylog.QueryLog // query log module
@@ -57,8 +64,29 @@ type homeContext struct {
whois *Whois // WHOIS module
dnsFilter *dnsfilter.Dnsfilter // DNS filtering module
dhcpServer *dhcpd.Server // DHCP module
auth *Auth // HTTP authentication module
httpServer *http.Server // HTTP module
httpsServer HTTPSServer // HTTPS module
// Runtime properties
// --
configFilename string // Config filename (can be overridden via the command line arguments)
workDir string // Location of our directory, used to protect against CWD being somewhere else
firstRun bool // if set to true, don't run any services except HTTP web inteface, and serve only first-run html
pidFileName string // PID file name. Empty if no PID file was created.
disableUpdate bool // If set, don't check for updates
controlLock sync.Mutex
transport *http.Transport
client *http.Client
appSignalChannel chan os.Signal // Channel for receiving OS signals by the console app
// runningAsService flag is set to true when options are passed from the service runner
runningAsService bool
}
// getDataDir returns path to the directory where we store databases and filters
func (c *homeContext) getDataDir() string {
return filepath.Join(c.workDir, dataDir)
}
// Context - a global context object
@@ -81,17 +109,38 @@ func Main(version string, channel string, armVer string) {
return
}
Context.appSignalChannel = make(chan os.Signal)
signal.Notify(Context.appSignalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
go func() {
<-Context.appSignalChannel
cleanup()
cleanupAlways()
os.Exit(0)
}()
// run the protection
run(args)
}
// run initializes configuration and runs the AdGuard Home
// run is a blocking method and it won't exit until the service is stopped!
// run is a blocking method!
// nolint
func run(args options) {
// config file path can be overridden by command-line arguments:
if args.configFilename != "" {
config.ourConfigFilename = args.configFilename
Context.configFilename = args.configFilename
} else {
// Default config file name
Context.configFilename = "AdGuardHome.yaml"
}
// Init some of the Context fields right away
Context.transport = &http.Transport{
DialContext: customDialContext,
}
Context.client = &http.Client{
Timeout: time.Minute * 5,
Transport: Context.transport,
}
// configure working dir and config path
@@ -106,31 +155,22 @@ func run(args options) {
msg = msg + " v" + ARMVersion
}
log.Printf(msg, versionString, updateChannel, runtime.GOOS, runtime.GOARCH, ARMVersion)
log.Debug("Current working directory is %s", config.ourWorkingDir)
log.Debug("Current working directory is %s", Context.workDir)
if args.runningAsService {
log.Info("AdGuard Home is running as a service")
}
config.runningAsService = args.runningAsService
config.disableUpdate = args.disableUpdate
Context.runningAsService = args.runningAsService
Context.disableUpdate = args.disableUpdate
config.firstRun = detectFirstRun()
if config.firstRun {
Context.firstRun = detectFirstRun()
if Context.firstRun {
requireAdminRights()
}
config.appSignalChannel = make(chan os.Signal)
signal.Notify(config.appSignalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
go func() {
<-config.appSignalChannel
cleanup()
cleanupAlways()
os.Exit(0)
}()
initConfig()
initServices()
if !config.firstRun {
if !Context.firstRun {
// Do the upgrade if necessary
err := upgradeConfig()
if err != nil {
@@ -148,7 +188,7 @@ func run(args options) {
}
}
config.DHCP.WorkDir = config.ourWorkingDir
config.DHCP.WorkDir = Context.workDir
config.DHCP.HTTPRegister = httpRegister
config.DHCP.ConfigModified = onConfigModified
Context.dhcpServer = dhcpd.Create(config.DHCP)
@@ -157,7 +197,7 @@ func run(args options) {
if (runtime.GOOS == "linux" || runtime.GOOS == "darwin") &&
config.RlimitNoFile != 0 {
setRlimit(config.RlimitNoFile)
util.SetRlimit(config.RlimitNoFile)
}
// override bind host/port from the console
@@ -168,7 +208,7 @@ func run(args options) {
config.BindPort = args.bindPort
}
if !config.firstRun {
if !Context.firstRun {
// Save the updated config
err := config.write()
if err != nil {
@@ -193,7 +233,7 @@ func run(args options) {
}
if len(args.pidFile) != 0 && writePIDFile(args.pidFile) {
config.pidFileName = args.pidFile
Context.pidFileName = args.pidFile
}
// Initialize and run the admin Web interface
@@ -204,7 +244,7 @@ func run(args options) {
registerControlHandlers()
// add handlers for /install paths, we only need them when we're not configured yet
if config.firstRun {
if Context.firstRun {
log.Info("This is the first launch of AdGuard Home, redirecting everything to /install.html ")
http.Handle("/install.html", preInstallHandler(http.FileServer(box)))
registerInstallHandlers()
@@ -291,7 +331,7 @@ func httpServerLoop() {
// Check if the current user has root (administrator) rights
// and if not, ask and try to run as root
func requireAdminRights() {
admin, _ := haveAdminRights()
admin, _ := util.HaveAdminRights()
if //noinspection ALL
admin || isdelve.Enabled {
return
@@ -331,7 +371,7 @@ func writePIDFile(fn string) bool {
return true
}
// initWorkingDir initializes the ourWorkingDir
// initWorkingDir initializes the workDir
// if no command-line arguments specified, we use the directory where our binary file is located
func initWorkingDir(args options) {
execPath, err := os.Executable()
@@ -341,9 +381,9 @@ func initWorkingDir(args options) {
if args.workDir != "" {
// If there is a custom config file, use it's directory as our working dir
config.ourWorkingDir = args.workDir
Context.workDir = args.workDir
} else {
config.ourWorkingDir = filepath.Dir(execPath)
Context.workDir = filepath.Dir(execPath)
}
}
@@ -376,12 +416,12 @@ func configureLogger(args options) {
if ls.LogFile == configSyslog {
// Use syslog where it is possible and eventlog on Windows
err := configureSyslog()
err := util.ConfigureSyslog(serviceName)
if err != nil {
log.Fatalf("cannot initialize syslog: %s", err)
}
} else {
logFilePath := filepath.Join(config.ourWorkingDir, ls.LogFile)
logFilePath := filepath.Join(Context.workDir, ls.LogFile)
if filepath.IsAbs(ls.LogFile) {
logFilePath = ls.LogFile
}
@@ -420,8 +460,8 @@ func stopHTTPServer() {
// This function is called before application exits
func cleanupAlways() {
if len(config.pidFileName) != 0 {
_ = os.Remove(config.pidFileName)
if len(Context.pidFileName) != 0 {
_ = os.Remove(Context.pidFileName)
}
log.Info("Stopped")
}
@@ -544,7 +584,7 @@ func printHTTPAddresses(proto string) {
}
} else if config.BindHost == "0.0.0.0" {
log.Println("AdGuard Home is available on the following addresses:")
ifaces, err := getValidNetInterfacesForWeb()
ifaces, err := util.GetValidNetInterfacesForWeb()
if err != nil {
// That's weird, but we'll ignore it
address = net.JoinHostPort(config.BindHost, strconv.Itoa(config.BindPort))
@@ -561,3 +601,60 @@ func printHTTPAddresses(proto string) {
log.Printf("Go to %s://%s", proto, address)
}
}
// -------------------
// first run / install
// -------------------
func detectFirstRun() bool {
configfile := Context.configFilename
if !filepath.IsAbs(configfile) {
configfile = filepath.Join(Context.workDir, Context.configFilename)
}
_, err := os.Stat(configfile)
if !os.IsNotExist(err) {
// do nothing, file exists
return false
}
return true
}
// Connect to a remote server resolving hostname using our own DNS server
func customDialContext(ctx context.Context, network, addr string) (net.Conn, error) {
log.Tracef("network:%v addr:%v", network, addr)
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
dialer := &net.Dialer{
Timeout: time.Minute * 5,
}
if net.ParseIP(host) != nil || config.DNS.Port == 0 {
con, err := dialer.DialContext(ctx, network, addr)
return con, err
}
addrs, e := Context.dnsServer.Resolve(host)
log.Debug("dnsServer.Resolve: %s: %v", host, addrs)
if e != nil {
return nil, e
}
if len(addrs) == 0 {
return nil, fmt.Errorf("couldn't lookup host: %s", host)
}
var dialErrs []error
for _, a := range addrs {
addr = net.JoinHostPort(a.String(), port)
con, err := dialer.DialContext(ctx, network, addr)
if err != nil {
dialErrs = append(dialErrs, err)
continue
}
return con, err
}
return nil, errorx.DecorateMany(fmt.Sprintf("couldn't dial to %s", addr), dialErrs...)
}