Pull request 2371: AGDNS-2714-tls-manager

Merge in DNS/adguard-home from AGDNS-2714-tls-manager to master

Squashed commit of the following:

commit 5c7cd1fa6d8a9bc1fd0f891818589b48bee641dc
Merge: 381f7666b 810ae9483
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 26 14:13:49 2025 +0300

    Merge branch 'master' into AGDNS-2714-tls-manager

commit 381f7666b063d225b114976a280e65df736495fe
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 25 19:53:12 2025 +0300

    home: imp code

commit 20be72abd449fcc76417381edf7d375248a11e9e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 25 19:19:51 2025 +0300

    home: imp code

commit b5a06e6a15b0f8511819267133a551a56e051499
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Mar 24 21:45:41 2025 +0300

    home: imp code

commit a6a5ba727ebbc59d6de4d3762ac196d2cf194875
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Mar 20 21:06:34 2025 +0300

    home: imp docs

commit 71d379bafc3f42377ce72add2cab3a56a796941d
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Thu Mar 20 20:47:15 2025 +0300

    all: upd chlog

commit be69a5b85d4cd4295a9b68e1c2c2205179a3e7f2
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 19 20:14:20 2025 +0300

    home: imp docs

commit 85b28db73b59b90365ff23fc5fc90dc1a10cc152
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 19 20:07:59 2025 +0300

    home: imp code

commit c11e4c9e500f7ead96a84575dac08e198569c14d
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Mar 19 19:11:59 2025 +0300

    home: imp code

commit 60eff2c66369ca8705a6bb859b5a65d3e6d0df5e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 18 21:27:49 2025 +0300

    home: imp code

commit fa9d57b2834fe3df85630d95b9eb022f1db372b1
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 18 21:14:56 2025 +0300

    home: imp docs

commit 3f561b64750ab57ef83793522a0b313225245e1e
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 18 20:59:59 2025 +0300

    home: imp code

commit 927296c49f861d102dad8d24e8b67e6204a6c17a
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 18 18:19:22 2025 +0300

    home: imp naming

commit e35f742e42a7304993a924928b51f2452634e258
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 18 17:53:17 2025 +0300

    home: tls manager web api

commit 85a4de7931fea68464fe36c1fb27686eb5b50066
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Tue Mar 18 15:06:34 2025 +0300

    home: tls manager config

commit 515b26d6bd6d837d3db937354f74d895b5793206
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Mon Mar 17 22:15:25 2025 +0300

    home: tls manager
This commit is contained in:
Stanislav Chzhen
2025-03-26 14:26:57 +03:00
parent 810ae94832
commit 8b4768aadd
8 changed files with 420 additions and 208 deletions

View File

