diff --git a/.gitignore b/.gitignore index 46bf661d..4e4dc035 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ /snapcraft_login AdGuardHome* coverage.txt -leases.db leases.json node_modules/ diff --git a/CHANGELOG.md b/CHANGELOG.md index af03a8e4..8d0d4813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,8 @@ NOTE: Add new changes BELOW THIS COMMENT. ### Changed +- Stored DHCP leases moved from `leases.db` to `data/leases.json` and now have + human-readable format. - ARPA domain names containing a subnet within private networks now also considered private, behaving closer to [RFC 6761][rfc6761] ([#5567]). diff --git a/internal/dhcpd/db.go b/internal/dhcpd/db.go index 2ef6ac71..348c6c8f 100644 --- a/internal/dhcpd/db.go +++ b/internal/dhcpd/db.go @@ -23,7 +23,9 @@ const ( dataFilename = "leases.json" ) -// Deprecated: Use Lease. +// leaseJSON is the structure of stored lease. +// +// Deprecated: Use [Lease]. type leaseJSON struct { HWAddr []byte `json:"mac"` IP []byte `json:"ip"` @@ -39,9 +41,7 @@ func normalizeIP(ip net.IP) net.IP { return ip } -// Load lease table from DB -// -// TODO(s.chzhen): Decrease complexity. +// dbLoad loads stored leases. func (s *server) dbLoad() (err error) { data, err := os.ReadFile(s.conf.DBFilePath) if err != nil { @@ -114,7 +114,7 @@ func normalizeLeases(staticLeases, dynLeases []*Lease) []*Lease { return leases } -// Store lease table in DB +// dbStore stores DHCP leases. func (s *server) dbStore() (err error) { // Use an empty slice here as opposed to nil so that it doesn't write // "null" into the database file if leases are empty. @@ -131,6 +131,7 @@ func (s *server) dbStore() (err error) { return writeDB(s.conf.DBFilePath, leases) } +// writeDB writes leases to file at path. func writeDB(path string, leases []*Lease) (err error) { defer func() { err = errors.Annotate(err, "writing db: %w") }() @@ -156,34 +157,24 @@ func writeDB(path string, leases []*Lease) (err error) { return nil } -func checkDB(conf *ServerConfig) (err error) { - workDirPath := filepath.Join(conf.WorkDir, dbFilename) - _, err = os.Stat(workDirPath) +// migrateDB migrates stored leases if necessary. +func migrateDB(conf *ServerConfig) (err error) { + defer func() { err = errors.Annotate(err, "migrating db: %w") }() + oldLeasesPath := filepath.Join(conf.WorkDir, dbFilename) + dataDirPath := filepath.Join(conf.DataDir, dataFilename) + + file, err := os.Open(oldLeasesPath) if errors.Is(err, os.ErrNotExist) { // Nothing to migrate. return nil - } else if err == nil { - dataDirPath := filepath.Join(conf.DataDir, dataFilename) - - err = migrateDB(workDirPath, dataDirPath) - } - - return errors.Annotate(err, "checking db: %w") -} - -func migrateDB(workDirPath, dataDirPath string) (err error) { - defer func() { err = errors.Annotate(err, "migrating db: %w") }() - - var data []byte - data, err = os.ReadFile(workDirPath) - if err != nil { + } else if err != nil { // Don't wrap the error since it's informative enough as is. return err } ljs := []leaseJSON{} - err = json.Unmarshal(data, &ljs) + err = json.NewDecoder(file).Decode(&ljs) if err != nil { // Don't wrap the error since it's informative enough as is. return err @@ -213,6 +204,10 @@ func migrateDB(workDirPath, dataDirPath string) (err error) { } err = writeDB(dataDirPath, leases) + if err != nil { + // Don't wrap the error since it's informative enough as is. + return err + } - return os.Remove(workDirPath) + return os.Remove(oldLeasesPath) } diff --git a/internal/dhcpd/db_internal_test.go b/internal/dhcpd/db_internal_test.go index f0afbc08..c904b587 100644 --- a/internal/dhcpd/db_internal_test.go +++ b/internal/dhcpd/db_internal_test.go @@ -13,18 +13,18 @@ import ( "github.com/stretchr/testify/require" ) -const testLeasesDB = `[ +const testData = `[ {"mac":"ESIzRFVm","ip":"AQIDBA==","host":"test1","exp":1}, {"mac":"ZlVEMyIR","ip":"BAMCAQ==","host":"test2","exp":1231231231} ]` -func Test_upgradeDB(t *testing.T) { +func Test_migrateDB(t *testing.T) { dir := t.TempDir() - workDirPath := filepath.Join(dir, dbFilename) + oldLeasesPath := filepath.Join(dir, dbFilename) dataDirPath := filepath.Join(dir, dataFilename) - err := os.WriteFile(workDirPath, []byte(testLeasesDB), 0o644) + err := os.WriteFile(oldLeasesPath, []byte(testData), 0o644) require.NoError(t, err) wantLeases := []*Lease{{ @@ -41,7 +41,12 @@ func Test_upgradeDB(t *testing.T) { IsStatic: false, }} - err = migrateDB(workDirPath, dataDirPath) + conf := &ServerConfig{ + WorkDir: dir, + DataDir: dir, + } + + err = migrateDB(conf) require.NoError(t, err) var data []byte diff --git a/internal/dhcpd/dhcpd.go b/internal/dhcpd/dhcpd.go index 77147880..cb32988c 100644 --- a/internal/dhcpd/dhcpd.go +++ b/internal/dhcpd/dhcpd.go @@ -279,8 +279,8 @@ func Create(conf *ServerConfig) (s *server, err error) { return nil, fmt.Errorf("neither dhcpv4 nor dhcpv6 srv is configured") } - // Check if leases db needs to be migrated. - err = checkDB(conf) + // Migrate leases db if needed. + err = migrateDB(conf) if err != nil { return nil, err } diff --git a/internal/dhcpd/dhcpd_unix_test.go b/internal/dhcpd/dhcpd_unix_test.go index a2efabbd..4b8fda19 100644 --- a/internal/dhcpd/dhcpd_unix_test.go +++ b/internal/dhcpd/dhcpd_unix_test.go @@ -53,7 +53,6 @@ func TestDB(t *testing.T) { Hostname: "static-2.local", HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xBB}, IP: netip.MustParseAddr("192.168.10.101"), - IsStatic: true, }} srv4, ok := s.srv4.(*v4Server) diff --git a/internal/dhcpd/http_unix_test.go b/internal/dhcpd/http_unix_test.go index f1ffc70d..f66a2a2b 100644 --- a/internal/dhcpd/http_unix_test.go +++ b/internal/dhcpd/http_unix_test.go @@ -33,7 +33,6 @@ func TestServer_handleDHCPStatus(t *testing.T) { Conf4: *defaultV4ServerConf(), DataDir: t.TempDir(), WorkDir: t.TempDir(), - DBFilePath: dbFilename, ConfigModified: func() {}, }) require.NoError(t, err)