Pull request: upd-websvc

Merge in DNS/adguard-home from upd-websvc to master

Squashed commit of the following:

commit 30d6a2dc5083efd91479bcbe20f03c37baddbf94
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Tue Aug 9 18:55:42 2022 +0300

    all: upd openapi, websvc
This commit is contained in:
Ainar Garipov 2022-08-10 13:39:28 +03:00
parent 70f85fca21
commit 50565bed3b
7 changed files with 135 additions and 31 deletions

View File

@ -154,10 +154,13 @@ func GetValidNetInterfacesForWeb() (netIfaces []*NetInterface, err error) {
return netIfaces, nil return netIfaces, nil
} }
// GetInterfaceByIP returns the name of interface containing provided ip. // InterfaceByIP returns the name of the interface bound to ip.
// //
// TODO(e.burkov): See TODO on GetValidInterfacesForWeb. // TODO(a.garipov, e.burkov): This function is technically incorrect, since one
func GetInterfaceByIP(ip net.IP) string { // IP address can be shared by multiple interfaces in some configurations.
//
// TODO(e.burkov): See TODO on GetValidNetInterfacesForWeb.
func InterfaceByIP(ip net.IP) (ifaceName string) {
ifaces, err := GetValidNetInterfacesForWeb() ifaces, err := GetValidNetInterfacesForWeb()
if err != nil { if err != nil {
return "" return ""
@ -177,7 +180,7 @@ func GetInterfaceByIP(ip net.IP) string {
// GetSubnet returns pointer to net.IPNet for the specified interface or nil if // GetSubnet returns pointer to net.IPNet for the specified interface or nil if
// the search fails. // the search fails.
// //
// TODO(e.burkov): See TODO on GetValidInterfacesForWeb. // TODO(e.burkov): See TODO on GetValidNetInterfacesForWeb.
func GetSubnet(ifaceName string) *net.IPNet { func GetSubnet(ifaceName string) *net.IPNet {
netIfaces, err := GetValidNetInterfacesForWeb() netIfaces, err := GetValidNetInterfacesForWeb()
if err != nil { if err != nil {

View File

@ -132,7 +132,7 @@ func TestGatewayIP(t *testing.T) {
} }
} }
func TestGetInterfaceByIP(t *testing.T) { func TestInterfaceByIP(t *testing.T) {
ifaces, err := GetValidNetInterfacesForWeb() ifaces, err := GetValidNetInterfacesForWeb()
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, ifaces) require.NotEmpty(t, ifaces)
@ -142,7 +142,7 @@ func TestGetInterfaceByIP(t *testing.T) {
require.NotEmpty(t, iface.Addresses) require.NotEmpty(t, iface.Addresses)
for _, ip := range iface.Addresses { for _, ip := range iface.Addresses {
ifaceName := GetInterfaceByIP(ip) ifaceName := InterfaceByIP(ip)
require.Equal(t, iface.Name, ifaceName) require.Equal(t, iface.Name, ifaceName)
} }
}) })

View File

@ -216,7 +216,7 @@ func (web *Web) handleInstallCheckConfig(w http.ResponseWriter, r *http.Request)
func handleStaticIP(ip net.IP, set bool) staticIPJSON { func handleStaticIP(ip net.IP, set bool) staticIPJSON {
resp := staticIPJSON{} resp := staticIPJSON{}
interfaceName := aghnet.GetInterfaceByIP(ip) interfaceName := aghnet.InterfaceByIP(ip)
resp.Static = "no" resp.Static = "no"
if len(interfaceName) == 0 { if len(interfaceName) == 0 {

View File

@ -8,12 +8,11 @@ import (
"context" "context"
"io/fs" "io/fs"
"math/rand" "math/rand"
"net" "net/netip"
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
) )
// Main is the entry point of application. // Main is the entry point of application.
@ -32,10 +31,7 @@ func Main(clientBuildFS fs.FS) {
// TODO(a.garipov): Make configurable. // TODO(a.garipov): Make configurable.
web := websvc.New(&websvc.Config{ web := websvc.New(&websvc.Config{
Addresses: []*netutil.IPPort{{ Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:3001")},
IP: net.IP{127, 0, 0, 1},
Port: 3001,
}},
Start: start, Start: start,
Timeout: 60 * time.Second, Timeout: 60 * time.Second,
}) })

View File

@ -10,13 +10,13 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"net/netip"
"sync" "sync"
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/v1/agh" "github.com/AdguardTeam/AdGuardHome/internal/v1/agh"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
httptreemux "github.com/dimfeld/httptreemux/v5" httptreemux "github.com/dimfeld/httptreemux/v5"
) )
@ -27,11 +27,11 @@ type Config struct {
TLS *tls.Config TLS *tls.Config
// Addresses are the addresses on which to serve the plain HTTP API. // Addresses are the addresses on which to serve the plain HTTP API.
Addresses []*netutil.IPPort Addresses []netip.AddrPort
// SecureAddresses are the addresses on which to serve the HTTPS API. If // SecureAddresses are the addresses on which to serve the HTTPS API. If
// SecureAddresses is not empty, TLS must not be nil. // SecureAddresses is not empty, TLS must not be nil.
SecureAddresses []*netutil.IPPort SecureAddresses []netip.AddrPort
// Start is the time of start of AdGuard Home. // Start is the time of start of AdGuard Home.
Start time.Time Start time.Time

View File

@ -3,14 +3,13 @@ package websvc_test
import ( import (
"context" "context"
"io" "io"
"net"
"net/http" "net/http"
"net/netip"
"net/url" "net/url"
"testing" "testing"
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/v1/websvc" "github.com/AdguardTeam/AdGuardHome/internal/v1/websvc"
"github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -31,10 +30,7 @@ func newTestServer(t testing.TB) (svc *websvc.Service, addr string) {
c := &websvc.Config{ c := &websvc.Config{
TLS: nil, TLS: nil,
Addresses: []*netutil.IPPort{{ Addresses: []netip.AddrPort{netip.MustParseAddrPort("127.0.0.1:0")},
IP: net.IP{127, 0, 0, 1},
Port: 0,
}},
SecureAddresses: nil, SecureAddresses: nil,
Timeout: testTimeout, Timeout: testTimeout,
Start: testStart, Start: testStart,

View File

@ -144,6 +144,13 @@
'/health-check': '/health-check':
'get': 'get':
'operationId': 'HealthCheck' 'operationId': 'HealthCheck'
'responses':
'200':
'description': >
An OK response.
'content':
'text/plain':
'example': 'OK'
'servers': 'servers':
- 'url': '/' - 'url': '/'
'summary': 'Check if the server is up.' 'summary': 'Check if the server is up.'
@ -874,6 +881,26 @@
'tags': 'tags':
- 'settings' - 'settings'
'/settings/http':
'patch':
'operationId': 'PatchV1SettingsHttp'
'requestBody':
'$ref': '#/components/requestBodies/PatchV1SettingsHttpReq'
'responses':
'200':
'$ref': '#/components/responses/PatchV1SettingsHttpResp'
'400':
'$ref': '#/components/responses/BadRequestResp'
'401':
'$ref': '#/components/responses/UnauthorizedResp'
'422':
'$ref': '#/components/responses/UnprocessableEntityResp'
'500':
'$ref': '#/components/responses/InternalServerErrorResp'
'summary': 'Update web interface settings.'
'tags':
- 'settings'
'/settings/log': '/settings/log':
'patch': 'patch':
'operationId': 'PatchV1SettingsLog' 'operationId': 'PatchV1SettingsLog'
@ -1209,6 +1236,13 @@
'$ref': '#/components/schemas/PatchV1SettingsDnsReq' '$ref': '#/components/schemas/PatchV1SettingsDnsReq'
'required': true 'required': true
'PatchV1SettingsHttpReq':
'content':
'application/json':
'schema':
'$ref': '#/components/schemas/PatchV1SettingsHttpReq'
'required': true
'PatchV1SettingsLogReq': 'PatchV1SettingsLogReq':
'content': 'content':
'application/json': 'application/json':
@ -1604,6 +1638,14 @@
'description': > 'description': >
A successful response to a `PATCH /api/v1/settings/dns` request. A successful response to a `PATCH /api/v1/settings/dns` request.
'PatchV1SettingsHttpResp':
'content':
'application/json':
'schema':
'$ref': '#/components/schemas/PatchV1SettingsHttpResp'
'description': >
A successful response to a `PATCH /api/v1/settings/http` request.
'PatchV1SettingsLogResp': 'PatchV1SettingsLogResp':
'content': 'content':
'application/json': 'application/json':
@ -2229,6 +2271,9 @@
- 'description': > - 'description': >
DNS server settings. DNS server settings.
'example': 'example':
'addresses':
- '127.0.0.1:53'
- '192.168.1.1:53'
'blocking_mode': 'default' 'blocking_mode': 'default'
'bootstrap_servers': 'bootstrap_servers':
- '9.9.9.10' - '9.9.9.10'
@ -2244,7 +2289,9 @@
'upstream_servers': 'upstream_servers':
- '1.1.1.1' - '1.1.1.1'
- '8.8.8.8' - '8.8.8.8'
'upstream_timeout': '1s'
'required': 'required':
- 'addresses'
- 'blocking_mode' - 'blocking_mode'
- 'bootstrap_servers' - 'bootstrap_servers'
- 'cache_size' - 'cache_size'
@ -2256,6 +2303,7 @@
- 'rate_limit' - 'rate_limit'
- 'upstream_mode' - 'upstream_mode'
- 'upstream_servers' - 'upstream_servers'
- 'upstream_timeout'
'DnsSettingsPatch': 'DnsSettingsPatch':
'description': > 'description': >
@ -2265,6 +2313,13 @@
'upstream_servers': 'upstream_servers':
- '1.1.1.1' - '1.1.1.1'
'properties': 'properties':
'addresses':
'description': >
Addresses on which to serve plain DNS, in ip:port format. Empty
array disables plain DNS.
'items':
'type': 'string'
'type': 'array'
'blocking_ipv4': 'blocking_ipv4':
'description': > 'description': >
IPv4 address to respond with when `blocking_mode` is `custom_ip`. IPv4 address to respond with when `blocking_mode` is `custom_ip`.
@ -2340,6 +2395,10 @@
'items': 'items':
'$ref': '#/components/schemas/UpstreamServerAddr' '$ref': '#/components/schemas/UpstreamServerAddr'
'type': 'array' 'type': 'array'
'upstream_timeout':
'description': >
Upstream request timeout, as a human readable duration.
'type': 'string'
'type': 'object' 'type': 'object'
'DnsType': 'DnsType':
@ -3038,6 +3097,8 @@
'$ref': '#/components/schemas/DhcpSettings' '$ref': '#/components/schemas/DhcpSettings'
'dns': 'dns':
'$ref': '#/components/schemas/DnsSettings' '$ref': '#/components/schemas/DnsSettings'
'http':
'$ref': '#/components/schemas/HttpSettings'
'log': 'log':
'$ref': '#/components/schemas/LogSettings' '$ref': '#/components/schemas/LogSettings'
'protection': 'protection':
@ -3049,6 +3110,7 @@
'required': 'required':
- 'dhcp' - 'dhcp'
- 'dns' - 'dns'
- 'http'
- 'log' - 'log'
- 'protection' - 'protection'
- 'stats' - 'stats'
@ -3432,6 +3494,53 @@
- 'version' - 'version'
'type': 'object' 'type': 'object'
'HttpSettings':
'allOf':
- '$ref': '#/components/schemas/HttpSettingsPatch'
- 'description': >
HTTP interface server settings.
**TODO(a.garipov): Finish, split from TLS settings.**
'example':
'addresses':
- '127.0.0.1:80'
- '192.168.1.1:80'
'secure_addresses':
- '127.0.0.1:443'
- '192.168.1.1:443'
'force_https': true
'required':
- 'addresses'
- 'secure_addresses'
- 'force_https'
'HttpSettingsPatch':
'description': >
HTTP server settings update object.
'example':
'force_https': false
'properties':
'addresses':
'description': >
Addresses on which to serve the plain-HTTP web interface and API, in
ip:port format. Empty array disables the web interface over plain
HTTP.
'items':
'type': 'string'
'type': 'array'
'force_https':
'description': >
If `true`, enabled the HTTP-to-HTTPS redirect.
'type': 'boolean'
'secure_addresses':
'description': >
Addresses on which to serve the HTTPS web interface and API, in
ip:port format. Empty array disables the web interface over HTTPS.
'items':
'type': 'string'
'type': 'array'
'type': 'object'
'InternalServerErrorResp': 'InternalServerErrorResp':
'example': 'example':
'code': 'RNT000' 'code': 'RNT000'
@ -3725,6 +3834,12 @@
'PatchV1SettingsDnsResp': 'PatchV1SettingsDnsResp':
'$ref': '#/components/schemas/DnsSettings' '$ref': '#/components/schemas/DnsSettings'
'PatchV1SettingsHttpReq':
'$ref': '#/components/schemas/HttpSettingsPatch'
'PatchV1SettingsHttpResp':
'$ref': '#/components/schemas/HttpSettings'
'PatchV1SettingsLogReq': 'PatchV1SettingsLogReq':
'$ref': '#/components/schemas/LogSettingsPatch' '$ref': '#/components/schemas/LogSettingsPatch'
@ -4750,7 +4865,6 @@
'example': 'example':
'certificate_path': '/etc/ssl/example.com.cert' 'certificate_path': '/etc/ssl/example.com.cert'
'enabled': true 'enabled': true
'force_https': true
'port_dns_over_quic': 784 'port_dns_over_quic': 784
'port_dns_over_tls': 853 'port_dns_over_tls': 853
'port_https': 443 'port_https': 443
@ -4758,7 +4872,6 @@
'server_name': 'dns.example.com' 'server_name': 'dns.example.com'
'required': 'required':
- 'enabled' - 'enabled'
- 'force_https'
- 'port_dns_over_quic' - 'port_dns_over_quic'
- 'port_dns_over_tls' - 'port_dns_over_tls'
- 'port_https' - 'port_https'
@ -4793,10 +4906,6 @@
over HTTPS, and the DNS server will listen requests over over HTTPS, and the DNS server will listen requests over
DNS-over-TLS and other protocols. DNS-over-TLS and other protocols.
'type': 'boolean' 'type': 'boolean'
'force_https':
'description': >
If `true`, enabled the HTTP-to-HTTPS redirect.
'type': 'boolean'
'port_dns_over_quic': 'port_dns_over_quic':
'default': 784 'default': 784
'description': > 'description': >