Skip to content

Commit

Permalink
Merge branch 'master' into 5902-bootstrap-hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneOne1 committed Jun 30, 2023
2 parents 0c336af + 1fd6cf1 commit fcc65d3
Show file tree
Hide file tree
Showing 27 changed files with 729 additions and 242 deletions.
21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,27 @@ NOTE: Add new changes BELOW THIS COMMENT.

#### Configuration Changes

In this release, the schema version has changed from 20 to 22.
In this release, the schema version has changed from 20 to 23.

- Properties `bind_host`, `bind_port`, and `web_session_ttl` which used to setup
web UI binding configuration, are now moved to a new object `http` containing
new properties `address` and `session_ttl`:

```yaml
# BEFORE:
'bind_host': '1.2.3.4'
'bind_port': 8080
'web_session_ttl': 720

# AFTER:
'http':
'address': '1.2.3.4:8080'
'session_ttl': '720h'
```
Note that the new `http.session_ttl` property is now a duration string. To
rollback this change, remove the new object `http`, set back `bind_host`,
`bind_port`, `web_session_ttl`, and change the `schema_version` back to `22`.
- Property `clients.persistent.blocked_services`, which in schema versions 21
and earlier used to be a list containing ids of blocked services, is now an
object containing ids and schedule for blocked services:
Expand Down
12 changes: 2 additions & 10 deletions docker/web-bind.awk
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
# Don't consider the HTTPS hostname since the enforced HTTPS redirection should
# work if the SSL check skipped. See file docker/healthcheck.sh.
/^bind_host:/ { host = $2 }
/^[^[:space:]]/ { is_http = /^http:/ }

/^bind_port:/ { port = $2 }

