mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-12-18 04:51:45 +03:00
all: sync with master
This commit is contained in:
parent
30244f361f
commit
73fcbd6ea2
21 changed files with 403 additions and 207 deletions
57
CHANGELOG.md
57
CHANGELOG.md
|
@ -18,12 +18,54 @@ and this project adheres to
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
## [v0.107.15] - 2022-10-26 (APPROX.)
|
## [v0.107.16] - 2022-11-02 (APPROX.)
|
||||||
|
|
||||||
|
See also the [v0.107.16 GitHub milestone][ms-v0.107.15].
|
||||||
|
|
||||||
|
[ms-v0.107.16]: https://github.com/AdguardTeam/AdGuardHome/milestone/52?closed=1
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [v0.107.15] - 2022-10-03
|
||||||
|
|
||||||
See also the [v0.107.15 GitHub milestone][ms-v0.107.15].
|
See also the [v0.107.15 GitHub milestone][ms-v0.107.15].
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- As an additional CSRF protection measure, AdGuard Home now ensures that
|
||||||
|
requests that change its state but have no body (such as `POST
|
||||||
|
/control/stats_reset` requests) do not have a `Content-Type` header set on
|
||||||
|
them ([#4970]).
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
#### Experimental HTTP/3 Support
|
||||||
|
|
||||||
|
See [#3955] and the related issues for more details. These features are still
|
||||||
|
experimental and may break or change in the future.
|
||||||
|
|
||||||
|
- DNS-over-HTTP/3 DNS and web UI client request support. This feature must be
|
||||||
|
explicitly enabled by setting the new property `dns.serve_http3` in the
|
||||||
|
configuration file to `true`.
|
||||||
|
- DNS-over-HTTP upstreams can now upgrade to HTTP/3 if the new configuration
|
||||||
|
file property `use_http3_upstreams` is set to `true`.
|
||||||
|
- Upstreams with forced DNS-over-HTTP/3 and no fallback to prior HTTP versions
|
||||||
|
using the `h3://` scheme.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- User-specific blocked services not applying correctly ([#4945], [#4982],
|
||||||
|
[#4983]).
|
||||||
|
- `only application/json is allowed` errors in various APIs ([#4970]).
|
||||||
|
|
||||||
|
[#3955]: https://github.com/AdguardTeam/AdGuardHome/issues/3955
|
||||||
|
[#4945]: https://github.com/AdguardTeam/AdGuardHome/issues/4945
|
||||||
|
[#4970]: https://github.com/AdguardTeam/AdGuardHome/issues/4970
|
||||||
|
[#4982]: https://github.com/AdguardTeam/AdGuardHome/issues/4982
|
||||||
|
[#4983]: https://github.com/AdguardTeam/AdGuardHome/issues/4983
|
||||||
|
|
||||||
[ms-v0.107.15]: https://github.com/AdguardTeam/AdGuardHome/milestone/51?closed=1
|
[ms-v0.107.15]: https://github.com/AdguardTeam/AdGuardHome/milestone/51?closed=1
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,8 +105,8 @@ bodies are documented in `openapi/openapi.yaml` and `openapi/CHANGELOG.md`.
|
||||||
|
|
||||||
#### Stricter Content-Type Checks (BREAKING API CHANGE)
|
#### Stricter Content-Type Checks (BREAKING API CHANGE)
|
||||||
|
|
||||||
All JSON APIs now check if the request actually has the `application/json`
|
All JSON APIs that expect a body now check if the request actually has
|
||||||
content-type.
|
`Content-Type` set to `application/json`.
|
||||||
|
|
||||||
#### Other Security Changes
|
#### Other Security Changes
|
||||||
|
|
||||||
|
@ -1283,11 +1325,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.15...HEAD
|
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.16...HEAD
|
||||||
[v0.107.15]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.14...v0.107.15
|
[v0.107.16]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.15...v0.107.15
|
||||||
-->
|
-->
|
||||||
|
|
||||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.14...HEAD
|
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.15...HEAD
|
||||||
|
[v0.107.15]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.14...v0.107.15
|
||||||
[v0.107.14]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.13...v0.107.14
|
[v0.107.14]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.13...v0.107.14
|
||||||
[v0.107.13]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.12...v0.107.13
|
[v0.107.13]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.12...v0.107.13
|
||||||
[v0.107.12]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.11...v0.107.12
|
[v0.107.12]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.11...v0.107.12
|
||||||
|
|
|
@ -10,11 +10,17 @@ class Api {
|
||||||
async makeRequest(path, method = 'POST', config) {
|
async makeRequest(path, method = 'POST', config) {
|
||||||
const url = `${this.baseUrl}/${path}`;
|
const url = `${this.baseUrl}/${path}`;
|
||||||
|
|
||||||
|
const axiosConfig = config || {};
|
||||||
|
if (method !== 'GET' && axiosConfig.data) {
|
||||||
|
axiosConfig.headers = axiosConfig.headers || {};
|
||||||
|
axiosConfig.headers['Content-Type'] = axiosConfig.headers['Content-Type'] || 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios({
|
const response = await axios({
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
...config,
|
...axiosConfig,
|
||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -55,7 +61,6 @@ class Api {
|
||||||
const { path, method } = this.GLOBAL_TEST_UPSTREAM_DNS;
|
const { path, method } = this.GLOBAL_TEST_UPSTREAM_DNS;
|
||||||
const config = {
|
const config = {
|
||||||
data: servers,
|
data: servers,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, config);
|
return this.makeRequest(path, method, config);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +69,6 @@ class Api {
|
||||||
const { path, method } = this.GLOBAL_VERSION;
|
const { path, method } = this.GLOBAL_VERSION;
|
||||||
const config = {
|
const config = {
|
||||||
data,
|
data,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, config);
|
return this.makeRequest(path, method, config);
|
||||||
}
|
}
|
||||||
|
@ -100,7 +104,6 @@ class Api {
|
||||||
const { path, method } = this.FILTERING_REFRESH;
|
const { path, method } = this.FILTERING_REFRESH;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
|
@ -110,7 +113,6 @@ class Api {
|
||||||
const { path, method } = this.FILTERING_ADD_FILTER;
|
const { path, method } = this.FILTERING_ADD_FILTER;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
|
@ -120,7 +122,6 @@ class Api {
|
||||||
const { path, method } = this.FILTERING_REMOVE_FILTER;
|
const { path, method } = this.FILTERING_REMOVE_FILTER;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
|
@ -130,7 +131,6 @@ class Api {
|
||||||
const { path, method } = this.FILTERING_SET_RULES;
|
const { path, method } = this.FILTERING_SET_RULES;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: rules,
|
data: rules,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,6 @@ class Api {
|
||||||
const { path, method } = this.FILTERING_CONFIG;
|
const { path, method } = this.FILTERING_CONFIG;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -148,7 +147,6 @@ class Api {
|
||||||
const { path, method } = this.FILTERING_SET_URL;
|
const { path, method } = this.FILTERING_SET_URL;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -239,7 +237,6 @@ class Api {
|
||||||
const { path, method } = this.CHANGE_LANGUAGE;
|
const { path, method } = this.CHANGE_LANGUAGE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -275,7 +272,6 @@ class Api {
|
||||||
const { path, method } = this.DHCP_SET_CONFIG;
|
const { path, method } = this.DHCP_SET_CONFIG;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -284,7 +280,6 @@ class Api {
|
||||||
const { path, method } = this.DHCP_FIND_ACTIVE;
|
const { path, method } = this.DHCP_FIND_ACTIVE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: req,
|
data: req,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -293,7 +288,6 @@ class Api {
|
||||||
const { path, method } = this.DHCP_ADD_STATIC_LEASE;
|
const { path, method } = this.DHCP_ADD_STATIC_LEASE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -302,7 +296,6 @@ class Api {
|
||||||
const { path, method } = this.DHCP_REMOVE_STATIC_LEASE;
|
const { path, method } = this.DHCP_REMOVE_STATIC_LEASE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -333,7 +326,6 @@ class Api {
|
||||||
const { path, method } = this.INSTALL_CONFIGURE;
|
const { path, method } = this.INSTALL_CONFIGURE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -342,7 +334,6 @@ class Api {
|
||||||
const { path, method } = this.INSTALL_CHECK_CONFIG;
|
const { path, method } = this.INSTALL_CHECK_CONFIG;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -363,7 +354,6 @@ class Api {
|
||||||
const { path, method } = this.TLS_CONFIG;
|
const { path, method } = this.TLS_CONFIG;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -372,7 +362,6 @@ class Api {
|
||||||
const { path, method } = this.TLS_VALIDATE;
|
const { path, method } = this.TLS_VALIDATE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -397,7 +386,6 @@ class Api {
|
||||||
const { path, method } = this.ADD_CLIENT;
|
const { path, method } = this.ADD_CLIENT;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +394,6 @@ class Api {
|
||||||
const { path, method } = this.DELETE_CLIENT;
|
const { path, method } = this.DELETE_CLIENT;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -415,7 +402,6 @@ class Api {
|
||||||
const { path, method } = this.UPDATE_CLIENT;
|
const { path, method } = this.UPDATE_CLIENT;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -440,7 +426,6 @@ class Api {
|
||||||
const { path, method } = this.ACCESS_SET;
|
const { path, method } = this.ACCESS_SET;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -461,7 +446,6 @@ class Api {
|
||||||
const { path, method } = this.REWRITE_ADD;
|
const { path, method } = this.REWRITE_ADD;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -470,7 +454,6 @@ class Api {
|
||||||
const { path, method } = this.REWRITE_DELETE;
|
const { path, method } = this.REWRITE_DELETE;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -496,7 +479,6 @@ class Api {
|
||||||
const { path, method } = this.BLOCKED_SERVICES_SET;
|
const { path, method } = this.BLOCKED_SERVICES_SET;
|
||||||
const parameters = {
|
const parameters = {
|
||||||
data: config,
|
data: config,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, parameters);
|
return this.makeRequest(path, method, parameters);
|
||||||
}
|
}
|
||||||
|
@ -524,7 +506,6 @@ class Api {
|
||||||
const { path, method } = this.STATS_CONFIG;
|
const { path, method } = this.STATS_CONFIG;
|
||||||
const config = {
|
const config = {
|
||||||
data,
|
data,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, config);
|
return this.makeRequest(path, method, config);
|
||||||
}
|
}
|
||||||
|
@ -560,7 +541,6 @@ class Api {
|
||||||
const { path, method } = this.QUERY_LOG_CONFIG;
|
const { path, method } = this.QUERY_LOG_CONFIG;
|
||||||
const config = {
|
const config = {
|
||||||
data,
|
data,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, config);
|
return this.makeRequest(path, method, config);
|
||||||
}
|
}
|
||||||
|
@ -577,7 +557,6 @@ class Api {
|
||||||
const { path, method } = this.LOGIN;
|
const { path, method } = this.LOGIN;
|
||||||
const config = {
|
const config = {
|
||||||
data,
|
data,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, config);
|
return this.makeRequest(path, method, config);
|
||||||
}
|
}
|
||||||
|
@ -604,7 +583,6 @@ class Api {
|
||||||
const { path, method } = this.SET_DNS_CONFIG;
|
const { path, method } = this.SET_DNS_CONFIG;
|
||||||
const config = {
|
const config = {
|
||||||
data,
|
data,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
};
|
};
|
||||||
return this.makeRequest(path, method, config);
|
return this.makeRequest(path, method, config);
|
||||||
}
|
}
|
||||||
|
|
16
go.mod
16
go.mod
|
@ -3,7 +3,7 @@ module github.com/AdguardTeam/AdGuardHome
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdguardTeam/dnsproxy v0.44.0
|
github.com/AdguardTeam/dnsproxy v0.45.2
|
||||||
github.com/AdguardTeam/golibs v0.10.9
|
github.com/AdguardTeam/golibs v0.10.9
|
||||||
github.com/AdguardTeam/urlfilter v0.16.0
|
github.com/AdguardTeam/urlfilter v0.16.0
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
|
@ -18,7 +18,7 @@ require (
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84
|
github.com/insomniacslk/dhcp v0.0.0-20220822114210-de18a9d48e84
|
||||||
github.com/kardianos/service v1.2.1
|
github.com/kardianos/service v1.2.1
|
||||||
github.com/lucas-clemente/quic-go v0.29.0
|
github.com/lucas-clemente/quic-go v0.29.1
|
||||||
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118
|
||||||
github.com/mdlayher/netlink v1.6.0
|
github.com/mdlayher/netlink v1.6.0
|
||||||
// TODO(a.garipov): This package is deprecated; find a new one or use
|
// TODO(a.garipov): This package is deprecated; find a new one or use
|
||||||
|
@ -28,10 +28,10 @@ require (
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
github.com/ti-mo/netfilter v0.4.0
|
github.com/ti-mo/netfilter v0.4.0
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||||
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91
|
golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9
|
||||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c
|
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||||
golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
howett.net/plist v1.0.0
|
howett.net/plist v1.0.0
|
||||||
|
@ -43,10 +43,12 @@ require (
|
||||||
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
|
||||||
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
github.com/ameshkov/dnsstamps v1.0.3 // indirect
|
||||||
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
|
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 // indirect
|
||||||
|
github.com/bluele/gcache v0.0.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/josharian/native v1.0.0 // indirect
|
github.com/josharian/native v1.0.0 // indirect
|
||||||
|
github.com/marten-seemann/qpack v0.2.1 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
github.com/marten-seemann/qtls-go1-19 v0.1.0 // indirect
|
||||||
github.com/mdlayher/packet v1.0.0 // indirect
|
github.com/mdlayher/packet v1.0.0 // indirect
|
||||||
|
@ -57,7 +59,7 @@ require (
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
|
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220922195421-2adab6b8c60e // indirect
|
||||||
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
|
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/tools v0.1.12 // indirect
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
|
|
35
go.sum
35
go.sum
|
@ -1,5 +1,5 @@
|
||||||
github.com/AdguardTeam/dnsproxy v0.44.0 h1:JzIxEXF4OyJq4wZVHeZkM1af4VfuwcgrUzjgdBGljsE=
|
github.com/AdguardTeam/dnsproxy v0.45.2 h1:K9BXkQAfAKjrzbWbczpA2IA1owLe/edv0nG0e2+Esko=
|
||||||
github.com/AdguardTeam/dnsproxy v0.44.0/go.mod h1:HsxYYW/bC8uo+4eX9pRW21hFD6gWZdrvcfBb1R6/AzU=
|
github.com/AdguardTeam/dnsproxy v0.45.2/go.mod h1:h+0r4GDvHHY2Wu6r7oqva+O37h00KofYysfzy1TEXFE=
|
||||||
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||||
github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
|
github.com/AdguardTeam/golibs v0.10.4/go.mod h1:rSfQRGHIdgfxriDDNgNJ7HmE5zRoURq8R+VdR81Zuzw=
|
||||||
github.com/AdguardTeam/golibs v0.10.9 h1:F9oP2da0dQ9RQDM1lGR7LxUTfUWu8hEFOs4icwAkKM0=
|
github.com/AdguardTeam/golibs v0.10.9 h1:F9oP2da0dQ9RQDM1lGR7LxUTfUWu8hEFOs4icwAkKM0=
|
||||||
|
@ -23,6 +23,8 @@ github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1O
|
||||||
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
|
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
|
||||||
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 h1:0b2vaepXIfMsG++IsjHiI2p4bxALD1Y2nQKGMR5zDQM=
|
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0 h1:0b2vaepXIfMsG++IsjHiI2p4bxALD1Y2nQKGMR5zDQM=
|
||||||
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA=
|
github.com/beefsack/go-rate v0.0.0-20220214233405-116f4ca011a0/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA=
|
||||||
|
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
|
||||||
|
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
@ -88,8 +90,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lucas-clemente/quic-go v0.29.0 h1:Vw0mGTfmWqGzh4jx/kMymsIkFK6rErFVmg+t9RLrnZE=
|
github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0=
|
||||||
github.com/lucas-clemente/quic-go v0.29.0/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE=
|
github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE=
|
||||||
|
github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
|
||||||
|
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
||||||
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||||
github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
|
github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU=
|
||||||
|
@ -125,6 +129,7 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
|
@ -168,16 +173,16 @@ go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
|
golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9 h1:lNtcVz/3bOstm7Vebox+5m3nLh/BYWnhmc3AhXOW6oI=
|
||||||
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9 h1:VtCrPQXM5Wo9l7XN64SjBMczl48j8mkP+2e3OhYlz+0=
|
golang.org/x/mod v0.6.0-dev.0.20220922195421-2adab6b8c60e h1:WhB000cGjOfbJiedMGvJkMTclI18VD69w27k+sceql8=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220922195421-2adab6b8c60e/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -189,6 +194,7 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
@ -200,8 +206,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c h1:yKufUcDwucU5urd+50/Opbt4AYpqthk7wHpHok8f1lo=
|
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
|
||||||
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -224,6 +230,7 @@ golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -247,8 +254,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 h1:C1tElbkWrsSkn3IRl1GCW/gETw1TywWIPgwZtXTZbYg=
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||||
golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|
|
@ -33,7 +33,7 @@ func OK(w http.ResponseWriter) {
|
||||||
// Error writes formatted message to w and also logs it.
|
// Error writes formatted message to w and also logs it.
|
||||||
func Error(r *http.Request, w http.ResponseWriter, code int, format string, args ...any) {
|
func Error(r *http.Request, w http.ResponseWriter, code int, format string, args ...any) {
|
||||||
text := fmt.Sprintf(format, args...)
|
text := fmt.Sprintf(format, args...)
|
||||||
log.Error("%s %s: %s", r.Method, r.URL, text)
|
log.Error("%s %s %s: %s", r.Method, r.Host, r.URL, text)
|
||||||
http.Error(w, text, code)
|
http.Error(w, text, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ package aghhttp
|
||||||
const (
|
const (
|
||||||
HdrNameAcceptEncoding = "Accept-Encoding"
|
HdrNameAcceptEncoding = "Accept-Encoding"
|
||||||
HdrNameAccessControlAllowOrigin = "Access-Control-Allow-Origin"
|
HdrNameAccessControlAllowOrigin = "Access-Control-Allow-Origin"
|
||||||
HdrNameContentType = "Content-Type"
|
|
||||||
HdrNameContentEncoding = "Content-Encoding"
|
HdrNameContentEncoding = "Content-Encoding"
|
||||||
|
HdrNameContentType = "Content-Type"
|
||||||
HdrNameServer = "Server"
|
HdrNameServer = "Server"
|
||||||
HdrNameTrailer = "Trailer"
|
HdrNameTrailer = "Trailer"
|
||||||
HdrNameUserAgent = "User-Agent"
|
HdrNameUserAgent = "User-Agent"
|
||||||
|
|
|
@ -183,15 +183,7 @@ func (s *Server) accessListJSON() (j accessListJSON) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAccessList(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleAccessList(w http.ResponseWriter, r *http.Request) {
|
||||||
j := s.accessListJSON()
|
_ = aghhttp.WriteJSONResponse(w, r, s.accessListJSON())
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
err := json.NewEncoder(w).Encode(j)
|
|
||||||
if err != nil {
|
|
||||||
aghhttp.Error(r, w, http.StatusInternalServerError, "encoding response: %s", err)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateAccessSet checks the internal accessListJSON lists. To search for
|
// validateAccessSet checks the internal accessListJSON lists. To search for
|
||||||
|
|
|
@ -201,6 +201,10 @@ type ServerConfig struct {
|
||||||
// Register an HTTP handler
|
// Register an HTTP handler
|
||||||
HTTPRegister aghhttp.RegisterFunc
|
HTTPRegister aghhttp.RegisterFunc
|
||||||
|
|
||||||
|
// LocalPTRResolvers is a slice of addresses to be used as upstreams for
|
||||||
|
// resolving PTR queries for local addresses.
|
||||||
|
LocalPTRResolvers []string
|
||||||
|
|
||||||
// ResolveClients signals if the RDNS should resolve clients' addresses.
|
// ResolveClients signals if the RDNS should resolve clients' addresses.
|
||||||
ResolveClients bool
|
ResolveClients bool
|
||||||
|
|
||||||
|
@ -208,9 +212,12 @@ type ServerConfig struct {
|
||||||
// locally-served networks should be resolved via private PTR resolvers.
|
// locally-served networks should be resolved via private PTR resolvers.
|
||||||
UsePrivateRDNS bool
|
UsePrivateRDNS bool
|
||||||
|
|
||||||
// LocalPTRResolvers is a slice of addresses to be used as upstreams for
|
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
|
||||||
// resolving PTR queries for local addresses.
|
ServeHTTP3 bool
|
||||||
LocalPTRResolvers []string
|
|
||||||
|
// UseHTTP3Upstreams defines if HTTP/3 is be allowed for DNS-over-HTTPS
|
||||||
|
// upstreams.
|
||||||
|
UseHTTP3Upstreams bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// if any of ServerConfig values are zero, then default values from below are used
|
// if any of ServerConfig values are zero, then default values from below are used
|
||||||
|
@ -226,6 +233,7 @@ func (s *Server) createProxyConfig() (conf proxy.Config, err error) {
|
||||||
conf = proxy.Config{
|
conf = proxy.Config{
|
||||||
UDPListenAddr: srvConf.UDPListenAddrs,
|
UDPListenAddr: srvConf.UDPListenAddrs,
|
||||||
TCPListenAddr: srvConf.TCPListenAddrs,
|
TCPListenAddr: srvConf.TCPListenAddrs,
|
||||||
|
HTTP3: srvConf.ServeHTTP3,
|
||||||
Ratelimit: int(srvConf.Ratelimit),
|
Ratelimit: int(srvConf.Ratelimit),
|
||||||
RatelimitWhitelist: srvConf.RatelimitWhitelist,
|
RatelimitWhitelist: srvConf.RatelimitWhitelist,
|
||||||
RefuseAny: srvConf.RefuseAny,
|
RefuseAny: srvConf.RefuseAny,
|
||||||
|
@ -324,6 +332,20 @@ func (s *Server) initDefaultSettings() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpstreamHTTPVersions returns the HTTP versions for upstream configuration
|
||||||
|
// depending on configuration.
|
||||||
|
func UpstreamHTTPVersions(http3 bool) (v []upstream.HTTPVersion) {
|
||||||
|
if !http3 {
|
||||||
|
return upstream.DefaultHTTPVersions
|
||||||
|
}
|
||||||
|
|
||||||
|
return []upstream.HTTPVersion{
|
||||||
|
upstream.HTTPVersion3,
|
||||||
|
upstream.HTTPVersion2,
|
||||||
|
upstream.HTTPVersion11,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// prepareUpstreamSettings - prepares upstream DNS server settings
|
// prepareUpstreamSettings - prepares upstream DNS server settings
|
||||||
func (s *Server) prepareUpstreamSettings() error {
|
func (s *Server) prepareUpstreamSettings() error {
|
||||||
// We're setting a customized set of RootCAs
|
// We're setting a customized set of RootCAs
|
||||||
|
@ -353,12 +375,14 @@ func (s *Server) prepareUpstreamSettings() error {
|
||||||
upstreams = s.conf.UpstreamDNS
|
upstreams = s.conf.UpstreamDNS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpVersions := UpstreamHTTPVersions(s.conf.UseHTTP3Upstreams)
|
||||||
upstreams = stringutil.FilterOut(upstreams, IsCommentOrEmpty)
|
upstreams = stringutil.FilterOut(upstreams, IsCommentOrEmpty)
|
||||||
upstreamConfig, err := proxy.ParseUpstreamsConfig(
|
upstreamConfig, err := proxy.ParseUpstreamsConfig(
|
||||||
upstreams,
|
upstreams,
|
||||||
&upstream.Options{
|
&upstream.Options{
|
||||||
Bootstrap: s.conf.BootstrapDNS,
|
Bootstrap: s.conf.BootstrapDNS,
|
||||||
Timeout: s.conf.UpstreamTimeout,
|
Timeout: s.conf.UpstreamTimeout,
|
||||||
|
HTTPVersions: httpVersions,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -371,8 +395,9 @@ func (s *Server) prepareUpstreamSettings() error {
|
||||||
uc, err = proxy.ParseUpstreamsConfig(
|
uc, err = proxy.ParseUpstreamsConfig(
|
||||||
defaultDNS,
|
defaultDNS,
|
||||||
&upstream.Options{
|
&upstream.Options{
|
||||||
Bootstrap: s.conf.BootstrapDNS,
|
Bootstrap: s.conf.BootstrapDNS,
|
||||||
Timeout: s.conf.UpstreamTimeout,
|
Timeout: s.conf.UpstreamTimeout,
|
||||||
|
HTTPVersions: httpVersions,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -151,7 +151,7 @@ func (s *Server) checkHostRules(host string, rrtype uint16, setts *filtering.Set
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterDNSResponse checks each resource record of the response's answer
|
// filterDNSResponse checks each resource record of the response's answer
|
||||||
// section from pctx and returns a non-nil res if at least one of canonnical
|
// section from pctx and returns a non-nil res if at least one of canonical
|
||||||
// names or IP addresses in it matches the filtering rules.
|
// names or IP addresses in it matches the filtering rules.
|
||||||
func (s *Server) filterDNSResponse(
|
func (s *Server) filterDNSResponse(
|
||||||
pctx *proxy.DNSContext,
|
pctx *proxy.DNSContext,
|
||||||
|
|
|
@ -112,13 +112,7 @@ func (s *Server) handleGetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
DefautLocalPTRUpstreams: defLocalPTRUps,
|
DefautLocalPTRUpstreams: defLocalPTRUps,
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
|
|
||||||
if err = json.NewEncoder(w).Encode(resp); err != nil {
|
|
||||||
aghhttp.Error(r, w, http.StatusInternalServerError, "json.Encoder: %s", err)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (req *jsonDNSConfig) checkBlockingMode() (err error) {
|
func (req *jsonDNSConfig) checkBlockingMode() (err error) {
|
||||||
|
@ -349,7 +343,10 @@ func newUpstreamConfig(upstreams []string) (conf *proxy.UpstreamConfig, err erro
|
||||||
|
|
||||||
conf, err = proxy.ParseUpstreamsConfig(
|
conf, err = proxy.ParseUpstreamsConfig(
|
||||||
upstreams,
|
upstreams,
|
||||||
&upstream.Options{Bootstrap: []string{}, Timeout: DefaultTimeout},
|
&upstream.Options{
|
||||||
|
Bootstrap: []string{},
|
||||||
|
Timeout: DefaultTimeout,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -412,7 +409,15 @@ func ValidateUpstreamsPrivate(upstreams []string, privateNets netutil.SubnetSet)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var protocols = []string{"udp://", "tcp://", "tls://", "https://", "sdns://", "quic://"}
|
var protocols = []string{
|
||||||
|
"h3://",
|
||||||
|
"https://",
|
||||||
|
"quic://",
|
||||||
|
"sdns://",
|
||||||
|
"tcp://",
|
||||||
|
"tls://",
|
||||||
|
"udp://",
|
||||||
|
}
|
||||||
|
|
||||||
// validateUpstream returns an error if u alongside with domains is not a valid
|
// validateUpstream returns an error if u alongside with domains is not a valid
|
||||||
// upstream configuration. useDefault is true if the upstream is
|
// upstream configuration. useDefault is true if the upstream is
|
||||||
|
@ -659,24 +664,7 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) {
|
||||||
result[host] = "OK"
|
result[host] = "OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonVal, err := json.Marshal(result)
|
_ = aghhttp.WriteJSONResponse(w, r, result)
|
||||||
if err != nil {
|
|
||||||
aghhttp.Error(
|
|
||||||
r,
|
|
||||||
w,
|
|
||||||
http.StatusInternalServerError,
|
|
||||||
"Unable to marshal status json: %s",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
_, err = w.Write(jsonVal)
|
|
||||||
if err != nil {
|
|
||||||
aghhttp.Error(r, w, http.StatusInternalServerError, "Couldn't write body: %s", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDoH is the DNS-over-HTTPs handler.
|
// handleDoH is the DNS-over-HTTPs handler.
|
||||||
|
@ -692,11 +680,13 @@ func (s *Server) handleTestUpstreamDNS(w http.ResponseWriter, r *http.Request) {
|
||||||
func (s *Server) handleDoH(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleDoH(w http.ResponseWriter, r *http.Request) {
|
||||||
if !s.conf.TLSAllowUnencryptedDoH && r.TLS == nil {
|
if !s.conf.TLSAllowUnencryptedDoH && r.TLS == nil {
|
||||||
aghhttp.Error(r, w, http.StatusNotFound, "Not Found")
|
aghhttp.Error(r, w, http.StatusNotFound, "Not Found")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !s.IsRunning() {
|
if !s.IsRunning() {
|
||||||
aghhttp.Error(r, w, http.StatusInternalServerError, "dns server is not running")
|
aghhttp.Error(r, w, http.StatusInternalServerError, "dns server is not running")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
|
@ -116,7 +117,8 @@ func TestDNSForwardHTTP_handleGetConfig(t *testing.T) {
|
||||||
s.conf = tc.conf()
|
s.conf = tc.conf()
|
||||||
s.handleGetConfig(w, nil)
|
s.handleGetConfig(w, nil)
|
||||||
|
|
||||||
assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
|
cType := w.Header().Get(aghhttp.HdrNameContentType)
|
||||||
|
assert.Equal(t, aghhttp.HdrValApplicationJSON, cType)
|
||||||
assert.JSONEq(t, string(caseWant), w.Body.String())
|
assert.JSONEq(t, string(caseWant), w.Body.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -456,8 +456,9 @@ func (clients *clientsContainer) findUpstreams(
|
||||||
conf, err = proxy.ParseUpstreamsConfig(
|
conf, err = proxy.ParseUpstreamsConfig(
|
||||||
upstreams,
|
upstreams,
|
||||||
&upstream.Options{
|
&upstream.Options{
|
||||||
Bootstrap: config.DNS.BootstrapDNS,
|
Bootstrap: config.DNS.BootstrapDNS,
|
||||||
Timeout: config.DNS.UpstreamTimeout.Duration,
|
Timeout: config.DNS.UpstreamTimeout.Duration,
|
||||||
|
HTTPVersions: dnsforward.UpstreamHTTPVersions(config.DNS.UseHTTP3Upstreams),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -166,6 +166,19 @@ type dnsConfig struct {
|
||||||
// LocalPTRResolvers is the slice of addresses to be used as upstreams
|
// LocalPTRResolvers is the slice of addresses to be used as upstreams
|
||||||
// for PTR queries for locally-served networks.
|
// for PTR queries for locally-served networks.
|
||||||
LocalPTRResolvers []string `yaml:"local_ptr_upstreams"`
|
LocalPTRResolvers []string `yaml:"local_ptr_upstreams"`
|
||||||
|
|
||||||
|
// ServeHTTP3 defines if HTTP/3 is be allowed for incoming requests.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Add to the UI when HTTP/3 support is no longer
|
||||||
|
// experimental.
|
||||||
|
ServeHTTP3 bool `yaml:"serve_http3"`
|
||||||
|
|
||||||
|
// UseHTTP3Upstreams defines if HTTP/3 is be allowed for DNS-over-HTTPS
|
||||||
|
// upstreams.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Add to the UI when HTTP/3 support is no longer
|
||||||
|
// experimental.
|
||||||
|
UseHTTP3Upstreams bool `yaml:"use_http3_upstreams"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type tlsConfigSettings struct {
|
type tlsConfigSettings struct {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package home
|
package home
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||||
|
@ -97,16 +97,16 @@ func collectDNSAddresses() (addrs []string, err error) {
|
||||||
|
|
||||||
// statusResponse is a response for /control/status endpoint.
|
// statusResponse is a response for /control/status endpoint.
|
||||||
type statusResponse struct {
|
type statusResponse struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
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 int `json:"http_port"`
|
||||||
IsProtectionEnabled bool `json:"protection_enabled"`
|
IsProtectionEnabled bool `json:"protection_enabled"`
|
||||||
// TODO(e.burkov): Inspect if front-end doesn't requires this field as
|
// TODO(e.burkov): Inspect if front-end doesn't requires this field as
|
||||||
// openapi.yaml declares.
|
// openapi.yaml declares.
|
||||||
IsDHCPAvailable bool `json:"dhcp_available"`
|
IsDHCPAvailable bool `json:"dhcp_available"`
|
||||||
IsRunning bool `json:"running"`
|
IsRunning bool `json:"running"`
|
||||||
Version string `json:"version"`
|
|
||||||
Language string `json:"language"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStatus(w http.ResponseWriter, r *http.Request) {
|
func handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -125,12 +125,12 @@ func handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
defer config.RUnlock()
|
defer config.RUnlock()
|
||||||
|
|
||||||
resp = statusResponse{
|
resp = statusResponse{
|
||||||
|
Version: version.Version(),
|
||||||
DNSAddrs: dnsAddrs,
|
DNSAddrs: dnsAddrs,
|
||||||
DNSPort: config.DNS.Port,
|
DNSPort: config.DNS.Port,
|
||||||
HTTPPort: config.BindPort,
|
HTTPPort: config.BindPort,
|
||||||
IsRunning: isRunning(),
|
|
||||||
Version: version.Version(),
|
|
||||||
Language: config.Language,
|
Language: config.Language,
|
||||||
|
IsRunning: isRunning(),
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -154,19 +154,12 @@ type profileJSON struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleGetProfile(w http.ResponseWriter, r *http.Request) {
|
func handleGetProfile(w http.ResponseWriter, r *http.Request) {
|
||||||
pj := profileJSON{}
|
|
||||||
u := Context.auth.getCurrentUser(r)
|
u := Context.auth.getCurrentUser(r)
|
||||||
|
resp := &profileJSON{
|
||||||
pj.Name = u.Name
|
Name: u.Name,
|
||||||
|
|
||||||
data, err := json.Marshal(pj)
|
|
||||||
if err != nil {
|
|
||||||
aghhttp.Error(r, w, http.StatusInternalServerError, "json.Marshal: %s", err)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = w.Write(data)
|
_ = aghhttp.WriteJSONResponse(w, r, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
@ -196,29 +189,26 @@ func httpRegister(method, url string, handler http.HandlerFunc) {
|
||||||
Context.mux.Handle(url, postInstallHandler(optionalAuthHandler(gziphandler.GzipHandler(ensureHandler(method, handler)))))
|
Context.mux.Handle(url, postInstallHandler(optionalAuthHandler(gziphandler.GzipHandler(ensureHandler(method, handler)))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ensure returns a wrapped handler that makes sure that the request has the
|
||||||
// helper functions for HTTP handlers
|
// correct method as well as additional method and header checks.
|
||||||
// ----------------------------------
|
func ensure(
|
||||||
func ensure(method string, handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
method string,
|
||||||
|
handler func(http.ResponseWriter, *http.Request),
|
||||||
|
) (wrapped func(http.ResponseWriter, *http.Request)) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Debug("%s %v", r.Method, r.URL)
|
start := time.Now()
|
||||||
|
m, u := r.Method, r.URL
|
||||||
|
log.Debug("started %s %s %s", m, r.Host, u)
|
||||||
|
defer func() { log.Debug("finished %s %s %s in %s", m, r.Host, u, time.Since(start)) }()
|
||||||
|
|
||||||
if r.Method != method {
|
if m != method {
|
||||||
aghhttp.Error(r, w, http.StatusMethodNotAllowed, "only %s is allowed", method)
|
aghhttp.Error(r, w, http.StatusMethodNotAllowed, "only method %s is allowed", method)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if method == http.MethodPost || method == http.MethodPut || method == http.MethodDelete {
|
if modifiesData(m) {
|
||||||
if r.Header.Get(aghhttp.HdrNameContentType) != aghhttp.HdrValApplicationJSON {
|
if !ensureContentType(w, r) {
|
||||||
aghhttp.Error(
|
|
||||||
r,
|
|
||||||
w,
|
|
||||||
http.StatusUnsupportedMediaType,
|
|
||||||
"only %s is allowed",
|
|
||||||
aghhttp.HdrValApplicationJSON,
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +220,42 @@ func ensure(method string, handler func(http.ResponseWriter, *http.Request)) fun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// modifiesData returns true if m is an HTTP method that can modify data.
|
||||||
|
func modifiesData(m string) (ok bool) {
|
||||||
|
return m == http.MethodPost || m == http.MethodPut || m == http.MethodDelete
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureContentType makes sure that the content type of a data-modifying
|
||||||
|
// request is set correctly. If it is not, ensureContentType writes a response
|
||||||
|
// to w, and ok is false.
|
||||||
|
func ensureContentType(w http.ResponseWriter, r *http.Request) (ok bool) {
|
||||||
|
const statusUnsup = http.StatusUnsupportedMediaType
|
||||||
|
|
||||||
|
cType := r.Header.Get(aghhttp.HdrNameContentType)
|
||||||
|
if r.ContentLength == 0 {
|
||||||
|
if cType == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that browsers always send a content type when submitting HTML
|
||||||
|
// forms and require no content type for requests with no body to make
|
||||||
|
// sure that the request comes from JavaScript.
|
||||||
|
aghhttp.Error(r, w, statusUnsup, "empty body with content-type %q not allowed", cType)
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const wantCType = aghhttp.HdrValApplicationJSON
|
||||||
|
if cType == wantCType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
aghhttp.Error(r, w, statusUnsup, "only content-type %s is allowed", wantCType)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func ensurePOST(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
func ensurePOST(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
|
||||||
return ensure(http.MethodPost, handler)
|
return ensure(http.MethodPost, handler)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||||
"github.com/AdguardTeam/golibs/errors"
|
"github.com/AdguardTeam/golibs/errors"
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
|
"github.com/lucas-clemente/quic-go/http3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getAddrsResponse is the response for /install/get_addresses endpoint.
|
// getAddrsResponse is the response for /install/get_addresses endpoint.
|
||||||
|
@ -328,6 +329,7 @@ func copyInstallSettings(dst, src *configuration) {
|
||||||
// shutdownTimeout is the timeout for shutting HTTP server down operation.
|
// shutdownTimeout is the timeout for shutting HTTP server down operation.
|
||||||
const shutdownTimeout = 5 * time.Second
|
const shutdownTimeout = 5 * time.Second
|
||||||
|
|
||||||
|
// shutdownSrv shuts srv down and prints error messages to the log.
|
||||||
func shutdownSrv(ctx context.Context, srv *http.Server) {
|
func shutdownSrv(ctx context.Context, srv *http.Server) {
|
||||||
defer log.OnPanic("")
|
defer log.OnPanic("")
|
||||||
|
|
||||||
|
@ -336,13 +338,38 @@ func shutdownSrv(ctx context.Context, srv *http.Server) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err := srv.Shutdown(ctx)
|
err := srv.Shutdown(ctx)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
const msgFmt = "shutting down http server %q: %s"
|
return
|
||||||
if errors.Is(err, context.Canceled) {
|
}
|
||||||
log.Debug(msgFmt, srv.Addr, err)
|
|
||||||
} else {
|
const msgFmt = "shutting down http server %q: %s"
|
||||||
log.Error(msgFmt, srv.Addr, err)
|
if errors.Is(err, context.Canceled) {
|
||||||
}
|
log.Debug(msgFmt, srv.Addr, err)
|
||||||
|
} else {
|
||||||
|
log.Error(msgFmt, srv.Addr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// shutdownSrv3 shuts srv down and prints error messages to the log.
|
||||||
|
//
|
||||||
|
// TODO(a.garipov): Think of a good way to merge with [shutdownSrv].
|
||||||
|
func shutdownSrv3(srv *http3.Server) {
|
||||||
|
defer log.OnPanic("")
|
||||||
|
|
||||||
|
if srv == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := srv.Close()
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const msgFmt = "shutting down http/3 server %q: %s"
|
||||||
|
if errors.Is(err, context.Canceled) {
|
||||||
|
log.Debug(msgFmt, srv.Addr, err)
|
||||||
|
} else {
|
||||||
|
log.Error(msgFmt, srv.Addr, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,16 +572,11 @@ func (web *Web) handleInstallCheckConfigBeta(w http.ResponseWriter, r *http.Requ
|
||||||
|
|
||||||
err = json.NewEncoder(nonBetaReqBody).Encode(nonBetaReqData)
|
err = json.NewEncoder(nonBetaReqBody).Encode(nonBetaReqData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aghhttp.Error(
|
aghhttp.Error(r, w, http.StatusBadRequest, "encoding check_config: %s", err)
|
||||||
r,
|
|
||||||
w,
|
|
||||||
http.StatusBadRequest,
|
|
||||||
"Failed to encode 'check_config' JSON data: %s",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
body := nonBetaReqBody.String()
|
body := nonBetaReqBody.String()
|
||||||
r.Body = io.NopCloser(strings.NewReader(body))
|
r.Body = io.NopCloser(strings.NewReader(body))
|
||||||
r.ContentLength = int64(len(body))
|
r.ContentLength = int64(len(body))
|
||||||
|
@ -622,13 +644,7 @@ func (web *Web) handleInstallConfigureBeta(w http.ResponseWriter, r *http.Reques
|
||||||
|
|
||||||
err = json.NewEncoder(nonBetaReqBody).Encode(nonBetaReqData)
|
err = json.NewEncoder(nonBetaReqBody).Encode(nonBetaReqData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aghhttp.Error(
|
aghhttp.Error(r, w, http.StatusBadRequest, "encoding configure: %s", err)
|
||||||
r,
|
|
||||||
w,
|
|
||||||
http.StatusBadRequest,
|
|
||||||
"Failed to encode 'check_config' JSON data: %s",
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,11 +246,14 @@ func generateServerConfig() (newConf dnsforward.ServerConfig, err error) {
|
||||||
newConf.FilterHandler = applyAdditionalFiltering
|
newConf.FilterHandler = applyAdditionalFiltering
|
||||||
newConf.GetCustomUpstreamByClient = Context.clients.findUpstreams
|
newConf.GetCustomUpstreamByClient = Context.clients.findUpstreams
|
||||||
|
|
||||||
newConf.ResolveClients = config.Clients.Sources.RDNS
|
|
||||||
newConf.UsePrivateRDNS = dnsConf.UsePrivateRDNS
|
|
||||||
newConf.LocalPTRResolvers = dnsConf.LocalPTRResolvers
|
newConf.LocalPTRResolvers = dnsConf.LocalPTRResolvers
|
||||||
newConf.UpstreamTimeout = dnsConf.UpstreamTimeout.Duration
|
newConf.UpstreamTimeout = dnsConf.UpstreamTimeout.Duration
|
||||||
|
|
||||||
|
newConf.ResolveClients = config.Clients.Sources.RDNS
|
||||||
|
newConf.UsePrivateRDNS = dnsConf.UsePrivateRDNS
|
||||||
|
newConf.ServeHTTP3 = dnsConf.ServeHTTP3
|
||||||
|
newConf.UseHTTP3Upstreams = dnsConf.UseHTTP3Upstreams
|
||||||
|
|
||||||
return newConf, nil
|
return newConf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +361,13 @@ func applyAdditionalFiltering(clientIP net.IP, clientID string, setts *filtering
|
||||||
log.Debug("%s: using settings for client %q (%s; %q)", pref, c.Name, clientIP, clientID)
|
log.Debug("%s: using settings for client %q (%s; %q)", pref, c.Name, clientIP, clientID)
|
||||||
|
|
||||||
if c.UseOwnBlockedServices {
|
if c.UseOwnBlockedServices {
|
||||||
Context.filters.ApplyBlockedServices(setts, c.BlockedServices)
|
// TODO(e.burkov): Get rid of this crutch.
|
||||||
|
svcs := c.BlockedServices
|
||||||
|
if svcs == nil {
|
||||||
|
svcs = []string{}
|
||||||
|
}
|
||||||
|
Context.filters.ApplyBlockedServices(setts, svcs)
|
||||||
|
log.Debug("%s: services for client %q set: %s", pref, c.Name, svcs)
|
||||||
}
|
}
|
||||||
|
|
||||||
setts.ClientName = c.Name
|
setts.ClientName = c.Name
|
||||||
|
|
|
@ -381,9 +381,11 @@ func initWeb(args options, clientBuildFS fs.FS) (web *Web, err error) {
|
||||||
|
|
||||||
clientFS: clientFS,
|
clientFS: clientFS,
|
||||||
clientBetaFS: clientBetaFS,
|
clientBetaFS: clientBetaFS,
|
||||||
|
|
||||||
|
serveHTTP3: config.DNS.ServeHTTP3,
|
||||||
}
|
}
|
||||||
|
|
||||||
web = CreateWeb(&webConf)
|
web = newWeb(&webConf)
|
||||||
if web == nil {
|
if web == nil {
|
||||||
return nil, fmt.Errorf("initializing web: %w", err)
|
return nil, fmt.Errorf("initializing web: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,7 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !WebCheckPortAvailable(setts.PortHTTPS) {
|
if !webCheckPortAvailable(setts.PortHTTPS) {
|
||||||
aghhttp.Error(
|
aghhttp.Error(
|
||||||
r,
|
r,
|
||||||
w,
|
w,
|
||||||
|
@ -356,7 +356,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(e.burkov): Investigate and perhaps check other ports.
|
// TODO(e.burkov): Investigate and perhaps check other ports.
|
||||||
if !WebCheckPortAvailable(data.PortHTTPS) {
|
if !webCheckPortAvailable(data.PortHTTPS) {
|
||||||
aghhttp.Error(
|
aghhttp.Error(
|
||||||
r,
|
r,
|
||||||
w,
|
w,
|
||||||
|
|
|
@ -16,6 +16,8 @@ import (
|
||||||
"github.com/AdguardTeam/golibs/log"
|
"github.com/AdguardTeam/golibs/log"
|
||||||
"github.com/AdguardTeam/golibs/netutil"
|
"github.com/AdguardTeam/golibs/netutil"
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
|
"github.com/lucas-clemente/quic-go"
|
||||||
|
"github.com/lucas-clemente/quic-go/http3"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"golang.org/x/net/http2/h2c"
|
"golang.org/x/net/http2/h2c"
|
||||||
)
|
)
|
||||||
|
@ -53,40 +55,56 @@ type webConfig struct {
|
||||||
WriteTimeout time.Duration
|
WriteTimeout time.Duration
|
||||||
|
|
||||||
firstRun bool
|
firstRun bool
|
||||||
|
|
||||||
|
serveHTTP3 bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPSServer - HTTPS Server
|
// httpsServer contains the data for the HTTPS server.
|
||||||
type HTTPSServer struct {
|
type httpsServer struct {
|
||||||
server *http.Server
|
// server is the pre-HTTP/3 HTTPS server.
|
||||||
cond *sync.Cond
|
server *http.Server
|
||||||
condLock sync.Mutex
|
// server3 is the HTTP/3 HTTPS server. If it is not nil,
|
||||||
shutdown bool // if TRUE, don't restart the server
|
// [httpsServer.server] must also be non-nil.
|
||||||
enabled bool
|
server3 *http3.Server
|
||||||
cert tls.Certificate
|
|
||||||
|
// TODO(a.garipov): Why is there a *sync.Cond here? Remove.
|
||||||
|
cond *sync.Cond
|
||||||
|
condLock sync.Mutex
|
||||||
|
cert tls.Certificate
|
||||||
|
inShutdown bool
|
||||||
|
enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web - module object
|
// Web is the web UI and API server.
|
||||||
type Web struct {
|
type Web struct {
|
||||||
conf *webConfig
|
conf *webConfig
|
||||||
forceHTTPS bool
|
|
||||||
httpServer *http.Server // HTTP module
|
|
||||||
httpsServer HTTPSServer // HTTPS module
|
|
||||||
|
|
||||||
// handlerBeta is the handler for new client.
|
// TODO(a.garipov): Refactor all these servers.
|
||||||
handlerBeta http.Handler
|
httpServer *http.Server
|
||||||
// installerBeta is the pre-install handler for new client.
|
|
||||||
installerBeta http.Handler
|
|
||||||
|
|
||||||
// httpServerBeta is a server for new client.
|
// httpServerBeta is a server for new client.
|
||||||
httpServerBeta *http.Server
|
httpServerBeta *http.Server
|
||||||
|
|
||||||
|
// handlerBeta is the handler for new client.
|
||||||
|
handlerBeta http.Handler
|
||||||
|
|
||||||
|
// installerBeta is the pre-install handler for new client.
|
||||||
|
installerBeta http.Handler
|
||||||
|
|
||||||
|
// httpsServer is the server that handles HTTPS traffic. If it is not nil,
|
||||||
|
// [Web.http3Server] must also not be nil.
|
||||||
|
httpsServer httpsServer
|
||||||
|
|
||||||
|
forceHTTPS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateWeb - create module
|
// newWeb creates a new instance of the web UI and API server.
|
||||||
func CreateWeb(conf *webConfig) *Web {
|
func newWeb(conf *webConfig) (w *Web) {
|
||||||
log.Info("Initialize web module")
|
log.Info("web: initializing")
|
||||||
|
|
||||||
w := Web{}
|
w = &Web{
|
||||||
w.conf = conf
|
conf: conf,
|
||||||
|
}
|
||||||
|
|
||||||
clientFS := http.FileServer(http.FS(conf.clientFS))
|
clientFS := http.FileServer(http.FS(conf.clientFS))
|
||||||
betaClientFS := http.FileServer(http.FS(conf.clientBetaFS))
|
betaClientFS := http.FileServer(http.FS(conf.clientBetaFS))
|
||||||
|
@ -108,12 +126,15 @@ func CreateWeb(conf *webConfig) *Web {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.httpsServer.cond = sync.NewCond(&w.httpsServer.condLock)
|
w.httpsServer.cond = sync.NewCond(&w.httpsServer.condLock)
|
||||||
return &w
|
|
||||||
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebCheckPortAvailable - check if port is available
|
// webCheckPortAvailable checks if port, which is considered an HTTPS port, is
|
||||||
// BUT: if we are already using this port, no need
|
// available, unless the HTTPS server isn't active.
|
||||||
func WebCheckPortAvailable(port int) bool {
|
//
|
||||||
|
// TODO(a.garipov): Adapt for HTTP/3.
|
||||||
|
func webCheckPortAvailable(port int) (ok bool) {
|
||||||
return Context.web.httpsServer.server != nil ||
|
return Context.web.httpsServer.server != nil ||
|
||||||
aghnet.CheckPort("tcp", config.BindHost, port) == nil
|
aghnet.CheckPort("tcp", config.BindHost, port) == nil
|
||||||
}
|
}
|
||||||
|
@ -121,7 +142,7 @@ func WebCheckPortAvailable(port int) bool {
|
||||||
// TLSConfigChanged updates the TLS configuration and restarts the HTTPS server
|
// TLSConfigChanged updates the TLS configuration and restarts the HTTPS server
|
||||||
// if necessary.
|
// if necessary.
|
||||||
func (web *Web) TLSConfigChanged(ctx context.Context, tlsConf tlsConfigSettings) {
|
func (web *Web) TLSConfigChanged(ctx context.Context, tlsConf tlsConfigSettings) {
|
||||||
log.Debug("Web: applying new TLS configuration")
|
log.Debug("web: applying new tls configuration")
|
||||||
web.conf.PortHTTPS = tlsConf.PortHTTPS
|
web.conf.PortHTTPS = tlsConf.PortHTTPS
|
||||||
web.forceHTTPS = (tlsConf.ForceHTTPS && tlsConf.Enabled && tlsConf.PortHTTPS != 0)
|
web.forceHTTPS = (tlsConf.ForceHTTPS && tlsConf.Enabled && tlsConf.PortHTTPS != 0)
|
||||||
|
|
||||||
|
@ -143,6 +164,8 @@ func (web *Web) TLSConfigChanged(ctx context.Context, tlsConf tlsConfigSettings)
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
ctx, cancel = context.WithTimeout(ctx, shutdownTimeout)
|
ctx, cancel = context.WithTimeout(ctx, shutdownTimeout)
|
||||||
shutdownSrv(ctx, web.httpsServer.server)
|
shutdownSrv(ctx, web.httpsServer.server)
|
||||||
|
shutdownSrv3(web.httpsServer.server3)
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +183,7 @@ func (web *Web) Start() {
|
||||||
go web.tlsServerLoop()
|
go web.tlsServerLoop()
|
||||||
|
|
||||||
// this loop is used as an ability to change listening host and/or port
|
// this loop is used as an ability to change listening host and/or port
|
||||||
for !web.httpsServer.shutdown {
|
for !web.httpsServer.inShutdown {
|
||||||
printHTTPAddresses(aghhttp.SchemeHTTP)
|
printHTTPAddresses(aghhttp.SchemeHTTP)
|
||||||
errs := make(chan error, 2)
|
errs := make(chan error, 2)
|
||||||
|
|
||||||
|
@ -231,7 +254,7 @@ func (web *Web) Close(ctx context.Context) {
|
||||||
log.Info("stopping http server...")
|
log.Info("stopping http server...")
|
||||||
|
|
||||||
web.httpsServer.cond.L.Lock()
|
web.httpsServer.cond.L.Lock()
|
||||||
web.httpsServer.shutdown = true
|
web.httpsServer.inShutdown = true
|
||||||
web.httpsServer.cond.L.Unlock()
|
web.httpsServer.cond.L.Unlock()
|
||||||
|
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
|
@ -239,6 +262,7 @@ func (web *Web) Close(ctx context.Context) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
shutdownSrv(ctx, web.httpsServer.server)
|
shutdownSrv(ctx, web.httpsServer.server)
|
||||||
|
shutdownSrv3(web.httpsServer.server3)
|
||||||
shutdownSrv(ctx, web.httpServer)
|
shutdownSrv(ctx, web.httpServer)
|
||||||
shutdownSrv(ctx, web.httpServerBeta)
|
shutdownSrv(ctx, web.httpServerBeta)
|
||||||
|
|
||||||
|
@ -248,7 +272,7 @@ func (web *Web) Close(ctx context.Context) {
|
||||||
func (web *Web) tlsServerLoop() {
|
func (web *Web) tlsServerLoop() {
|
||||||
for {
|
for {
|
||||||
web.httpsServer.cond.L.Lock()
|
web.httpsServer.cond.L.Lock()
|
||||||
if web.httpsServer.shutdown {
|
if web.httpsServer.inShutdown {
|
||||||
web.httpsServer.cond.L.Unlock()
|
web.httpsServer.cond.L.Unlock()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -256,7 +280,7 @@ func (web *Web) tlsServerLoop() {
|
||||||
// this mechanism doesn't let us through until all conditions are met
|
// this mechanism doesn't let us through until all conditions are met
|
||||||
for !web.httpsServer.enabled { // sleep until necessary data is supplied
|
for !web.httpsServer.enabled { // sleep until necessary data is supplied
|
||||||
web.httpsServer.cond.Wait()
|
web.httpsServer.cond.Wait()
|
||||||
if web.httpsServer.shutdown {
|
if web.httpsServer.inShutdown {
|
||||||
web.httpsServer.cond.L.Unlock()
|
web.httpsServer.cond.L.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -264,11 +288,10 @@ func (web *Web) tlsServerLoop() {
|
||||||
|
|
||||||
web.httpsServer.cond.L.Unlock()
|
web.httpsServer.cond.L.Unlock()
|
||||||
|
|
||||||
// prepare HTTPS server
|
addr := netutil.JoinHostPort(web.conf.BindHost.String(), web.conf.PortHTTPS)
|
||||||
address := netutil.JoinHostPort(web.conf.BindHost.String(), web.conf.PortHTTPS)
|
|
||||||
web.httpsServer.server = &http.Server{
|
web.httpsServer.server = &http.Server{
|
||||||
ErrorLog: log.StdLog("web: https", log.DEBUG),
|
ErrorLog: log.StdLog("web: https", log.DEBUG),
|
||||||
Addr: address,
|
Addr: addr,
|
||||||
TLSConfig: &tls.Config{
|
TLSConfig: &tls.Config{
|
||||||
Certificates: []tls.Certificate{web.httpsServer.cert},
|
Certificates: []tls.Certificate{web.httpsServer.cert},
|
||||||
RootCAs: Context.tlsRoots,
|
RootCAs: Context.tlsRoots,
|
||||||
|
@ -282,10 +305,40 @@ func (web *Web) tlsServerLoop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
printHTTPAddresses(aghhttp.SchemeHTTPS)
|
printHTTPAddresses(aghhttp.SchemeHTTPS)
|
||||||
|
|
||||||
|
if web.conf.serveHTTP3 {
|
||||||
|
go web.mustStartHTTP3(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("web: starting https server")
|
||||||
err := web.httpsServer.server.ListenAndServeTLS("", "")
|
err := web.httpsServer.server.ListenAndServeTLS("", "")
|
||||||
if err != http.ErrServerClosed {
|
if !errors.Is(err, http.ErrServerClosed) {
|
||||||
cleanupAlways()
|
cleanupAlways()
|
||||||
log.Fatal(err)
|
log.Fatalf("web: https: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (web *Web) mustStartHTTP3(address string) {
|
||||||
|
defer log.OnPanic("web: http3")
|
||||||
|
|
||||||
|
web.httpsServer.server3 = &http3.Server{
|
||||||
|
// TODO(a.garipov): See if there is a way to use the error log as
|
||||||
|
// well as timeouts here.
|
||||||
|
Addr: address,
|
||||||
|
TLSConfig: &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{web.httpsServer.cert},
|
||||||
|
RootCAs: Context.tlsRoots,
|
||||||
|
CipherSuites: aghtls.SaferCipherSuites(),
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
},
|
||||||
|
Handler: withMiddlewares(Context.mux, limitRequestBody),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("web: starting http/3 server")
|
||||||
|
err := web.httpsServer.server3.ListenAndServe()
|
||||||
|
if !errors.Is(err, quic.ErrServerClosed) {
|
||||||
|
cleanupAlways()
|
||||||
|
log.Fatalf("web: http3: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,28 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## v0.107.15: `POST` Requests Without Bodies
|
||||||
|
|
||||||
|
As an additional CSRF protection measure, AdGuard Home now ensures that requests
|
||||||
|
that change its state but have no body do not have a `Content-Type` header set
|
||||||
|
on them.
|
||||||
|
|
||||||
|
This concerns the following APIs:
|
||||||
|
|
||||||
|
* `POST /control/dhcp/reset_leases`;
|
||||||
|
* `POST /control/dhcp/reset`;
|
||||||
|
* `POST /control/parental/disable`;
|
||||||
|
* `POST /control/parental/enable`;
|
||||||
|
* `POST /control/querylog_clear`;
|
||||||
|
* `POST /control/safebrowsing/disable`;
|
||||||
|
* `POST /control/safebrowsing/enable`;
|
||||||
|
* `POST /control/safesearch/disable`;
|
||||||
|
* `POST /control/safesearch/enable`;
|
||||||
|
* `POST /control/stats_reset`;
|
||||||
|
* `POST /control/update`.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## v0.107.14: BREAKING API CHANGES
|
## v0.107.14: BREAKING API CHANGES
|
||||||
|
|
||||||
A Cross-Site Request Forgery (CSRF) vulnerability has been discovered. We have
|
A Cross-Site Request Forgery (CSRF) vulnerability has been discovered. We have
|
||||||
|
@ -13,6 +35,9 @@ implemented several measures to prevent such vulnerabilities in the future, but
|
||||||
some of these measures break backwards compatibility for the sake of better
|
some of these measures break backwards compatibility for the sake of better
|
||||||
protection.
|
protection.
|
||||||
|
|
||||||
|
All JSON APIs that expect a body now check if the request actually has
|
||||||
|
`Content-Type` set to `application/json`.
|
||||||
|
|
||||||
All new formats for the request and response bodies are documented in
|
All new formats for the request and response bodies are documented in
|
||||||
`openapi.yaml`.
|
`openapi.yaml`.
|
||||||
|
|
||||||
|
|
|
@ -601,11 +601,10 @@
|
||||||
'summary': 'Set user-defined filter rules'
|
'summary': 'Set user-defined filter rules'
|
||||||
'requestBody':
|
'requestBody':
|
||||||
'content':
|
'content':
|
||||||
'text/plain':
|
'application/json':
|
||||||
'schema':
|
'schema':
|
||||||
'type': 'string'
|
'$ref': '#/components/schemas/SetRulesRequest'
|
||||||
'example': '@@||yandex.ru^|'
|
'description': 'Custom filtering rules.'
|
||||||
'description': 'All filtering rules, one line per rule'
|
|
||||||
'responses':
|
'responses':
|
||||||
'200':
|
'200':
|
||||||
'description': 'OK.'
|
'description': 'OK.'
|
||||||
|
@ -1538,6 +1537,19 @@
|
||||||
'properties':
|
'properties':
|
||||||
'updated':
|
'updated':
|
||||||
'type': 'integer'
|
'type': 'integer'
|
||||||
|
'SetRulesRequest':
|
||||||
|
'description': 'Custom filtering rules setting request.'
|
||||||
|
'example':
|
||||||
|
'rules':
|
||||||
|
- '||example.com^'
|
||||||
|
- '# comment'
|
||||||
|
- '@@||www.example.com^'
|
||||||
|
'properties':
|
||||||
|
'rules':
|
||||||
|
'items':
|
||||||
|
'type': 'string'
|
||||||
|
'type': 'array'
|
||||||
|
'type': 'object'
|
||||||
'GetVersionRequest':
|
'GetVersionRequest':
|
||||||
'type': 'object'
|
'type': 'object'
|
||||||
'description': '/version.json request data'
|
'description': '/version.json request data'
|
||||||
|
|
Loading…
Reference in a new issue