mirror of
https://git.vectorsigma.ru/public/AdGuardHome.git
synced 2026-08-03 21:49:40 +00:00
Merge in DNS/adguard-home from AGDNS-3061-config-modifier to master Squashed commit of the following: commit a0068547bd0209d12e8dbf98ddd5e4ed2545cdd0 Merge: 97b798af6451255675Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Tue Aug 5 17:39:31 2025 +0300 Merge branch 'master' into AGDNS-3061-config-modifier commit 97b798af6a50ee27ee5ed2bcf1c4c3670f5afc5d Merge: 96d21efc9b8043e4f0Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Wed Jul 30 20:27:41 2025 +0300 Merge branch 'master' into AGDNS-3061-config-modifier commit 96d21efc984073adef5026de8a03b5bf94542648 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Wed Jul 30 20:18:43 2025 +0300 all: imp code commit 67c5608b4be3bd712a0ab5980f25ecea1ed21d65 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Tue Jul 29 20:31:19 2025 +0300 all: imp code commit 52f45a9f70f57d8e7f7fc0e9e8291ff0dde74343 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Mon Jul 28 20:32:13 2025 +0300 all: use config modifier commit d389ffd286460d8ff1964bd2ee8dabdafb832b9b Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Fri Jul 25 14:20:31 2025 +0300 bamboo-specs: fix ci commit 3f303ac9131a07e4af5783696b237436fd93d65c Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Fri Jul 25 14:18:42 2025 +0300 home: config modifier
321 lines
7.1 KiB
Go
321 lines
7.1 KiB
Go
//go:build darwin || freebsd || linux || openbsd
|
|
|
|
package dhcpd
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/netip"
|
|
"testing"
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/agh"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// defaultResponse is a helper that returns the response with default
|
|
// configuration.
|
|
func defaultResponse() *dhcpStatusResponse {
|
|
conf4 := defaultV4ServerConf()
|
|
conf4.LeaseDuration = 86400
|
|
|
|
resp := &dhcpStatusResponse{
|
|
V4: *conf4,
|
|
V6: V6ServerConf{},
|
|
Leases: []*leaseDynamic{},
|
|
StaticLeases: []*leaseStatic{},
|
|
Enabled: true,
|
|
}
|
|
|
|
return resp
|
|
}
|
|
|
|
// handleLease is the helper function that calls handler with provided static
|
|
// lease as body and returns modified response recorder.
|
|
func handleLease(t *testing.T, lease *leaseStatic, handler http.HandlerFunc) (w *httptest.ResponseRecorder) {
|
|
t.Helper()
|
|
|
|
w = httptest.NewRecorder()
|
|
|
|
b := &bytes.Buffer{}
|
|
err := json.NewEncoder(b).Encode(lease)
|
|
require.NoError(t, err)
|
|
|
|
var r *http.Request
|
|
r, err = http.NewRequest(http.MethodPost, "", b)
|
|
require.NoError(t, err)
|
|
|
|
handler(w, r)
|
|
|
|
return w
|
|
}
|
|
|
|
// checkStatus is a helper that asserts the response of
|
|
// [*server.handleDHCPStatus].
|
|
func checkStatus(t *testing.T, s *server, want *dhcpStatusResponse) {
|
|
w := httptest.NewRecorder()
|
|
|
|
b := &bytes.Buffer{}
|
|
err := json.NewEncoder(b).Encode(&want)
|
|
require.NoError(t, err)
|
|
|
|
r, err := http.NewRequest(http.MethodPost, "", b)
|
|
require.NoError(t, err)
|
|
|
|
s.handleDHCPStatus(w, r)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
assert.JSONEq(t, b.String(), w.Body.String())
|
|
}
|
|
|
|
func TestServer_handleDHCPStatus(t *testing.T) {
|
|
const (
|
|
staticName = "static-client"
|
|
staticMAC = "aa:aa:aa:aa:aa:aa"
|
|
)
|
|
|
|
staticIP := netip.MustParseAddr("192.168.10.10")
|
|
|
|
staticLease := &leaseStatic{
|
|
HWAddr: staticMAC,
|
|
IP: staticIP,
|
|
Hostname: staticName,
|
|
}
|
|
|
|
s, err := Create(&ServerConfig{
|
|
Enabled: true,
|
|
Conf4: *defaultV4ServerConf(),
|
|
DataDir: t.TempDir(),
|
|
ConfModifier: agh.EmptyConfigModifier{},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
ok := t.Run("status", func(t *testing.T) {
|
|
resp := defaultResponse()
|
|
|
|
checkStatus(t, s, resp)
|
|
})
|
|
require.True(t, ok)
|
|
|
|
ok = t.Run("add_static_lease", func(t *testing.T) {
|
|
w := handleLease(t, staticLease, s.handleDHCPAddStaticLease)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
resp := defaultResponse()
|
|
resp.StaticLeases = []*leaseStatic{staticLease}
|
|
|
|
checkStatus(t, s, resp)
|
|
})
|
|
require.True(t, ok)
|
|
|
|
ok = t.Run("add_invalid_lease", func(t *testing.T) {
|
|
w := handleLease(t, staticLease, s.handleDHCPAddStaticLease)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
})
|
|
require.True(t, ok)
|
|
|
|
ok = t.Run("remove_static_lease", func(t *testing.T) {
|
|
w := handleLease(t, staticLease, s.handleDHCPRemoveStaticLease)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
resp := defaultResponse()
|
|
|
|
checkStatus(t, s, resp)
|
|
})
|
|
require.True(t, ok)
|
|
|
|
ok = t.Run("set_config", func(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
|
|
resp := defaultResponse()
|
|
resp.Enabled = false
|
|
|
|
b := &bytes.Buffer{}
|
|
err = json.NewEncoder(b).Encode(&resp)
|
|
require.NoError(t, err)
|
|
|
|
var r *http.Request
|
|
r, err = http.NewRequest(http.MethodPost, "", b)
|
|
require.NoError(t, err)
|
|
|
|
s.handleDHCPSetConfig(w, r)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
checkStatus(t, s, resp)
|
|
})
|
|
require.True(t, ok)
|
|
}
|
|
|
|
func TestServer_HandleUpdateStaticLease(t *testing.T) {
|
|
const (
|
|
leaseV4Name = "static-client-v4"
|
|
leaseV4MAC = "44:44:44:44:44:44"
|
|
|
|
leaseV6Name = "static-client-v6"
|
|
leaseV6MAC = "66:66:66:66:66:66"
|
|
)
|
|
|
|
leaseV4IP := netip.MustParseAddr("192.168.10.10")
|
|
leaseV6IP := netip.MustParseAddr("2001::6")
|
|
|
|
const (
|
|
leaseV4Pos = iota
|
|
leaseV6Pos
|
|
)
|
|
|
|
leases := []*leaseStatic{
|
|
leaseV4Pos: {
|
|
HWAddr: leaseV4MAC,
|
|
IP: leaseV4IP,
|
|
Hostname: leaseV4Name,
|
|
},
|
|
leaseV6Pos: {
|
|
HWAddr: leaseV6MAC,
|
|
IP: leaseV6IP,
|
|
Hostname: leaseV6Name,
|
|
},
|
|
}
|
|
|
|
s, err := Create(&ServerConfig{
|
|
Enabled: true,
|
|
Conf4: *defaultV4ServerConf(),
|
|
Conf6: V6ServerConf{},
|
|
DataDir: t.TempDir(),
|
|
ConfModifier: agh.EmptyConfigModifier{},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, l := range leases {
|
|
w := handleLease(t, l, s.handleDHCPAddStaticLease)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
pos int
|
|
lease *leaseStatic
|
|
}{{
|
|
name: "update_v4_name",
|
|
pos: leaseV4Pos,
|
|
lease: &leaseStatic{
|
|
HWAddr: leaseV4MAC,
|
|
IP: leaseV4IP,
|
|
Hostname: "updated-client-v4",
|
|
},
|
|
}, {
|
|
name: "update_v4_ip",
|
|
pos: leaseV4Pos,
|
|
lease: &leaseStatic{
|
|
HWAddr: leaseV4MAC,
|
|
IP: netip.MustParseAddr("192.168.10.200"),
|
|
Hostname: "updated-client-v4",
|
|
},
|
|
}, {
|
|
name: "update_v6_name",
|
|
pos: leaseV6Pos,
|
|
lease: &leaseStatic{
|
|
HWAddr: leaseV6MAC,
|
|
IP: leaseV6IP,
|
|
Hostname: "updated-client-v6",
|
|
},
|
|
}, {
|
|
name: "update_v6_ip",
|
|
pos: leaseV6Pos,
|
|
lease: &leaseStatic{
|
|
HWAddr: leaseV6MAC,
|
|
IP: netip.MustParseAddr("2001::666"),
|
|
Hostname: "updated-client-v6",
|
|
},
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
w := handleLease(t, tc.lease, s.handleDHCPUpdateStaticLease)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
resp := defaultResponse()
|
|
leases[tc.pos] = tc.lease
|
|
resp.StaticLeases = leases
|
|
|
|
checkStatus(t, s, resp)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestServer_HandleUpdateStaticLease_validation(t *testing.T) {
|
|
const (
|
|
leaseV4Name = "static-client-v4"
|
|
leaseV4MAC = "44:44:44:44:44:44"
|
|
|
|
anotherV4Name = "another-client-v4"
|
|
anotherV4MAC = "55:55:55:55:55:55"
|
|
)
|
|
|
|
leaseV4IP := netip.MustParseAddr("192.168.10.10")
|
|
anotherV4IP := netip.MustParseAddr("192.168.10.20")
|
|
|
|
leases := []*leaseStatic{{
|
|
HWAddr: leaseV4MAC,
|
|
IP: leaseV4IP,
|
|
Hostname: leaseV4Name,
|
|
}, {
|
|
HWAddr: anotherV4MAC,
|
|
IP: anotherV4IP,
|
|
Hostname: anotherV4Name,
|
|
}}
|
|
|
|
s, err := Create(&ServerConfig{
|
|
Enabled: true,
|
|
Conf4: *defaultV4ServerConf(),
|
|
Conf6: V6ServerConf{},
|
|
DataDir: t.TempDir(),
|
|
ConfModifier: agh.EmptyConfigModifier{},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, l := range leases {
|
|
w := handleLease(t, l, s.handleDHCPAddStaticLease)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
testCases := []struct {
|
|
lease *leaseStatic
|
|
name string
|
|
want string
|
|
}{{
|
|
name: "v4_unknown_mac",
|
|
lease: &leaseStatic{
|
|
HWAddr: "aa:aa:aa:aa:aa:aa",
|
|
IP: leaseV4IP,
|
|
Hostname: leaseV4Name,
|
|
},
|
|
want: "dhcpv4: updating static lease: can't find lease aa:aa:aa:aa:aa:aa\n",
|
|
}, {
|
|
name: "update_v4_same_ip",
|
|
lease: &leaseStatic{
|
|
HWAddr: leaseV4MAC,
|
|
IP: anotherV4IP,
|
|
Hostname: leaseV4Name,
|
|
},
|
|
want: "dhcpv4: updating static lease: ip address is not unique\n",
|
|
}, {
|
|
name: "update_v4_same_name",
|
|
lease: &leaseStatic{
|
|
HWAddr: leaseV4MAC,
|
|
IP: leaseV4IP,
|
|
Hostname: anotherV4Name,
|
|
},
|
|
want: "dhcpv4: updating static lease: hostname is not unique\n",
|
|
}}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
w := handleLease(t, tc.lease, s.handleDHCPUpdateStaticLease)
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
assert.Equal(t, tc.want, w.Body.String())
|
|
})
|
|
}
|
|
}
|