@@ -30,6 +30,7 @@ import (
"github.com/stretchr/testify/require"
)
// TODO(s.chzhen): Consider moving to testdata.
var testCertChainData = []byte(`-----BEGIN CERTIFICATE-----
MIICKzCCAZSgAwIBAgIJAMT9kPVJdM7LMA0GCSqGSIb3DQEBCwUAMC0xFDASBgNV
BAoMC0FkR3VhcmQgTHRkMRUwEwYDVQQDDAxBZEd1YXJkIEhvbWUwHhcNMTkwMjI3
@@ -66,7 +67,11 @@ func TestValidateCertificates(t *testing.T) {
ctx := testutil.ContextWithTimeout(t, testTimeout)
logger := slogutil.NewDiscardLogger()
m, err := newTLSManager(ctx, logger, tlsConfigSettings{}, false)
m, err := newTLSManager(ctx, &tlsManagerConfig{
logger: logger,
configModified: func() {},
servePlainDNS: false,
})
require.NoError(t, err)
t.Run("bad_certificate", func(t *testing.T) {
@@ -112,7 +117,6 @@ func TestValidateCertificates(t *testing.T) {
// - [homeContext.clients.storage]
// - [homeContext.dnsServer]
// - [homeContext.mux]
// - [homeContext.web]
//
// TODO(s.chzhen): Remove this once the TLS manager no longer accesses global
// variables. Make tests that use this helper concurrent.
@@ -123,14 +127,12 @@ func storeGlobals(tb testing.TB) {
storage := globalContext.clients.storage
dnsServer := globalContext.dnsServer
mux := globalContext.mux
web := globalContext.web
tb.Cleanup(func() {
config = prevConfig
globalContext.clients.storage = storage
globalContext.dnsServer = dnsServer
globalContext.mux = mux
globalContext.web = web
})
}
@@ -221,9 +223,6 @@ func TestTLSManager_Reload(t *testing.T) {
globalContext.mux = http.NewServeMux()
globalContext.web, err = initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
const (
snBefore int64 = 1
snAfter int64 = 2
@@ -236,15 +235,25 @@ func TestTLSManager_Reload(t *testing.T) {
certDER, key := newCertAndKey(t, snBefore)
writeCertAndKey(t, certDER, certPath, key, keyPath)
m, err := newTLSManager(ctx, logger, tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificatePath: certPath,
PrivateKeyPath: keyPath,
m, err := newTLSManager(ctx, &tlsManagerConfig{
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificatePath: certPath,
PrivateKeyPath: keyPath,
},
},
}, false)
servePlainDNS: false,
})
require.NoError(t, err)
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
m.setWebAPI(web)
conf := &tlsConfigSettings{}
m.WriteDiskConfig(conf)
assertCertSerialNumber(t, conf, snBefore)
@@ -265,13 +274,18 @@ func TestTLSManager_HandleTLSStatus(t *testing.T) {
err error
)
m, err := newTLSManager(ctx, logger, tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
m, err := newTLSManager(ctx, &tlsManagerConfig{
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
},
},
}, false)
servePlainDNS: false,
})
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -291,26 +305,42 @@ func TestTLSManager_HandleTLSStatus(t *testing.T) {
func TestValidateTLSSettings(t *testing.T) {
storeGlobals(t)
globalContext.mux = http.NewServeMux()
var (
logger = slogutil.NewDiscardLogger()
ctx = testutil.ContextWithTimeout(t, testTimeout)
err error
)
ln, err := net.Listen("tcp", ":0")
m, err := newTLSManager(ctx, &tlsManagerConfig{
logger: logger,
configModified: func() {},
servePlainDNS: false,
})
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, ln.Close)
addr := testutil.RequireTypeAssert[*net.TCPAddr](t, ln.Addr())
busyPort := addr.Port
globalContext.mux = http.NewServeMux()
globalContext.web, err = initWeb(ctx, options{}, nil, nil, logger, nil, false)
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
m.setWebAPI(web)
tcpLn, err := net.Listen("tcp", ":0")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, tcpLn.Close)
tcpAddr := testutil.RequireTypeAssert[*net.TCPAddr](t, tcpLn.Addr())
busyTCPPort := tcpAddr.Port
udpLn, err := net.ListenPacket("udp", ":0")
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, udpLn.Close)
udpAddr := testutil.RequireTypeAssert[*net.UDPAddr](t, udpLn.LocalAddr())
busyUDPPort := udpAddr.Port
testCases := []struct {
setts tlsConfigSettingsExt
name string
@@ -329,11 +359,29 @@ func TestValidateTLSSettings(t *testing.T) {
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortHTTPS: uint16(busyPort),
PortHTTPS: uint16(busyTCPPort),
},
},
name: "busy_port",
wantErr: fmt.Sprintf("port %d is not available, cannot enable HTTPS on it", busyPort),
name: "busy_https_port",
wantErr: fmt.Sprintf("port %d for HTTPS is not available", busyTCPPort),
}, {
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortDNSOverTLS: uint16(busyTCPPort),
},
},
name: "busy_dot_port",
wantErr: fmt.Sprintf("port %d for DNS-over-TLS is not available", busyTCPPort),
}, {
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
PortDNSOverQUIC: uint16(busyUDPPort),
},
},
name: "busy_doq_port",
wantErr: fmt.Sprintf("port %d for DNS-over-QUIC is not available", busyUDPPort),
}, {
setts: tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
@@ -348,7 +396,7 @@ func TestValidateTLSSettings(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err = validateTLSSettings(tc.setts)
err = m.validateTLSSettings(tc.setts)
testutil.AssertErrorMsg(t, tc.wantErr, err)
})
}
@@ -357,26 +405,33 @@ func TestValidateTLSSettings(t *testing.T) {
func TestTLSManager_HandleTLSValidate(t *testing.T) {
storeGlobals(t)
globalContext.mux = http.NewServeMux()
var (
logger = slogutil.NewDiscardLogger()
ctx = testutil.ContextWithTimeout(t, testTimeout)
err error
)
globalContext.mux = http.NewServeMux()
globalContext.web, err = initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
m, err := newTLSManager(ctx, logger, tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
m, err := newTLSManager(ctx, &tlsManagerConfig{
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificateChain: string(testCertChainData),
PrivateKey: string(testPrivateKeyData),
},
},
}, false)
servePlainDNS: false,
})
require.NoError(t, err)
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
m.setWebAPI(web)
setts := &tlsConfigSettingsExt{
tlsConfigSettings: tlsConfigSettings{
Enabled: true,
@@ -438,9 +493,6 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
globalContext.mux = http.NewServeMux()
globalContext.web, err = initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
config.DNS.BindHosts = []netip.Addr{netip.MustParseAddr("127.0.0.1")}
config.DNS.Port = 0
@@ -455,15 +507,25 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
writeCertAndKey(t, certDER, certPath, key, keyPath)
// Initialize the TLS manager and assert its configuration.
m, err := newTLSManager(ctx, logger, tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificatePath: certPath,
PrivateKeyPath: keyPath,
m, err := newTLSManager(ctx, &tlsManagerConfig{
logger: logger,
configModified: func() {},
tlsSettings: tlsConfigSettings{
Enabled: true,
TLSConfig: dnsforward.TLSConfig{
CertificatePath: certPath,
PrivateKeyPath: keyPath,
},
},
}, true)
servePlainDNS: true,
})
require.NoError(t, err)
web, err := initWeb(ctx, options{}, nil, nil, logger, nil, false)
require.NoError(t, err)
m.setWebAPI(web)
conf := &tlsConfigSettings{}
m.WriteDiskConfig(conf)
assertCertSerialNumber(t, conf, wantSerialNumber)
@@ -509,10 +571,10 @@ func TestTLSManager_HandleTLSConfigure(t *testing.T) {
//
// TODO(s.chzhen): Remove when [httpsServer.cond] is removed.
assert.Eventually(t, func() bool {
globalContext.web.httpsServer.condLock.Lock()
defer globalContext.web.httpsServer.condLock.Unlock()
web.httpsServer.condLock.Lock()
defer web.httpsServer.condLock.Unlock()
cert = globalContext.web.httpsServer.cert
cert = web.httpsServer.cert
if cert.Leaf == nil {
return false
}