diff --git a/CHANGELOG.md b/CHANGELOG.md index 127971a1..39217416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ and this project adheres to ### Fixed +- Error when enabling the DHCP server when AdGuard Home couldn't determine if + the machine has a static IP. - Optical issue on custom rules ([#2641]). - Occasional crashes during startup. - The field `"range_start"` in the `GET /control/dhcp/status` HTTP API response diff --git a/internal/dhcpd/http.go b/internal/dhcpd/http.go index de155c5c..2dab1132 100644 --- a/internal/dhcpd/http.go +++ b/internal/dhcpd/http.go @@ -95,26 +95,40 @@ func (s *Server) enableDHCP(ifaceName string) (code int, err error) { var hasStaticIP bool hasStaticIP, err = sysutil.IfaceHasStaticIP(ifaceName) if err != nil { - // ErrPermission may happen here on Linux systems where AdGuard - // Home is installed using Snap. That doesn't necessarily mean - // that the machine doesn't have a static IP, so we can assume - // that it has and go on. If the machine doesn't, we'll get an - // error later. - // - // See https://github.com/AdguardTeam/AdGuardHome/issues/2667. if errors.Is(err, os.ErrPermission) { + // ErrPermission may happen here on Linux systems where + // AdGuard Home is installed using Snap. That doesn't + // necessarily mean that the machine doesn't have + // a static IP, so we can assume that it has and go on. + // If the machine doesn't, we'll get an error later. + // + // See https://github.com/AdguardTeam/AdGuardHome/issues/2667. + // + // TODO(a.garipov): I was thinking about moving this + // into IfaceHasStaticIP, but then we wouldn't be able + // to log it. Think about it more. log.Info("error while checking static ip: %s; "+ "assuming machine has static ip and going on", err) hasStaticIP = true + } else if errors.Is(err, sysutil.ErrNoStaticIPInfo) { + // Couldn't obtain a definitive answer. Assume static + // IP an go on. + log.Info("can't check for static ip; " + + "assuming machine has static ip and going on") + hasStaticIP = true } else { - return http.StatusInternalServerError, fmt.Errorf("checking static ip: %w", err) + err = fmt.Errorf("checking static ip: %w", err) + + return http.StatusInternalServerError, err } } if !hasStaticIP { err = sysutil.IfaceSetStaticIP(ifaceName) if err != nil { - return http.StatusInternalServerError, fmt.Errorf("setting static ip: %w", err) + err = fmt.Errorf("setting static ip: %w", err) + + return http.StatusInternalServerError, err } } diff --git a/internal/sysutil/net.go b/internal/sysutil/net.go index 0e3b448e..9ba41704 100644 --- a/internal/sysutil/net.go +++ b/internal/sysutil/net.go @@ -5,10 +5,17 @@ import ( "os/exec" "strings" + "github.com/AdguardTeam/AdGuardHome/internal/agherr" "github.com/AdguardTeam/golibs/log" ) +// ErrNoStaticIPInfo is returned by IfaceHasStaticIP when no information about +// the IP being static is available. +const ErrNoStaticIPInfo agherr.Error = "no information about static ip" + // IfaceHasStaticIP checks if interface is configured to have static IP address. +// If it can't give a definitive answer, it returns false and an error for which +// errors.Is(err, ErrNoStaticIPInfo) is true. func IfaceHasStaticIP(ifaceName string) (has bool, err error) { return ifaceHasStaticIP(ifaceName) } diff --git a/internal/sysutil/net_linux.go b/internal/sysutil/net_linux.go index 9205fd5c..1964f9dd 100644 --- a/internal/sysutil/net_linux.go +++ b/internal/sysutil/net_linux.go @@ -21,7 +21,11 @@ import ( const maxConfigFileSize = 1024 * 1024 func ifaceHasStaticIP(ifaceName string) (has bool, err error) { - var f *os.File + // TODO(a.garipov): Currently, this function returns the first + // definitive result. So if /etc/dhcpcd.conf has a static IP while + // /etc/network/interfaces doesn't, it will return true. Perhaps this + // is not the most desirable behavior. + for _, check := range []struct { checker func(io.Reader, string) (bool, error) filePath string @@ -32,8 +36,11 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) { checker: ifacesStaticConfig, filePath: "/etc/network/interfaces", }} { + var f *os.File f, err = os.Open(check.filePath) if err != nil { + // ErrNotExist can happen here if there is no such file. + // This is normal, as not every system uses those files. if errors.Is(err, os.ErrNotExist) { err = nil @@ -52,12 +59,14 @@ func ifaceHasStaticIP(ifaceName string) (has bool, err error) { defer fileReadCloser.Close() has, err = check.checker(fileReadCloser, ifaceName) - if has || err != nil { - break + if err != nil { + return false, err } + + return has, nil } - return has, err + return false, ErrNoStaticIPInfo } // dhcpcdStaticConfig checks if interface is configured by /etc/dhcpcd.conf to