mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-21 20:45:33 +03:00
Pull request: home: http conf
Updates #2860. Squashed commit of the following: commit 0d55a99d5c0b9f1d8c9497775dd69929e5091eaa Merge: 73a203ac8d4a4bda64
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 16:25:36 2023 +0400 Merge remote-tracking branch 'origin/master' into http-yaml-conf commit 73a203ac8acf083fa289015e1f301d05bf320ea7 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 16:21:48 2023 +0400 home: imp docs commit a4819ace94bfe4427f70f1b8341c9babc9234740 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Thu Jun 29 11:45:30 2023 +0400 snap: imp script commit b0913c7ac5c6c46d6a73790fd57d8c5f9d7ace75 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 17:34:03 2023 +0400 all: docs commit 14820d6d56f958081d9f236277fd34f356bdab33 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 13:21:43 2023 +0400 home: imp tests commit 9db800d3ce39c36da7959e37b4a46736f4217e5c Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 13:17:34 2023 +0400 all: docs commit 9174a0ae710da51d85b4e1b1af79eda6a61dd3a2 Merge: ca8c4ae95d88181343
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 10:19:01 2023 +0400 Merge remote-tracking branch 'origin/master' into http-yaml-conf # Conflicts: # CHANGELOG.md # internal/home/upgrade.go # internal/home/upgrade_test.go commit ca8c4ae954ece25d78ef2f873bb3ba71fa4b8fa9 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 10:07:15 2023 +0400 snap: imp script commit d84473f8e07b2c6e65023613eb4032fd01951521 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Wed Jun 28 09:59:57 2023 +0400 snap: imp script commit 8a0808e42ddbff7d9d3345d758f91b14bb4453be Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jun 27 15:03:53 2023 +0400 home: http conf commit e8fbb89cc5748f9d8fa4be9e702756bd8b869de9 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jun 27 14:59:37 2023 +0400 home: imp code commit 46541aabc421118562d564675dfd7e594d2056aa Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jun 27 12:36:14 2023 +0400 snap: bind port commit cecda5fcfd8c473db42f235b4f586b2193086997 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jun 27 12:12:39 2023 +0400 docker: bind port commit 8d8945b70366c6b018616a32421c77eb281a6ea1 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jun 27 11:06:32 2023 +0400 home: imp code commit ae5e8c1c4333d7b752c08605d80e41f55ee50e59 Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Tue Jun 27 11:02:09 2023 +0400 home: imp code commit c9ee460f37e32941b84ea5fa94d21b186d6dd82b Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jun 26 17:11:10 2023 +0400 home: imp code commit 44c72445112ef38d6ec9c25b197c119edd6c959f Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jun 26 11:52:19 2023 +0400 all: docs commit e3bf5faeb748f347b1202a496788739ff9219ed0 Merge: 38cc0f639e7e638443
Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jun 26 11:39:12 2023 +0400 Merge remote-tracking branch 'origin/master' into http-yaml-conf commit 38cc0f6399040f1fa39d9da31ad6db65a6bdd4cc Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jun 26 11:38:17 2023 +0400 snap: bind port commit 3b9cb9e8cc89a67e55cecc7a2040c150f8675b4c Author: Dimitry Kolyshev <dkolyshev@adguard.com> Date: Mon Jun 26 11:25:03 2023 +0400 docker: bind port ... and 4 more commits
This commit is contained in:
parent
d4a4bda645
commit
39f5c50acd
12 changed files with 247 additions and 77 deletions
21
CHANGELOG.md
21
CHANGELOG.md
|
@ -37,8 +37,27 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||||
|
|
||||||
#### Configuration Changes
|
#### 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
|
- 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
|
and earlier used to be a list containing ids of blocked services, is now an
|
||||||
object containing ids and schedule for blocked services:
|
object containing ids and schedule for blocked services:
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
# Don't consider the HTTPS hostname since the enforced HTTPS redirection should
|
# Don't consider the HTTPS hostname since the enforced HTTPS redirection should
|
||||||
# work if the SSL check skipped. See file docker/healthcheck.sh.
|
# work if the SSL check skipped. See file docker/healthcheck.sh.
|
||||||
/^bind_host:/ { host = $2 }
|
/^[^[:space:]]/ { is_http = /^http:/ }
|
||||||
|
|
||||||
/^bind_port:/ { port = $2 }
|
/^[[:space:]]+address:/ { if (is_http) print "http://" $2 }
|
||||||
|
|
||||||
END {
|
|
||||||
if (match(host, ":")) {
|
|
||||||
print "http://[" host "]:" port
|
|
||||||
} else {
|
|
||||||
print "http://" host ":" port
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -91,18 +91,17 @@ type clientSourcesConfig struct {
|
||||||
HostsFile bool `yaml:"hosts"`
|
HostsFile bool `yaml:"hosts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// configuration is loaded from YAML
|
// configuration is loaded from YAML.
|
||||||
// field ordering is important -- yaml fields will mirror ordering from here
|
//
|
||||||
|
// Field ordering is important, YAML fields better not to be reordered, if it's
|
||||||
|
// not absolutely necessary.
|
||||||
type configuration struct {
|
type configuration struct {
|
||||||
// Raw file data to avoid re-reading of configuration file
|
// Raw file data to avoid re-reading of configuration file
|
||||||
// It's reset after config is parsed
|
// It's reset after config is parsed
|
||||||
fileData []byte
|
fileData []byte
|
||||||
|
|
||||||
// BindHost is the address for the web interface server to listen on.
|
// HTTPConfig is the block with http conf.
|
||||||
BindHost netip.Addr `yaml:"bind_host"`
|
HTTPConfig httpConfig `yaml:"http"`
|
||||||
// BindPort is the port for the web interface server to listen on.
|
|
||||||
BindPort int `yaml:"bind_port"`
|
|
||||||
|
|
||||||
// Users are the clients capable for accessing the web interface.
|
// Users are the clients capable for accessing the web interface.
|
||||||
Users []webUser `yaml:"users"`
|
Users []webUser `yaml:"users"`
|
||||||
// AuthAttempts is the maximum number of failed login attempts a user
|
// AuthAttempts is the maximum number of failed login attempts a user
|
||||||
|
@ -120,10 +119,6 @@ type configuration struct {
|
||||||
// DebugPProf defines if the profiling HTTP handler will listen on :6060.
|
// DebugPProf defines if the profiling HTTP handler will listen on :6060.
|
||||||
DebugPProf bool `yaml:"debug_pprof"`
|
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"`
|
DNS dnsConfig `yaml:"dns"`
|
||||||
TLS tlsConfigSettings `yaml:"tls"`
|
TLS tlsConfigSettings `yaml:"tls"`
|
||||||
QueryLog queryLogConfig `yaml:"querylog"`
|
QueryLog queryLogConfig `yaml:"querylog"`
|
||||||
|
@ -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
|
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 {
|
type dnsConfig struct {
|
||||||
BindHosts []netip.Addr `yaml:"bind_hosts"`
|
BindHosts []netip.Addr `yaml:"bind_hosts"`
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
|
@ -261,11 +272,12 @@ type statsConfig struct {
|
||||||
//
|
//
|
||||||
// TODO(a.garipov, e.burkov): This global is awful and must be removed.
|
// TODO(a.garipov, e.burkov): This global is awful and must be removed.
|
||||||
var config = &configuration{
|
var config = &configuration{
|
||||||
BindPort: 3000,
|
|
||||||
BindHost: netip.IPv4Unspecified(),
|
|
||||||
AuthAttempts: 5,
|
AuthAttempts: 5,
|
||||||
AuthBlockMin: 15,
|
AuthBlockMin: 15,
|
||||||
WebSessionTTLHours: 30 * 24,
|
HTTPConfig: httpConfig{
|
||||||
|
Address: netip.AddrPortFrom(netip.IPv4Unspecified(), 3000),
|
||||||
|
SessionTTL: timeutil.Duration{Duration: 30 * timeutil.Day},
|
||||||
|
},
|
||||||
DNS: dnsConfig{
|
DNS: dnsConfig{
|
||||||
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
BindHosts: []netip.Addr{netip.IPv4Unspecified()},
|
||||||
Port: defaultPortDNS,
|
Port: defaultPortDNS,
|
||||||
|
@ -427,8 +439,8 @@ func readLogSettings() (ls *logSettings) {
|
||||||
// validateBindHosts returns error if any of binding hosts from configuration is
|
// validateBindHosts returns error if any of binding hosts from configuration is
|
||||||
// not a valid IP address.
|
// not a valid IP address.
|
||||||
func validateBindHosts(conf *configuration) (err error) {
|
func validateBindHosts(conf *configuration) (err error) {
|
||||||
if !conf.BindHost.IsValid() {
|
if !conf.HTTPConfig.Address.IsValid() {
|
||||||
return errors.Error("bind_host is not a valid ip address")
|
return errors.Error("http.address is not a valid ip address")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, addr := range conf.DNS.BindHosts {
|
for i, addr := range conf.DNS.BindHosts {
|
||||||
|
@ -462,7 +474,7 @@ func parseConfig() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpPorts := aghalg.UniqChecker[tcpPort]{}
|
tcpPorts := aghalg.UniqChecker[tcpPort]{}
|
||||||
addPorts(tcpPorts, tcpPort(config.BindPort))
|
addPorts(tcpPorts, tcpPort(config.HTTPConfig.Address.Port()))
|
||||||
|
|
||||||
udpPorts := aghalg.UniqChecker[udpPort]{}
|
udpPorts := aghalg.UniqChecker[udpPort]{}
|
||||||
addPorts(udpPorts, udpPort(config.DNS.Port))
|
addPorts(udpPorts, udpPort(config.DNS.Port))
|
||||||
|
|
|
@ -103,7 +103,7 @@ type statusResponse struct {
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
DNSAddrs []string `json:"dns_addresses"`
|
DNSAddrs []string `json:"dns_addresses"`
|
||||||
DNSPort int `json:"dns_port"`
|
DNSPort int `json:"dns_port"`
|
||||||
HTTPPort int `json:"http_port"`
|
HTTPPort uint16 `json:"http_port"`
|
||||||
|
|
||||||
// ProtectionDisabledDuration is the duration of the protection pause in
|
// ProtectionDisabledDuration is the duration of the protection pause in
|
||||||
// milliseconds.
|
// milliseconds.
|
||||||
|
@ -158,7 +158,7 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
Language: config.Language,
|
Language: config.Language,
|
||||||
DNSAddrs: dnsAddrs,
|
DNSAddrs: dnsAddrs,
|
||||||
DNSPort: config.DNS.Port,
|
DNSPort: config.DNS.Port,
|
||||||
HTTPPort: config.BindPort,
|
HTTPPort: config.HTTPConfig.Address.Port(),
|
||||||
ProtectionDisabledDuration: protectionDisabledDuration,
|
ProtectionDisabledDuration: protectionDisabledDuration,
|
||||||
ProtectionEnabled: protectionEnabled,
|
ProtectionEnabled: protectionEnabled,
|
||||||
IsRunning: isRunning(),
|
IsRunning: isRunning(),
|
||||||
|
|
|
@ -96,8 +96,9 @@ type checkConfResp struct {
|
||||||
func (req *checkConfReq) validateWeb(tcpPorts aghalg.UniqChecker[tcpPort]) (err error) {
|
func (req *checkConfReq) validateWeb(tcpPorts aghalg.UniqChecker[tcpPort]) (err error) {
|
||||||
defer func() { err = errors.Annotate(err, "validating ports: %w") }()
|
defer func() { err = errors.Annotate(err, "validating ports: %w") }()
|
||||||
|
|
||||||
portInt := req.Web.Port
|
// TODO(a.garipov): Declare all port variables anywhere as uint16.
|
||||||
port := tcpPort(portInt)
|
reqPort := uint16(req.Web.Port)
|
||||||
|
port := tcpPort(reqPort)
|
||||||
addPorts(tcpPorts, port)
|
addPorts(tcpPorts, port)
|
||||||
if err = tcpPorts.Validate(); err != nil {
|
if err = tcpPorts.Validate(); err != nil {
|
||||||
// Reset the value for the port to 1 to make sure that validateDNS
|
// Reset the value for the port to 1 to make sure that validateDNS
|
||||||
|
@ -108,15 +109,15 @@ func (req *checkConfReq) validateWeb(tcpPorts aghalg.UniqChecker[tcpPort]) (err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch portInt {
|
switch reqPort {
|
||||||
case 0, config.BindPort:
|
case 0, config.HTTPConfig.Address.Port():
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
// Go on and check the port binding only if it's not zero or won't be
|
// Go on and check the port binding only if it's not zero or won't be
|
||||||
// unbound after install.
|
// 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
|
// validateDNS returns error if the DNS part of the initial configuration can't
|
||||||
|
@ -127,11 +128,11 @@ func (req *checkConfReq) validateDNS(
|
||||||
) (canAutofix bool, err error) {
|
) (canAutofix bool, err error) {
|
||||||
defer func() { err = errors.Annotate(err, "validating ports: %w") }()
|
defer func() { err = errors.Annotate(err, "validating ports: %w") }()
|
||||||
|
|
||||||
port := req.DNS.Port
|
port := uint16(req.DNS.Port)
|
||||||
switch port {
|
switch port {
|
||||||
case 0:
|
case 0:
|
||||||
return false, nil
|
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
|
// Go on and only check the UDP port since the TCP one is already bound
|
||||||
// by AdGuard Home for web interface.
|
// by AdGuard Home for web interface.
|
||||||
default:
|
default:
|
||||||
|
@ -318,8 +319,7 @@ type applyConfigReq struct {
|
||||||
// copyInstallSettings copies the installation parameters between two
|
// copyInstallSettings copies the installation parameters between two
|
||||||
// configuration structures.
|
// configuration structures.
|
||||||
func copyInstallSettings(dst, src *configuration) {
|
func copyInstallSettings(dst, src *configuration) {
|
||||||
dst.BindHost = src.BindHost
|
dst.HTTPConfig = src.HTTPConfig
|
||||||
dst.BindPort = src.BindPort
|
|
||||||
dst.DNS.BindHosts = src.DNS.BindHosts
|
dst.DNS.BindHosts = src.DNS.BindHosts
|
||||||
dst.DNS.Port = src.DNS.Port
|
dst.DNS.Port = src.DNS.Port
|
||||||
}
|
}
|
||||||
|
@ -413,8 +413,7 @@ func (web *webAPI) handleInstallConfigure(w http.ResponseWriter, r *http.Request
|
||||||
copyInstallSettings(curConfig, config)
|
copyInstallSettings(curConfig, config)
|
||||||
|
|
||||||
Context.firstRun = false
|
Context.firstRun = false
|
||||||
config.BindHost = req.Web.IP
|
config.HTTPConfig.Address = netip.AddrPortFrom(req.Web.IP, uint16(req.Web.Port))
|
||||||
config.BindPort = req.Web.Port
|
|
||||||
config.DNS.BindHosts = []netip.Addr{req.DNS.IP}
|
config.DNS.BindHosts = []netip.Addr{req.DNS.IP}
|
||||||
config.DNS.Port = req.DNS.Port
|
config.DNS.Port = req.DNS.Port
|
||||||
|
|
||||||
|
@ -487,7 +486,8 @@ func decodeApplyConfigReq(r io.Reader) (req *applyConfigReq, restartHTTP bool, e
|
||||||
return nil, false, errors.Error("ports cannot be 0")
|
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 {
|
if restartHTTP {
|
||||||
err = aghnet.CheckPort("tcp", netip.AddrPortFrom(req.Web.IP, uint16(req.Web.Port)))
|
err = aghnet.CheckPort("tcp", netip.AddrPortFrom(req.Web.IP, uint16(req.Web.Port)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -157,7 +157,9 @@ func (vr *versionResponse) setAllowedToAutoUpdate() (err error) {
|
||||||
Context.tls.WriteDiskConfig(tlsConf)
|
Context.tls.WriteDiskConfig(tlsConf)
|
||||||
|
|
||||||
canUpdate := true
|
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()
|
canUpdate, err = aghnet.CanBindPrivilegedPorts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("checking ability to bind privileged ports: %w", err)
|
return fmt.Errorf("checking ability to bind privileged ports: %w", err)
|
||||||
|
|
|
@ -372,8 +372,26 @@ func initContextClients() (err error) {
|
||||||
|
|
||||||
// setupBindOpts overrides bind host/port from the opts.
|
// setupBindOpts overrides bind host/port from the opts.
|
||||||
func setupBindOpts(opts options) (err error) {
|
func setupBindOpts(opts options) (err error) {
|
||||||
|
bindAddr := opts.bindAddr
|
||||||
|
if bindAddr != (netip.AddrPort{}) {
|
||||||
|
config.HTTPConfig.Address = bindAddr
|
||||||
|
|
||||||
|
if config.HTTPConfig.Address.Port() != 0 {
|
||||||
|
err = checkPorts()
|
||||||
|
if err != nil {
|
||||||
|
// Don't wrap the error, because it's informative enough as is.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if opts.bindPort != 0 {
|
if opts.bindPort != 0 {
|
||||||
config.BindPort = opts.bindPort
|
config.HTTPConfig.Address = netip.AddrPortFrom(
|
||||||
|
config.HTTPConfig.Address.Addr(),
|
||||||
|
uint16(opts.bindPort),
|
||||||
|
)
|
||||||
|
|
||||||
err = checkPorts()
|
err = checkPorts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -383,20 +401,10 @@ func setupBindOpts(opts options) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.bindHost.IsValid() {
|
if opts.bindHost.IsValid() {
|
||||||
config.BindHost = opts.bindHost
|
config.HTTPConfig.Address = netip.AddrPortFrom(
|
||||||
}
|
opts.bindHost,
|
||||||
|
config.HTTPConfig.Address.Port(),
|
||||||
// Rewrite deprecated options.
|
)
|
||||||
bindAddr := opts.bindAddr
|
|
||||||
if bindAddr.IsValid() {
|
|
||||||
config.BindHost = bindAddr.Addr()
|
|
||||||
config.BindPort = int(bindAddr.Port())
|
|
||||||
|
|
||||||
err = checkPorts()
|
|
||||||
if err != nil {
|
|
||||||
// Don't wrap the error, because it's informative enough as is.
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -480,7 +488,7 @@ func setupDNSFilteringConf(conf *filtering.Config) (err error) {
|
||||||
// checkPorts is a helper for ports validation in config.
|
// checkPorts is a helper for ports validation in config.
|
||||||
func checkPorts() (err error) {
|
func checkPorts() (err error) {
|
||||||
tcpPorts := aghalg.UniqChecker[tcpPort]{}
|
tcpPorts := aghalg.UniqChecker[tcpPort]{}
|
||||||
addPorts(tcpPorts, tcpPort(config.BindPort))
|
addPorts(tcpPorts, tcpPort(config.HTTPConfig.Address.Port()))
|
||||||
|
|
||||||
udpPorts := aghalg.UniqChecker[udpPort]{}
|
udpPorts := aghalg.UniqChecker[udpPort]{}
|
||||||
addPorts(udpPorts, udpPort(config.DNS.Port))
|
addPorts(udpPorts, udpPort(config.DNS.Port))
|
||||||
|
@ -520,8 +528,8 @@ func initWeb(opts options, clientBuildFS fs.FS) (web *webAPI, err error) {
|
||||||
|
|
||||||
webConf := webConfig{
|
webConf := webConfig{
|
||||||
firstRun: Context.firstRun,
|
firstRun: Context.firstRun,
|
||||||
BindHost: config.BindHost,
|
BindHost: config.HTTPConfig.Address.Addr(),
|
||||||
BindPort: config.BindPort,
|
BindPort: int(config.HTTPConfig.Address.Port()),
|
||||||
|
|
||||||
ReadTimeout: readTimeout,
|
ReadTimeout: readTimeout,
|
||||||
ReadHeaderTimeout: readHdrTimeout,
|
ReadHeaderTimeout: readHdrTimeout,
|
||||||
|
@ -657,8 +665,8 @@ func initUsers() (auth *Auth, err error) {
|
||||||
log.Info("authratelimiter is disabled")
|
log.Info("authratelimiter is disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionTTL := config.WebSessionTTLHours * 60 * 60
|
sessionTTL := config.HTTPConfig.SessionTTL.Seconds()
|
||||||
auth = InitAuth(sessFilename, config.Users, sessionTTL, rateLimiter)
|
auth = InitAuth(sessFilename, config.Users, uint32(sessionTTL), rateLimiter)
|
||||||
if auth == nil {
|
if auth == nil {
|
||||||
return nil, errors.Error("initializing auth module failed")
|
return nil, errors.Error("initializing auth module failed")
|
||||||
}
|
}
|
||||||
|
@ -936,7 +944,7 @@ func printHTTPAddresses(proto string) {
|
||||||
Context.tls.WriteDiskConfig(&tlsConf)
|
Context.tls.WriteDiskConfig(&tlsConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
port := config.BindPort
|
port := int(config.HTTPConfig.Address.Port())
|
||||||
if proto == aghhttp.SchemeHTTPS {
|
if proto == aghhttp.SchemeHTTPS {
|
||||||
port = tlsConf.PortHTTPS
|
port = tlsConf.PortHTTPS
|
||||||
}
|
}
|
||||||
|
@ -948,9 +956,9 @@ func printHTTPAddresses(proto string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bindhost := config.BindHost
|
bindHost := config.HTTPConfig.Address.Addr()
|
||||||
if !bindhost.IsUnspecified() {
|
if !bindHost.IsUnspecified() {
|
||||||
printWebAddrs(proto, bindhost.String(), port)
|
printWebAddrs(proto, bindHost.String(), port)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -961,14 +969,14 @@ func printHTTPAddresses(proto string) {
|
||||||
// That's weird, but we'll ignore it.
|
// That's weird, but we'll ignore it.
|
||||||
//
|
//
|
||||||
// TODO(e.burkov): Find out when it happens.
|
// TODO(e.burkov): Find out when it happens.
|
||||||
printWebAddrs(proto, bindhost.String(), port)
|
printWebAddrs(proto, bindHost.String(), port)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, iface := range ifaces {
|
for _, iface := range ifaces {
|
||||||
for _, addr := range iface.Addresses {
|
for _, addr := range iface.Addresses {
|
||||||
printWebAddrs(proto, addr.String(), config.BindPort)
|
printWebAddrs(proto, addr.String(), port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ func (m *tlsManager) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if setts.Enabled {
|
if setts.Enabled {
|
||||||
err = validatePorts(
|
err = validatePorts(
|
||||||
tcpPort(config.BindPort),
|
tcpPort(config.HTTPConfig.Address.Port()),
|
||||||
tcpPort(setts.PortHTTPS),
|
tcpPort(setts.PortHTTPS),
|
||||||
tcpPort(setts.PortDNSOverTLS),
|
tcpPort(setts.PortDNSOverTLS),
|
||||||
tcpPort(setts.PortDNSCrypt),
|
tcpPort(setts.PortDNSCrypt),
|
||||||
|
@ -407,7 +407,7 @@ func (m *tlsManager) handleTLSConfigure(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
if req.Enabled {
|
if req.Enabled {
|
||||||
err = validatePorts(
|
err = validatePorts(
|
||||||
tcpPort(config.BindPort),
|
tcpPort(config.HTTPConfig.Address.Port()),
|
||||||
tcpPort(req.PortHTTPS),
|
tcpPort(req.PortHTTPS),
|
||||||
tcpPort(req.PortDNSOverTLS),
|
tcpPort(req.PortDNSOverTLS),
|
||||||
tcpPort(req.PortDNSCrypt),
|
tcpPort(req.PortDNSCrypt),
|
||||||
|
|
|
@ -3,6 +3,7 @@ package home
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -22,7 +23,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// currentSchemaVersion is the current schema version.
|
// currentSchemaVersion is the current schema version.
|
||||||
const currentSchemaVersion = 22
|
const currentSchemaVersion = 23
|
||||||
|
|
||||||
// These aliases are provided for convenience.
|
// These aliases are provided for convenience.
|
||||||
type (
|
type (
|
||||||
|
@ -96,6 +97,7 @@ func upgradeConfigSchema(oldVersion int, diskConf yobj) (err error) {
|
||||||
upgradeSchema19to20,
|
upgradeSchema19to20,
|
||||||
upgradeSchema20to21,
|
upgradeSchema20to21,
|
||||||
upgradeSchema21to22,
|
upgradeSchema21to22,
|
||||||
|
upgradeSchema22to23,
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
|
@ -1256,6 +1258,73 @@ func upgradeSchema21to22(diskConf yobj) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// upgradeSchema22to23 performs the following changes:
|
||||||
|
//
|
||||||
|
// # 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'
|
||||||
|
func upgradeSchema22to23(diskConf yobj) (err error) {
|
||||||
|
log.Printf("Upgrade yaml: 22 to 23")
|
||||||
|
diskConf["schema_version"] = 23
|
||||||
|
|
||||||
|
bindHostVal, ok := diskConf["bind_host"]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bindHost, ok := bindHostVal.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of bind_host: %T", bindHostVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindHostAddr, err := netip.ParseAddr(bindHost)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid bind_host value: %s", bindHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindPortVal, ok := diskConf["bind_port"]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bindPort, ok := bindPortVal.(int)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of bind_port: %T", bindPortVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionTTLVal, ok := diskConf["web_session_ttl"]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionTTL, ok := sessionTTLVal.(int)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type of web_session_ttl: %T", sessionTTLVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := netip.AddrPortFrom(bindHostAddr, uint16(bindPort))
|
||||||
|
if !addr.IsValid() {
|
||||||
|
return fmt.Errorf("invalid address: %s", addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
diskConf["http"] = yobj{
|
||||||
|
"address": addr.String(),
|
||||||
|
"session_ttl": timeutil.Duration{Duration: time.Duration(sessionTTL) * time.Hour}.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(diskConf, "bind_host")
|
||||||
|
delete(diskConf, "bind_port")
|
||||||
|
delete(diskConf, "web_session_ttl")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
// TODO(a.garipov): Replace with log.Output when we port it to our logging
|
||||||
// package.
|
// package.
|
||||||
func funcName() string {
|
func funcName() string {
|
||||||
|
|
|
@ -1253,3 +1253,56 @@ func TestUpgradeSchema21to22(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpgradeSchema22to23(t *testing.T) {
|
||||||
|
const newSchemaVer = 23
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
in yobj
|
||||||
|
want yobj
|
||||||
|
name string
|
||||||
|
}{{
|
||||||
|
name: "empty",
|
||||||
|
in: yobj{},
|
||||||
|
want: yobj{
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "ok",
|
||||||
|
in: yobj{
|
||||||
|
"bind_host": "1.2.3.4",
|
||||||
|
"bind_port": 8081,
|
||||||
|
"web_session_ttl": 720,
|
||||||
|
},
|
||||||
|
want: yobj{
|
||||||
|
"http": yobj{
|
||||||
|
"address": "1.2.3.4:8081",
|
||||||
|
"session_ttl": "720h",
|
||||||
|
},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "v6_address",
|
||||||
|
in: yobj{
|
||||||
|
"bind_host": "2001:db8::1",
|
||||||
|
"bind_port": 8081,
|
||||||
|
"web_session_ttl": 720,
|
||||||
|
},
|
||||||
|
want: yobj{
|
||||||
|
"http": yobj{
|
||||||
|
"address": "[2001:db8::1]:8081",
|
||||||
|
"session_ttl": "720h",
|
||||||
|
},
|
||||||
|
"schema_version": newSchemaVer,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
err := upgradeSchema22to23(tc.in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, tc.want, tc.in)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -119,7 +119,9 @@ func webCheckPortAvailable(port int) (ok bool) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return aghnet.CheckPort("tcp", netip.AddrPortFrom(config.BindHost, uint16(port))) == nil
|
addrPort := netip.AddrPortFrom(config.HTTPConfig.Address.Addr(), uint16(port))
|
||||||
|
|
||||||
|
return aghnet.CheckPort("tcp", addrPort) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// tlsConfigChanged updates the TLS configuration and restarts the HTTPS server
|
// tlsConfigChanged updates the TLS configuration and restarts the HTTPS server
|
||||||
|
|
|
@ -1,7 +1,20 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
conf_file="${SNAP_DATA}/AdGuardHome.yaml"
|
||||||
|
readonly conf_file
|
||||||
|
|
||||||
|
if ! [ -f "$conf_file" ]
|
||||||
|
then
|
||||||
|
xdg-open 'http://localhost:3000'
|
||||||
|
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
# Get the admin interface port from the configuration.
|
# Get the admin interface port from the configuration.
|
||||||
bind_port="$( grep -e 'bind_port' "${SNAP_DATA}/AdGuardHome.yaml" | awk -F ' ' '{print $2}' )"
|
awk_prog='/^[^[:space:]]/ { is_http = /^http:/ };/^[[:space:]]+address:/ { if (is_http) print $2 }'
|
||||||
|
readonly awk_prog
|
||||||
|
|
||||||
|
bind_port="$( awk "$awk_prog" "$conf_file" | awk -F ':' '{print $NF}' )"
|
||||||
readonly bind_port
|
readonly bind_port
|
||||||
|
|
||||||
if [ "$bind_port" = '' ]
|
if [ "$bind_port" = '' ]
|
||||||
|
|
Loading…
Reference in a new issue