END {
if (match(host, ":")) {
print "http://[" host "]:" port
} else {
print "http://" host ":" port
}
}
/^[[:space:]]+address:/ { if (is_http) print "http://" $2 }
3 changes: 3 additions & 0 deletions internal/dhcpd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func migrateDB(conf *ServerConfig) (err error) {
oldLeasesPath := filepath.Join(conf.WorkDir, dbFilename)
dataDirPath := filepath.Join(conf.DataDir, dataFilename)

// #nosec G304 -- Trust this path, since it's taken from the old file name
// relative to the working directory and should generally be considered
// safe.
file, err := os.Open(oldLeasesPath)
if errors.Is(err, os.ErrNotExist) {
// Nothing to migrate.
Expand Down
1 change: 1 addition & 0 deletions internal/dnsforward/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ func (s *Server) prepareIpsetListSettings() (err error) {
return s.ipset.init(s.conf.IpsetList)
}

// #nosec G304 -- Trust the path explicitly given by the user.
data, err := os.ReadFile(fn)
if err != nil {
return err
Expand Down
8 changes: 7 additions & 1 deletion internal/home/clientshttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/AdGuardHome/internal/schedule"
"github.com/AdguardTeam/AdGuardHome/internal/whois"
)

Expand Down Expand Up @@ -118,13 +119,18 @@ func (clients *clientsContainer) jsonToClient(cj clientJSON, prev *Client) (c *C
}
}

weekly := schedule.EmptyWeekly()
if prev != nil {
weekly = prev.BlockedServices.Schedule.Clone()
}

c = &Client{
safeSearchConf: safeSearchConf,

Name: cj.Name,

BlockedServices: &filtering.BlockedServices{
Schedule: prev.BlockedServices.Schedule.Clone(),
Schedule: weekly,
IDs: cj.BlockedServices,
},

Expand Down
52 changes: 32 additions & 20 deletions internal/home/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,17 @@ type clientSourcesConfig struct {
HostsFile bool `yaml:"hosts"`
}

// configuration is loaded from YAML
// field ordering is important -- yaml fields will mirror ordering from here
// configuration is loaded from YAML.
//
// Field ordering is important, YAML fields better not to be reordered, if it's
// not absolutely necessary.
type configuration struct {
// Raw file data to avoid re-reading of configuration file
// It's reset after config is parsed
fileData []byte

// BindHost is the address for the web interface server to listen on.
BindHost netip.Addr `yaml:"bind_host"`
// BindPort is the port for the web interface server to listen on.
BindPort int `yaml:"bind_port"`

// HTTPConfig is the block with http conf.
HTTPConfig httpConfig `yaml:"http"`
// Users are the clients capable for accessing the web interface.
Users []webUser `yaml:"users"`
// AuthAttempts is the maximum number of failed login attempts a user
Expand All @@ -120,10 +119,6 @@ type configuration struct {
// DebugPProf defines if the profiling HTTP handler will listen on :6060.
DebugPProf bool `yaml:"debug_pprof"`

// TTL for a web session (in hours)
// An active session is automatically refreshed once a day.
WebSessionTTLHours uint32 `yaml:"web_session_ttl"`

DNS dnsConfig `yaml:"dns"`
TLS tlsConfigSettings `yaml:"tls"`
QueryLog queryLogConfig `yaml:"querylog"`
Expand Down Expand Up @@ -156,7 +151,23 @@ type configuration struct {
SchemaVersion int `yaml:"schema_version"` // keeping last so that users will be less tempted to change it -- used when upgrading between versions
}

// field ordering is important -- yaml fields will mirror ordering from here
// httpConfig is a block with HTTP configuration params.
//
// Field ordering is important, YAML fields better not to be reordered, if it's
// not absolutely necessary.
type httpConfig struct {
// Address is the address to serve the web UI on.
Address netip.AddrPort

// SessionTTL for a web session.
// An active session is automatically refreshed once a day.
SessionTTL timeutil.Duration `yaml:"session_ttl"`
}

// dnsConfig is a block with DNS configuration params.
//
// Field ordering is important, YAML fields better not to be reordered, if it's
// not absolutely necessary.
type dnsConfig struct {
BindHosts []netip.Addr `yaml:"bind_hosts"`
Port int `yaml:"port"`
Expand Down Expand Up @@ -261,11 +272,12 @@ type statsConfig struct {
//
// TODO(a.garipov, e.burkov): This global is awful and must be removed.
var config = &configuration{
BindPort: 3000,
BindHost: netip.IPv4Unspecified(),
AuthAttempts: 5,
AuthBlockMin: 15,
WebSessionTTLHours: 30 * 24,
AuthAttempts: 5,
AuthBlockMin: 15,
HTTPConfig: httpConfig{
Address: netip.AddrPortFrom(netip.IPv4Unspecified(), 3000),
SessionTTL: timeutil.Duration{Duration: 30 * timeutil.Day},
},
DNS: dnsConfig{
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
Port: defaultPortDNS,
Expand Down Expand Up @@ -427,8 +439,8 @@ func readLogSettings() (ls *logSettings) {
// validateBindHosts returns error if any of binding hosts from configuration is
// not a valid IP address.
func validateBindHosts(conf *configuration) (err error) {
if !conf.BindHost.IsValid() {
return errors.Error("bind_host is not a valid ip address")
if !conf.HTTPConfig.Address.IsValid() {
return errors.Error("http.address is not a valid ip address")
}

for i, addr := range conf.DNS.BindHosts {
Expand Down Expand Up @@ -462,7 +474,7 @@ func parseConfig() (err error) {
}

tcpPorts := aghalg.UniqChecker[tcpPort]{}
addPorts(tcpPorts, tcpPort(config.BindPort))
addPorts(tcpPorts, tcpPort(config.HTTPConfig.Address.Port()))

udpPorts := aghalg.UniqChecker[udpPort]{}
addPorts(udpPorts, udpPort(config.DNS.Port))
Expand Down
4 changes: 2 additions & 2 deletions internal/home/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ type statusResponse struct {
Language string `json:"language"`
DNSAddrs []string `json:"dns_addresses"`
DNSPort int `json:"dns_port"`
HTTPPort int `json:"http_port"`
HTTPPort uint16 `json:"http_port"`

// ProtectionDisabledDuration is the duration of the protection pause in
// milliseconds.
Expand Down Expand Up @@ -158,7 +158,7 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
Language: config.Language,
DNSAddrs: dnsAddrs,
DNSPort: config.DNS.Port,
HTTPPort: config.BindPort,
HTTPPort: config.HTTPConfig.Address.Port(),
ProtectionDisabledDuration: protectionDisabledDuration,
ProtectionEnabled: protectionEnabled,
IsRunning: isRunning(),
Expand Down
24 changes: 12 additions & 12 deletions internal/home/controlinstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ type checkConfResp struct {
func (req *checkConfReq) validateWeb(tcpPorts aghalg.UniqChecker[tcpPort]) (err error) {
defer func() { err = errors.Annotate(err, "validating ports: %w") }()

portInt := req.Web.Port
port := tcpPort(portInt)
// TODO(a.garipov): Declare all port variables anywhere as uint16.
reqPort := uint16(req.Web.Port)
port := tcpPort(reqPort)
addPorts(tcpPorts, port)
if err = tcpPorts.Validate(); err != nil {
// Reset the value for the port to 1 to make sure that validateDNS
Expand All @@ -108,15 +109,15 @@ func (req *checkConfReq) validateWeb(tcpPorts aghalg.UniqChecker[tcpPort]) (err
return err
}

switch portInt {
case 0, config.BindPort:
switch reqPort {
case 0, config.HTTPConfig.Address.Port():
return nil
default:
// Go on and check the port binding only if it's not zero or won't be
// unbound after install.
}

return aghnet.CheckPort("tcp", netip.AddrPortFrom(req.Web.IP, uint16(portInt)))
return aghnet.CheckPort("tcp", netip.AddrPortFrom(req.Web.IP, reqPort))
}

// validateDNS returns error if the DNS part of the initial configuration can't
Expand All @@ -127,11 +128,11 @@ func (req *checkConfReq) validateDNS(
) (canAutofix bool, err error) {
defer func() { err = errors.Annotate(err, "validating ports: %w") }()

port := req.DNS.Port
port := uint16(req.DNS.Port)
switch port {
case 0:
return false, nil
case config.BindPort:
case config.HTTPConfig.Address.Port():
// Go on and only check the UDP port since the TCP one is already bound
// by AdGuard Home for web interface.
default:
Expand Down Expand Up @@ -318,8 +319,7 @@ type applyConfigReq struct {
// copyInstallSettings copies the installation parameters between two
// configuration structures.
func copyInstallSettings(dst, src *configuration) {
dst.BindHost = src.BindHost
dst.BindPort = src.BindPort
dst.HTTPConfig = src.HTTPConfig
dst.DNS.BindHosts = src.DNS.BindHosts
dst.DNS.Port = src.DNS.Port
}
Expand Down Expand Up @@ -413,8 +413,7 @@ func (web *webAPI) handleInstallConfigure(w http.ResponseWriter, r *http.Request
copyInstallSettings(curConfig, config)

Context.firstRun = false
config.BindHost = req.Web.IP
config.BindPort = req.Web.Port
config.HTTPConfig.Address = netip.AddrPortFrom(req.Web.IP, uint16(req.Web.Port))
config.DNS.BindHosts = []netip.Addr{req.DNS.IP}
config.DNS.Port = req.DNS.Port

Expand Down Expand Up @@ -487,7 +486,8 @@ func decodeApplyConfigReq(r io.Reader) (req *applyConfigReq, restartHTTP bool, e
return nil, false, errors.Error("ports cannot be 0")
}

restartHTTP = config.BindHost != req.Web.IP || config.BindPort != req.Web.Port
addrPort := config.HTTPConfig.Address
restartHTTP = addrPort.Addr() != req.Web.IP || int(addrPort.Port()) != req.Web.Port
if restartHTTP {
err = aghnet.CheckPort("tcp", netip.AddrPortFrom(req.Web.IP, uint16(req.Web.Port)))
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion internal/home/controlupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ func (vr *versionResponse) setAllowedToAutoUpdate() (err error) {
Context.tls.WriteDiskConfig(tlsConf)

canUpdate := true
if tlsConfUsesPrivilegedPorts(tlsConf) || config.BindPort < 1024 || config.DNS.Port < 1024 {
if tlsConfUsesPrivilegedPorts(tlsConf) ||
config.HTTPConfig.Address.Port() < 1024 ||
config.DNS.Port < 1024 {
canUpdate, err = aghnet.CanBindPrivilegedPorts()
if err != nil {
return fmt.Errorf("checking ability to bind privileged ports: %w", err)
Expand Down
Loading

0 comments on commit fcc65d3

Please sign in to comment.