diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 61ed05e2..dbe2bad3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,7 +1,7 @@
'name': 'build'
'env':
- 'GO_VERSION': '1.18'
+ 'GO_VERSION': '1.18.6'
'NODE_VERSION': '14'
'on':
@@ -31,7 +31,7 @@
'with':
'fetch-depth': 0
- 'name': 'Set up Go'
- 'uses': 'actions/setup-go@v2'
+ 'uses': 'actions/setup-go@v3'
'with':
'go-version': '${{ env.GO_VERSION }}'
- 'name': 'Set up Node'
@@ -72,7 +72,7 @@
'with':
'fetch-depth': 0
- 'name': 'Set up Go'
- 'uses': 'actions/setup-go@v2'
+ 'uses': 'actions/setup-go@v3'
'with':
'go-version': '${{ env.GO_VERSION }}'
- 'name': 'Set up Node'
@@ -112,7 +112,9 @@
# Use always() to signal to the runner that this job must run even if the
# previous ones failed.
'if':
- ${{ always() &&
+ ${{
+ always() &&
+ github.repository_owner == 'AdguardTeam' &&
(
github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name == github.repository
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 1842c2dc..64719a3e 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -1,7 +1,7 @@
'name': 'lint'
'env':
- 'GO_VERSION': '1.18'
+ 'GO_VERSION': '1.18.6'
'on':
'push':
@@ -17,7 +17,7 @@
'steps':
- 'uses': 'actions/checkout@v2'
- 'name': 'Set up Go'
- 'uses': 'actions/setup-go@v2'
+ 'uses': 'actions/setup-go@v3'
'with':
'go-version': '${{ env.GO_VERSION }}'
- 'name': 'run-lint'
@@ -43,7 +43,9 @@
# Use always() to signal to the runner that this job must run even if the
# previous ones failed.
'if':
- ${{ always() &&
+ ${{
+ always() &&
+ github.repository_owner == 'AdguardTeam' &&
(
github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name == github.repository
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67835936..c19eac80 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,12 +26,39 @@ and this project adheres to
+
+
+
+## [v0.107.13] - 2022-09-14
See also the [v0.107.13 GitHub milestone][ms-v0.107.13].
+### Added
+
+- The new optional `dns.ipset_file` property in the configuration file. It
+ allows loading the `ipset` list from a file, just like `dns.upstream_dns_file`
+ does for upstream servers ([#4686]).
+
+### Changed
+
+- The minimum DHCP message size is reassigned back to BOOTP's constraint of 300
+ bytes ([#4904]).
+
+### Fixed
+
+- Panic when adding a static lease within the disabled DHCP server ([#4722]).
+
+[#4686]: https://github.com/AdguardTeam/AdGuardHome/issues/4686
+[#4722]: https://github.com/AdguardTeam/AdGuardHome/issues/4722
+[#4904]: https://github.com/AdguardTeam/AdGuardHome/issues/4904
+
[ms-v0.107.13]: https://github.com/AdguardTeam/AdGuardHome/milestone/49?closed=1
--->
@@ -1203,11 +1230,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
-[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.12...HEAD
+[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.13...HEAD
+[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.11]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.10...v0.107.11
[v0.107.10]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.9...v0.107.10
diff --git a/client/src/__locales/be.json b/client/src/__locales/be.json
index cdefa29a..1455825b 100644
--- a/client/src/__locales/be.json
+++ b/client/src/__locales/be.json
@@ -70,7 +70,7 @@
"dhcp_warning": "Калі вы ўсё адно хочаце ўключыць DHCP-сервер, пераканайцеся, што ў сеціве больш няма актыўных DHCP-сервераў. Інакш гэта можа зламаць доступ у сеціва для падлучаных прылад!",
"dhcp_error": "AdGuard Home не можа вызначыць, ці ёсць у сетцы іншы актыўны DHCP-сервер",
"dhcp_static_ip_error": "Для таго, каб выкарыстоўваць DHCP-сервер, павінен быць усталяваны статычны IP-адрас. Мы не змаглі вызначыць, ці выкарыстоўвае гэты інтэрфейс сеціва статычны IP-адрас. Калі ласка, усталюйце яго ручна.",
- "dhcp_dynamic_ip_found": "Ваша сістэма выкарыстоўвае дынамічны IP-адрас для інтэрфейсу <0>{{interfaceName}}0>. Каб выкарыстоўваць DHCP-сервер трэба ўсталяваць статычны IP-адрас. Ваш бягучы IP-адрас – <0>{{ipAddress}}0>. Мы аўтаматычна ўсталюем яго як статычны, калі вы націснеце кнопку Ўключыць DHCP.",
+ "dhcp_dynamic_ip_found": "Ваша сістэма выкарыстоўвае дынамічны IP-адрас для інтэрфейсу <0>{{interfaceName}}0>. Каб выкарыстоўваць DHCP-сервер трэба ўсталяваць статычны IP-адрас. Ваш бягучы IP-адрас – <0>{{ipAddress}}0>. Мы аўтаматычна ўсталюем яго як статычны, калі вы націснеце кнопку «Ўключыць DHCP».",
"dhcp_lease_added": "Статычная арэнда «{{key}}» паспяхова дададзена",
"dhcp_lease_deleted": "Статычная арэнда «{{key}}» паспяхова выдалена",
"dhcp_new_static_lease": "Новая статычная арэнда",
@@ -447,7 +447,7 @@
"access_disallowed_title": "Забароненыя кліенты",
"access_disallowed_desc": "Спіс CIDR, IP-адрасоў або ClientID. Калі ў гэтым спісе ёсць запісы, AdGuard Home выдаліць запыты ад гэтых кліентаў. Гэта поле ігнаруецца, калі ёсць запісы ў Дазволеныя кліенты.",
"access_blocked_title": "Заблакаваныя дамены",
- "access_blocked_desc": "Не блытайце гэта з фільтрамі. AdGuard Home будзе ігнараваць DNS-запыты з гэтымі даменамі.",
+ "access_blocked_desc": "Не блытаць з фільтрамі. AdGuard Home выдаляе запыты DNS, якія адпавядаюць гэтым даменам, і гэтыя запыты нават не з'яўляюцца ў журнале запытаў. Вы можаце ўказаць дакладныя даменныя імёны, падстаноўныя знакі або правілы фільтрацыі URL-адрасоў, напрыклад, «example.org», «*.example.org» ці «||example.org^» адпаведна.",
"access_settings_saved": "Налады доступу паспяхова захаваны",
"updates_checked": "Даступная новая версія AdGuard Home",
"updates_version_equal": "Версія AdGuard Home актуальная",
diff --git a/client/src/__locales/uk.json b/client/src/__locales/uk.json
index e111863d..c613b016 100644
--- a/client/src/__locales/uk.json
+++ b/client/src/__locales/uk.json
@@ -447,7 +447,7 @@
"access_disallowed_title": "Заборонені клієнти",
"access_disallowed_desc": "Перелік CIDR, IP-адрес та ClientIDs. Якщо налаштовано, AdGuard Home буде скасовувати запити від цих клієнтів. Проте якщо налаштовано список Дозволених клієнтів, то це поле проігнорується.",
"access_blocked_title": "Заборонені домени",
- "access_blocked_desc": "Не плутайте з фільтрами. AdGuard Home буде ігнорувати DNS-запити з цими доменами, такі запити навіть не будуть записані до журналу. Ви можете вказати точні доменні імена, замінні знаки та правила фільтрування URL-адрес, наприклад, 'example.org', '*.example.org' або '||example.org^' відповідно.",
+ "access_blocked_desc": "Не плутайте з фільтрами. AdGuard Home буде ігнорувати DNS-запити з цими доменами, такі запити навіть не будуть записані до журналу. Ви можете вказати точні доменні імена, замінні знаки та правила фільтрування URL-адрес, наприклад, «example.org», «*.example.org» або «||example.org^» відповідно.",
"access_settings_saved": "Налаштування доступу успішно збережено",
"updates_checked": "Доступна нова версія AdGuard Home",
"updates_version_equal": "AdGuard Home останньої версії",
diff --git a/internal/aghnet/arpdb_bsd.go b/internal/aghnet/arpdb_bsd.go
index 317579de..9519eeec 100644
--- a/internal/aghnet/arpdb_bsd.go
+++ b/internal/aghnet/arpdb_bsd.go
@@ -1,5 +1,4 @@
//go:build darwin || freebsd
-// +build darwin freebsd
package aghnet
diff --git a/internal/aghnet/arpdb_bsd_test.go b/internal/aghnet/arpdb_bsd_test.go
index 3404af69..9933c721 100644
--- a/internal/aghnet/arpdb_bsd_test.go
+++ b/internal/aghnet/arpdb_bsd_test.go
@@ -1,5 +1,4 @@
//go:build darwin || freebsd
-// +build darwin freebsd
package aghnet
diff --git a/internal/aghnet/arpdb_linux.go b/internal/aghnet/arpdb_linux.go
index e8b34a2f..82f83adf 100644
--- a/internal/aghnet/arpdb_linux.go
+++ b/internal/aghnet/arpdb_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/arpdb_linux_test.go b/internal/aghnet/arpdb_linux_test.go
index 46d87150..22fe7135 100644
--- a/internal/aghnet/arpdb_linux_test.go
+++ b/internal/aghnet/arpdb_linux_test.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/arpdb_openbsd.go b/internal/aghnet/arpdb_openbsd.go
index e1626c0b..5590f335 100644
--- a/internal/aghnet/arpdb_openbsd.go
+++ b/internal/aghnet/arpdb_openbsd.go
@@ -1,5 +1,4 @@
//go:build openbsd
-// +build openbsd
package aghnet
diff --git a/internal/aghnet/arpdb_openbsd_test.go b/internal/aghnet/arpdb_openbsd_test.go
index 915c17ff..0a45514a 100644
--- a/internal/aghnet/arpdb_openbsd_test.go
+++ b/internal/aghnet/arpdb_openbsd_test.go
@@ -1,5 +1,4 @@
//go:build openbsd
-// +build openbsd
package aghnet
diff --git a/internal/aghnet/arpdb_windows.go b/internal/aghnet/arpdb_windows.go
index e81f6818..f6e27b5b 100644
--- a/internal/aghnet/arpdb_windows.go
+++ b/internal/aghnet/arpdb_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/arpdb_windows_test.go b/internal/aghnet/arpdb_windows_test.go
index ad88ff8e..bb75c988 100644
--- a/internal/aghnet/arpdb_windows_test.go
+++ b/internal/aghnet/arpdb_windows_test.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/dhcp_unix.go b/internal/aghnet/dhcp_unix.go
index 4791d0e5..464e5aa9 100644
--- a/internal/aghnet/dhcp_unix.go
+++ b/internal/aghnet/dhcp_unix.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package aghnet
diff --git a/internal/aghnet/dhcp_windows.go b/internal/aghnet/dhcp_windows.go
index 6d1ba231..f8f6dbd2 100644
--- a/internal/aghnet/dhcp_windows.go
+++ b/internal/aghnet/dhcp_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/hostscontainer_linux.go b/internal/aghnet/hostscontainer_linux.go
index b456efdd..290291e9 100644
--- a/internal/aghnet/hostscontainer_linux.go
+++ b/internal/aghnet/hostscontainer_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/hostscontainer_others.go b/internal/aghnet/hostscontainer_others.go
index cd9f0fb7..61487dc4 100644
--- a/internal/aghnet/hostscontainer_others.go
+++ b/internal/aghnet/hostscontainer_others.go
@@ -1,5 +1,4 @@
//go:build !(windows || linux)
-// +build !windows,!linux
package aghnet
diff --git a/internal/aghnet/hostscontainer_windows.go b/internal/aghnet/hostscontainer_windows.go
index 9eb2fe6f..819ba5bb 100644
--- a/internal/aghnet/hostscontainer_windows.go
+++ b/internal/aghnet/hostscontainer_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/interfaces_linux.go b/internal/aghnet/interfaces_linux.go
index a3cda5fa..435084fb 100644
--- a/internal/aghnet/interfaces_linux.go
+++ b/internal/aghnet/interfaces_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/interfaces_unix.go b/internal/aghnet/interfaces_unix.go
index 529b0d9c..476f1a1e 100644
--- a/internal/aghnet/interfaces_unix.go
+++ b/internal/aghnet/interfaces_unix.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd netbsd openbsd solaris
+//go:build darwin || freebsd || openbsd
package aghnet
diff --git a/internal/aghnet/interfaces_windows.go b/internal/aghnet/interfaces_windows.go
index e483c350..a00b7094 100644
--- a/internal/aghnet/interfaces_windows.go
+++ b/internal/aghnet/interfaces_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/ipset_linux.go b/internal/aghnet/ipset_linux.go
index 57248b41..d1376b52 100644
--- a/internal/aghnet/ipset_linux.go
+++ b/internal/aghnet/ipset_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/ipset_linux_test.go b/internal/aghnet/ipset_linux_test.go
index 12c842a0..d220f87e 100644
--- a/internal/aghnet/ipset_linux_test.go
+++ b/internal/aghnet/ipset_linux_test.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/ipset_others.go b/internal/aghnet/ipset_others.go
index 814c35be..8406e0e1 100644
--- a/internal/aghnet/ipset_others.go
+++ b/internal/aghnet/ipset_others.go
@@ -1,5 +1,4 @@
//go:build !linux
-// +build !linux
package aghnet
diff --git a/internal/aghnet/net_bsd.go b/internal/aghnet/net_bsd.go
index bd705e92..94a27a6d 100644
--- a/internal/aghnet/net_bsd.go
+++ b/internal/aghnet/net_bsd.go
@@ -1,5 +1,4 @@
//go:build darwin || freebsd || openbsd
-// +build darwin freebsd openbsd
package aghnet
diff --git a/internal/aghnet/net_darwin.go b/internal/aghnet/net_darwin.go
index 296a18b0..bdf04729 100644
--- a/internal/aghnet/net_darwin.go
+++ b/internal/aghnet/net_darwin.go
@@ -1,5 +1,4 @@
//go:build darwin
-// +build darwin
package aghnet
diff --git a/internal/aghnet/net_freebsd.go b/internal/aghnet/net_freebsd.go
index 85d40184..94ce77c7 100644
--- a/internal/aghnet/net_freebsd.go
+++ b/internal/aghnet/net_freebsd.go
@@ -1,5 +1,4 @@
//go:build freebsd
-// +build freebsd
package aghnet
diff --git a/internal/aghnet/net_freebsd_test.go b/internal/aghnet/net_freebsd_test.go
index 2c758360..8e23092c 100644
--- a/internal/aghnet/net_freebsd_test.go
+++ b/internal/aghnet/net_freebsd_test.go
@@ -1,5 +1,4 @@
//go:build freebsd
-// +build freebsd
package aghnet
diff --git a/internal/aghnet/net_linux.go b/internal/aghnet/net_linux.go
index 4be8835c..d0c3f7fd 100644
--- a/internal/aghnet/net_linux.go
+++ b/internal/aghnet/net_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/net_linux_test.go b/internal/aghnet/net_linux_test.go
index 838802ff..89058312 100644
--- a/internal/aghnet/net_linux_test.go
+++ b/internal/aghnet/net_linux_test.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghnet
diff --git a/internal/aghnet/net_openbsd.go b/internal/aghnet/net_openbsd.go
index cf911105..a2650aee 100644
--- a/internal/aghnet/net_openbsd.go
+++ b/internal/aghnet/net_openbsd.go
@@ -1,5 +1,4 @@
//go:build openbsd
-// +build openbsd
package aghnet
diff --git a/internal/aghnet/net_openbsd_test.go b/internal/aghnet/net_openbsd_test.go
index 356799b7..7239f50f 100644
--- a/internal/aghnet/net_openbsd_test.go
+++ b/internal/aghnet/net_openbsd_test.go
@@ -1,5 +1,4 @@
//go:build openbsd
-// +build openbsd
package aghnet
diff --git a/internal/aghnet/net_unix.go b/internal/aghnet/net_unix.go
index 27b79579..421c5ec0 100644
--- a/internal/aghnet/net_unix.go
+++ b/internal/aghnet/net_unix.go
@@ -1,5 +1,4 @@
-//go:build openbsd || freebsd || linux || darwin
-// +build openbsd freebsd linux darwin
+//go:build darwin || freebsd || linux || openbsd
package aghnet
diff --git a/internal/aghnet/net_windows.go b/internal/aghnet/net_windows.go
index 17499cce..1a17ab4d 100644
--- a/internal/aghnet/net_windows.go
+++ b/internal/aghnet/net_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/systemresolvers_others.go b/internal/aghnet/systemresolvers_others.go
index f8afa286..a0bdf953 100644
--- a/internal/aghnet/systemresolvers_others.go
+++ b/internal/aghnet/systemresolvers_others.go
@@ -1,5 +1,4 @@
//go:build !windows
-// +build !windows
package aghnet
diff --git a/internal/aghnet/systemresolvers_others_test.go b/internal/aghnet/systemresolvers_others_test.go
index f7cf9ef0..a9974e0a 100644
--- a/internal/aghnet/systemresolvers_others_test.go
+++ b/internal/aghnet/systemresolvers_others_test.go
@@ -1,5 +1,4 @@
//go:build !windows
-// +build !windows
package aghnet
diff --git a/internal/aghnet/systemresolvers_windows.go b/internal/aghnet/systemresolvers_windows.go
index 2e8ed3df..0f5d8c6e 100644
--- a/internal/aghnet/systemresolvers_windows.go
+++ b/internal/aghnet/systemresolvers_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghnet/systemresolvers_windows_test.go b/internal/aghnet/systemresolvers_windows_test.go
index d8c38396..5b60bda7 100644
--- a/internal/aghnet/systemresolvers_windows_test.go
+++ b/internal/aghnet/systemresolvers_windows_test.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghnet
diff --git a/internal/aghos/endian_big.go b/internal/aghos/endian_big.go
index 8e6c0b99..d825023e 100644
--- a/internal/aghos/endian_big.go
+++ b/internal/aghos/endian_big.go
@@ -1,5 +1,4 @@
//go:build mips || mips64
-// +build mips mips64
// This file is an adapted version of github.com/josharian/native.
diff --git a/internal/aghos/endian_little.go b/internal/aghos/endian_little.go
index 56a4e3ce..22845305 100644
--- a/internal/aghos/endian_little.go
+++ b/internal/aghos/endian_little.go
@@ -1,5 +1,4 @@
//go:build amd64 || 386 || arm || arm64 || mipsle || mips64le || ppc64le
-// +build amd64 386 arm arm64 mipsle mips64le ppc64le
// This file is an adapted version of github.com/josharian/native.
diff --git a/internal/aghos/os_bsd.go b/internal/aghos/os_bsd.go
index 48b76609..746a8f3f 100644
--- a/internal/aghos/os_bsd.go
+++ b/internal/aghos/os_bsd.go
@@ -1,5 +1,4 @@
-//go:build darwin || netbsd || openbsd
-// +build darwin netbsd openbsd
+//go:build darwin || openbsd
package aghos
diff --git a/internal/aghos/os_freebsd.go b/internal/aghos/os_freebsd.go
index 33cd9d3f..081aa55a 100644
--- a/internal/aghos/os_freebsd.go
+++ b/internal/aghos/os_freebsd.go
@@ -1,5 +1,4 @@
//go:build freebsd
-// +build freebsd
package aghos
diff --git a/internal/aghos/os_linux.go b/internal/aghos/os_linux.go
index ed513b00..daffb621 100644
--- a/internal/aghos/os_linux.go
+++ b/internal/aghos/os_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package aghos
diff --git a/internal/aghos/os_unix.go b/internal/aghos/os_unix.go
index 9a3cc308..da8ee912 100644
--- a/internal/aghos/os_unix.go
+++ b/internal/aghos/os_unix.go
@@ -1,5 +1,4 @@
//go:build darwin || freebsd || linux || openbsd
-// +build darwin freebsd linux openbsd
package aghos
diff --git a/internal/aghos/os_windows.go b/internal/aghos/os_windows.go
index 31fca3ef..c79a603f 100644
--- a/internal/aghos/os_windows.go
+++ b/internal/aghos/os_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghos
diff --git a/internal/aghos/syslog_others.go b/internal/aghos/syslog_others.go
index 8399bae0..1659ae49 100644
--- a/internal/aghos/syslog_others.go
+++ b/internal/aghos/syslog_others.go
@@ -1,5 +1,4 @@
-//go:build !(windows || plan9)
-// +build !windows,!plan9
+//go:build !windows
package aghos
diff --git a/internal/aghos/syslog_windows.go b/internal/aghos/syslog_windows.go
index f562168e..c8e86e78 100644
--- a/internal/aghos/syslog_windows.go
+++ b/internal/aghos/syslog_windows.go
@@ -1,5 +1,4 @@
-//go:build windows || plan9
-// +build windows plan9
+//go:build windows
package aghos
diff --git a/internal/aghos/user_unix.go b/internal/aghos/user_unix.go
index 3ccb6eb9..e6da5fca 100644
--- a/internal/aghos/user_unix.go
+++ b/internal/aghos/user_unix.go
@@ -1,5 +1,4 @@
-//go:build darwin || freebsd || linux || netbsd || openbsd
-// +build darwin freebsd linux netbsd openbsd
+//go:build darwin || freebsd || linux || openbsd
package aghos
diff --git a/internal/aghos/user_windows.go b/internal/aghos/user_windows.go
index 4fac90e1..a5876588 100644
--- a/internal/aghos/user_windows.go
+++ b/internal/aghos/user_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package aghos
diff --git a/internal/dhcpd/broadcast_bsd.go b/internal/dhcpd/broadcast_bsd.go
index b55a903d..59372cdf 100644
--- a/internal/dhcpd/broadcast_bsd.go
+++ b/internal/dhcpd/broadcast_bsd.go
@@ -1,5 +1,4 @@
//go:build freebsd || openbsd
-// +build freebsd openbsd
package dhcpd
@@ -10,11 +9,10 @@ import (
// broadcast sends resp to the broadcast address specific for network interface.
func (c *dhcpConn) broadcast(respData []byte, peer *net.UDPAddr) (n int, err error) {
// Despite the fact that server4.NewIPv4UDPConn explicitly sets socket
- // options to allow broadcasting, it also binds the connection to a
- // specific interface. On FreeBSD and OpenBSD net.UDPConn.WriteTo
- // causes errors while writing to the addresses that belong to another
- // interface. So, use the broadcast address specific for the interface
- // bound.
+ // options to allow broadcasting, it also binds the connection to a specific
+ // interface. On FreeBSD and OpenBSD net.UDPConn.WriteTo causes errors
+ // while writing to the addresses that belong to another interface. So, use
+ // the broadcast address specific for the interface bound.
peer.IP = c.bcastIP
return c.udpConn.WriteTo(respData, peer)
diff --git a/internal/dhcpd/broadcast_bsd_test.go b/internal/dhcpd/broadcast_bsd_test.go
index ed81d272..dc333ca6 100644
--- a/internal/dhcpd/broadcast_bsd_test.go
+++ b/internal/dhcpd/broadcast_bsd_test.go
@@ -1,5 +1,4 @@
//go:build freebsd || openbsd
-// +build freebsd openbsd
package dhcpd
diff --git a/internal/dhcpd/broadcast_others.go b/internal/dhcpd/broadcast_others.go
index a6e1307a..46326f8d 100644
--- a/internal/dhcpd/broadcast_others.go
+++ b/internal/dhcpd/broadcast_others.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || linux || netbsd || solaris
-// +build aix darwin dragonfly linux netbsd solaris
+//go:build darwin || linux
package dhcpd
diff --git a/internal/dhcpd/broadcast_others_test.go b/internal/dhcpd/broadcast_others_test.go
index cb25ac28..437f114c 100644
--- a/internal/dhcpd/broadcast_others_test.go
+++ b/internal/dhcpd/broadcast_others_test.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || linux || netbsd || solaris
-// +build aix darwin dragonfly linux netbsd solaris
+//go:build darwin || linux
package dhcpd
diff --git a/internal/dhcpd/server.go b/internal/dhcpd/config.go
similarity index 55%
rename from internal/dhcpd/server.go
rename to internal/dhcpd/config.go
index be88804b..9d8ef057 100644
--- a/internal/dhcpd/server.go
+++ b/internal/dhcpd/config.go
@@ -1,10 +1,40 @@
package dhcpd
import (
+ "fmt"
"net"
"time"
+
+ "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
+ "github.com/AdguardTeam/AdGuardHome/internal/aghnet"
+ "github.com/AdguardTeam/golibs/errors"
+ "github.com/AdguardTeam/golibs/netutil"
)
+// ServerConfig is the configuration for the DHCP server. The order of YAML
+// fields is important, since the YAML configuration file follows it.
+type ServerConfig struct {
+ // Called when the configuration is changed by HTTP request
+ ConfigModified func() `yaml:"-"`
+
+ // Register an HTTP handler
+ HTTPRegister aghhttp.RegisterFunc `yaml:"-"`
+
+ Enabled bool `yaml:"enabled"`
+ InterfaceName string `yaml:"interface_name"`
+
+ // LocalDomainName is the domain name used for DHCP hosts. For example,
+ // a DHCP client with the hostname "myhost" can be addressed as "myhost.lan"
+ // when LocalDomainName is "lan".
+ LocalDomainName string `yaml:"local_domain_name"`
+
+ Conf4 V4ServerConf `yaml:"dhcpv4"`
+ Conf6 V6ServerConf `yaml:"dhcpv6"`
+
+ WorkDir string `yaml:"-"`
+ DBFilePath string `yaml:"-"`
+}
+
// DHCPServer - DHCP server interface
type DHCPServer interface {
// ResetLeases resets leases.
@@ -80,6 +110,86 @@ type V4ServerConf struct {
notify func(uint32)
}
+// errNilConfig is an error returned by validation method if the config is nil.
+const errNilConfig errors.Error = "nil config"
+
+// ensureV4 returns a 4-byte version of ip. An error is returned if the passed
+// ip is not an IPv4.
+func ensureV4(ip net.IP) (ip4 net.IP, err error) {
+ if ip == nil {
+ return nil, fmt.Errorf("%v is not an IP address", ip)
+ }
+
+ ip4 = ip.To4()
+ if ip4 == nil {
+ return nil, fmt.Errorf("%v is not an IPv4 address", ip)
+ }
+
+ return ip4, nil
+}
+
+// Validate returns an error if c is not a valid configuration.
+//
+// TODO(e.burkov): Don't set the config fields when the server itself will stop
+// containing the config.
+func (c *V4ServerConf) Validate() (err error) {
+ defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
+
+ if c == nil {
+ return errNilConfig
+ }
+
+ var gatewayIP net.IP
+ gatewayIP, err = ensureV4(c.GatewayIP)
+ if err != nil {
+ // Don't wrap an errors since it's inforative enough as is and there is
+ // an annotation deferred already.
+ return err
+ }
+
+ if c.SubnetMask == nil {
+ return fmt.Errorf("invalid subnet mask: %v", c.SubnetMask)
+ }
+
+ subnetMask := net.IPMask(netutil.CloneIP(c.SubnetMask.To4()))
+ c.subnet = &net.IPNet{
+ IP: gatewayIP,
+ Mask: subnetMask,
+ }
+ c.broadcastIP = aghnet.BroadcastFromIPNet(c.subnet)
+
+ c.ipRange, err = newIPRange(c.RangeStart, c.RangeEnd)
+ if err != nil {
+ // Don't wrap an errors since it's inforative enough as is and there is
+ // an annotation deferred already.
+ return err
+ }
+
+ if c.ipRange.contains(gatewayIP) {
+ return fmt.Errorf("gateway ip %v in the ip range: %v-%v",
+ gatewayIP,
+ c.RangeStart,
+ c.RangeEnd,
+ )
+ }
+
+ if !c.subnet.Contains(c.RangeStart) {
+ return fmt.Errorf("range start %v is outside network %v",
+ c.RangeStart,
+ c.subnet,
+ )
+ }
+
+ if !c.subnet.Contains(c.RangeEnd) {
+ return fmt.Errorf("range end %v is outside network %v",
+ c.RangeEnd,
+ c.subnet,
+ )
+ }
+
+ return nil
+}
+
// V6ServerConf - server configuration
type V6ServerConf struct {
Enabled bool `yaml:"-" json:"-"`
diff --git a/internal/dhcpd/conn_unix.go b/internal/dhcpd/conn_unix.go
index 01c063d1..ec58afda 100644
--- a/internal/dhcpd/conn_unix.go
+++ b/internal/dhcpd/conn_unix.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
diff --git a/internal/dhcpd/conn_unix_test.go b/internal/dhcpd/conn_unix_test.go
index 0fdbfec0..aab79082 100644
--- a/internal/dhcpd/conn_unix_test.go
+++ b/internal/dhcpd/conn_unix_test.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
diff --git a/internal/dhcpd/db.go b/internal/dhcpd/db.go
index af6bf72e..91a83447 100644
--- a/internal/dhcpd/db.go
+++ b/internal/dhcpd/db.go
@@ -32,7 +32,7 @@ func normalizeIP(ip net.IP) net.IP {
}
// Load lease table from DB
-func (s *Server) dbLoad() (err error) {
+func (s *server) dbLoad() (err error) {
dynLeases := []*Lease{}
staticLeases := []*Lease{}
v6StaticLeases := []*Lease{}
@@ -132,7 +132,7 @@ func normalizeLeases(staticLeases, dynLeases []*Lease) []*Lease {
}
// Store lease table in DB
-func (s *Server) dbStore() (err error) {
+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.
leases := []leaseJSON{}
diff --git a/internal/dhcpd/dhcpd.go b/internal/dhcpd/dhcpd.go
index a085e656..875b3d79 100644
--- a/internal/dhcpd/dhcpd.go
+++ b/internal/dhcpd/dhcpd.go
@@ -6,12 +6,11 @@ import (
"fmt"
"net"
"path/filepath"
- "runtime"
"time"
- "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/netutil"
+ "github.com/AdguardTeam/golibs/timeutil"
)
const (
@@ -21,9 +20,19 @@ const (
// TODO(e.burkov): Remove it when static leases determining mechanism
// will be improved.
leaseExpireStatic = 1
+
+ // DefaultDHCPLeaseTTL is the default time-to-live for leases.
+ DefaultDHCPLeaseTTL = uint32(timeutil.Day / time.Second)
+
+ // DefaultDHCPTimeoutICMP is the default timeout for waiting ICMP responses.
+ DefaultDHCPTimeoutICMP = 1000
)
-var webHandlersRegistered = false
+// Currently used defaults for ifaceDNSAddrs.
+const (
+ defaultMaxAttempts int = 10
+ defaultBackoff time.Duration = 500 * time.Millisecond
+)
// Lease contains the necessary information about a DHCP lease
type Lease struct {
@@ -119,30 +128,6 @@ func (l *Lease) UnmarshalJSON(data []byte) (err error) {
return nil
}
-// ServerConfig is the configuration for the DHCP server. The order of YAML
-// fields is important, since the YAML configuration file follows it.
-type ServerConfig struct {
- // Called when the configuration is changed by HTTP request
- ConfigModified func() `yaml:"-"`
-
- // Register an HTTP handler
- HTTPRegister aghhttp.RegisterFunc `yaml:"-"`
-
- Enabled bool `yaml:"enabled"`
- InterfaceName string `yaml:"interface_name"`
-
- // LocalDomainName is the domain name used for DHCP hosts. For example,
- // a DHCP client with the hostname "myhost" can be addressed as "myhost.lan"
- // when LocalDomainName is "lan".
- LocalDomainName string `yaml:"local_domain_name"`
-
- Conf4 V4ServerConf `yaml:"dhcpv4"`
- Conf6 V6ServerConf `yaml:"dhcpv6"`
-
- WorkDir string `yaml:"-"`
- DBFilePath string `yaml:"-"`
-}
-
// OnLeaseChangedT is a callback for lease changes.
type OnLeaseChangedT func(flags int)
@@ -156,8 +141,68 @@ const (
LeaseChangedDBStore
)
-// Server - the current state of the DHCP server
-type Server struct {
+// GetLeasesFlags are the flags for GetLeases.
+type GetLeasesFlags uint8
+
+// GetLeasesFlags values
+const (
+ LeasesDynamic GetLeasesFlags = 0b01
+ LeasesStatic GetLeasesFlags = 0b10
+
+ LeasesAll = LeasesDynamic | LeasesStatic
+)
+
+// Interface is the DHCP server that deals with both IP address families.
+type Interface interface {
+ Start() (err error)
+ Stop() (err error)
+ Enabled() (ok bool)
+
+ Leases(flags GetLeasesFlags) (leases []*Lease)
+ SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
+ FindMACbyIP(ip net.IP) (mac net.HardwareAddr)
+
+ WriteDiskConfig(c *ServerConfig)
+}
+
+// MockInterface is a mock Interface implementation.
+//
+// TODO(e.burkov): Move to aghtest when the API stabilized.
+type MockInterface struct {
+ OnStart func() (err error)
+ OnStop func() (err error)
+ OnEnabled func() (ok bool)
+ OnLeases func(flags GetLeasesFlags) (leases []*Lease)
+ OnSetOnLeaseChanged func(f OnLeaseChangedT)
+ OnFindMACbyIP func(ip net.IP) (mac net.HardwareAddr)
+ OnWriteDiskConfig func(c *ServerConfig)
+}
+
+var _ Interface = (*MockInterface)(nil)
+
+// Start implements the Interface for *MockInterface.
+func (s *MockInterface) Start() (err error) { return s.OnStart() }
+
+// Stop implements the Interface for *MockInterface.
+func (s *MockInterface) Stop() (err error) { return s.OnStop() }
+
+// Enabled implements the Interface for *MockInterface.
+func (s *MockInterface) Enabled() (ok bool) { return s.OnEnabled() }
+
+// Leases implements the Interface for *MockInterface.
+func (s *MockInterface) Leases(flags GetLeasesFlags) (ls []*Lease) { return s.OnLeases(flags) }
+
+// SetOnLeaseChanged implements the Interface for *MockInterface.
+func (s *MockInterface) SetOnLeaseChanged(f OnLeaseChangedT) { s.OnSetOnLeaseChanged(f) }
+
+// FindMACbyIP implements the Interface for *MockInterface.
+func (s *MockInterface) FindMACbyIP(ip net.IP) (mac net.HardwareAddr) { return s.OnFindMACbyIP(ip) }
+
+// WriteDiskConfig implements the Interface for *MockInterface.
+func (s *MockInterface) WriteDiskConfig(c *ServerConfig) { s.OnWriteDiskConfig(c) }
+
+// server is the DHCP service that handles DHCPv4, DHCPv6, and HTTP API.
+type server struct {
srv4 DHCPServer
srv6 DHCPServer
@@ -169,27 +214,15 @@ type Server struct {
onLeaseChanged []OnLeaseChangedT
}
-// GetLeasesFlags are the flags for GetLeases.
-type GetLeasesFlags uint8
+// type check
+var _ Interface = (*server)(nil)
-// GetLeasesFlags values
-const (
- LeasesDynamic GetLeasesFlags = 0b0001
- LeasesStatic GetLeasesFlags = 0b0010
-
- LeasesAll = LeasesDynamic | LeasesStatic
-)
-
-// ServerInterface is an interface for servers.
-type ServerInterface interface {
- Enabled() (ok bool)
- Leases(flags GetLeasesFlags) (leases []*Lease)
- SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT)
-}
-
-// Create - create object
-func Create(conf *ServerConfig) (s *Server, err error) {
- s = &Server{
+// Create initializes and returns the DHCP server handling both address
+// families. It also registers the corresponding HTTP API endpoints.
+//
+// TODO(e.burkov): Don't register handlers, see TODO on [aghhttp.RegisterFunc].
+func Create(conf *ServerConfig) (s *server, err error) {
+ s = &server{
conf: &ServerConfig{
ConfigModified: conf.ConfigModified,
@@ -204,35 +237,20 @@ func Create(conf *ServerConfig) (s *Server, err error) {
},
}
- if !webHandlersRegistered && s.conf.HTTPRegister != nil {
- if runtime.GOOS == "windows" {
- // Our DHCP server doesn't work on Windows yet, so
- // signal that to the front with an HTTP 501.
- //
- // TODO(a.garipov): This needs refactoring. We
- // shouldn't even try and initialize a DHCP server on
- // Windows, but there are currently too many
- // interconnected parts--such as HTTP handlers and
- // frontend--to make that work properly.
- s.registerNotImplementedHandlers()
- } else {
- s.registerHandlers()
- }
-
- webHandlersRegistered = true
- }
+ s.registerHandlers()
v4conf := conf.Conf4
- v4conf.Enabled = s.conf.Enabled
- if len(v4conf.RangeStart) == 0 {
- v4conf.Enabled = false
- }
-
v4conf.InterfaceName = s.conf.InterfaceName
v4conf.notify = s.onNotify
- s.srv4, err = v4Create(v4conf)
+ v4conf.Enabled = s.conf.Enabled && len(v4conf.RangeStart) != 0
+
+ s.srv4, err = v4Create(&v4conf)
if err != nil {
- return nil, fmt.Errorf("creating dhcpv4 srv: %w", err)
+ if v4conf.Enabled {
+ return nil, fmt.Errorf("creating dhcpv4 srv: %w", err)
+ }
+
+ log.Error("creating dhcpv4 srv: %s", err)
}
v6conf := conf.Conf6
@@ -265,12 +283,12 @@ func Create(conf *ServerConfig) (s *Server, err error) {
}
// Enabled returns true when the server is enabled.
-func (s *Server) Enabled() (ok bool) {
+func (s *server) Enabled() (ok bool) {
return s.conf.Enabled
}
// resetLeases resets all leases in the lease database.
-func (s *Server) resetLeases() (err error) {
+func (s *server) resetLeases() (err error) {
err = s.srv4.ResetLeases(nil)
if err != nil {
return err
@@ -287,7 +305,7 @@ func (s *Server) resetLeases() (err error) {
}
// server calls this function after DB is updated
-func (s *Server) onNotify(flags uint32) {
+func (s *server) onNotify(flags uint32) {
if flags == LeaseChangedDBStore {
err := s.dbStore()
if err != nil {
@@ -301,31 +319,28 @@ func (s *Server) onNotify(flags uint32) {
}
// SetOnLeaseChanged - set callback
-func (s *Server) SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT) {
+func (s *server) SetOnLeaseChanged(onLeaseChanged OnLeaseChangedT) {
s.onLeaseChanged = append(s.onLeaseChanged, onLeaseChanged)
}
-func (s *Server) notify(flags int) {
- if len(s.onLeaseChanged) == 0 {
- return
- }
-
+func (s *server) notify(flags int) {
for _, f := range s.onLeaseChanged {
f(flags)
}
}
// WriteDiskConfig - write configuration
-func (s *Server) WriteDiskConfig(c *ServerConfig) {
+func (s *server) WriteDiskConfig(c *ServerConfig) {
c.Enabled = s.conf.Enabled
c.InterfaceName = s.conf.InterfaceName
c.LocalDomainName = s.conf.LocalDomainName
+
s.srv4.WriteDiskConfig4(&c.Conf4)
s.srv6.WriteDiskConfig6(&c.Conf6)
}
// Start will listen on port 67 and serve DHCP requests.
-func (s *Server) Start() (err error) {
+func (s *server) Start() (err error) {
err = s.srv4.Start()
if err != nil {
return err
@@ -340,7 +355,7 @@ func (s *Server) Start() (err error) {
}
// Stop closes the listening UDP socket
-func (s *Server) Stop() (err error) {
+func (s *server) Stop() (err error) {
err = s.srv4.Stop()
if err != nil {
return err
@@ -356,12 +371,12 @@ func (s *Server) Stop() (err error) {
// Leases returns the list of active IPv4 and IPv6 DHCP leases. It's safe for
// concurrent use.
-func (s *Server) Leases(flags GetLeasesFlags) (leases []*Lease) {
+func (s *server) Leases(flags GetLeasesFlags) (leases []*Lease) {
return append(s.srv4.GetLeases(flags), s.srv6.GetLeases(flags)...)
}
// FindMACbyIP - find a MAC address by IP address in the currently active DHCP leases
-func (s *Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
+func (s *server) FindMACbyIP(ip net.IP) net.HardwareAddr {
if ip.To4() != nil {
return s.srv4.FindMACbyIP(ip)
}
@@ -369,6 +384,6 @@ func (s *Server) FindMACbyIP(ip net.IP) net.HardwareAddr {
}
// AddStaticLease - add static v4 lease
-func (s *Server) AddStaticLease(l *Lease) error {
+func (s *server) AddStaticLease(l *Lease) error {
return s.srv4.AddStaticLease(l)
}
diff --git a/internal/dhcpd/dhcpd_test.go b/internal/dhcpd/dhcpd_unix_test.go
similarity index 84%
rename from internal/dhcpd/dhcpd_test.go
rename to internal/dhcpd/dhcpd_unix_test.go
index b704cbb4..cd1ca39a 100644
--- a/internal/dhcpd/dhcpd_test.go
+++ b/internal/dhcpd/dhcpd_unix_test.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
@@ -26,13 +25,13 @@ func testNotify(flags uint32) {
// Leases database store/load.
func TestDB(t *testing.T) {
var err error
- s := Server{
+ s := server{
conf: &ServerConfig{
DBFilePath: dbFilename,
},
}
- s.srv4, err = v4Create(V4ServerConf{
+ s.srv4, err = v4Create(&V4ServerConf{
Enabled: true,
RangeStart: net.IP{192, 168, 10, 100},
RangeEnd: net.IP{192, 168, 10, 200},
@@ -88,32 +87,6 @@ func TestDB(t *testing.T) {
assert.Equal(t, leases[0].Expiry.Unix(), ll[1].Expiry.Unix())
}
-func TestIsValidSubnetMask(t *testing.T) {
- testCases := []struct {
- mask net.IP
- want bool
- }{{
- mask: net.IP{255, 255, 255, 0},
- want: true,
- }, {
- mask: net.IP{255, 255, 254, 0},
- want: true,
- }, {
- mask: net.IP{255, 255, 252, 0},
- want: true,
- }, {
- mask: net.IP{255, 255, 253, 0},
- }, {
- mask: net.IP{255, 255, 255, 1},
- }}
-
- for _, tc := range testCases {
- t.Run(tc.mask.String(), func(t *testing.T) {
- assert.Equal(t, tc.want, isValidSubnetMask(tc.mask))
- })
- }
-}
-
func TestNormalizeLeases(t *testing.T) {
dynLeases := []*Lease{{
HWAddr: net.HardwareAddr{1, 2, 3, 4},
@@ -174,7 +147,7 @@ func TestV4Server_badRange(t *testing.T) {
notify: testNotify,
}
- _, err := v4Create(conf)
+ _, err := v4Create(&conf)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
})
}
diff --git a/internal/dhcpd/helpers.go b/internal/dhcpd/helpers.go
deleted file mode 100644
index df157a49..00000000
--- a/internal/dhcpd/helpers.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package dhcpd
-
-import (
- "encoding/binary"
- "fmt"
- "net"
-)
-
-func tryTo4(ip net.IP) (ip4 net.IP, err error) {
- if ip == nil {
- return nil, fmt.Errorf("%v is not an IP address", ip)
- }
-
- ip4 = ip.To4()
- if ip4 == nil {
- return nil, fmt.Errorf("%v is not an IPv4 address", ip)
- }
-
- return ip4, nil
-}
-
-// Return TRUE if subnet mask is correct (e.g. 255.255.255.0)
-func isValidSubnetMask(mask net.IP) bool {
- var n uint32
- n = binary.BigEndian.Uint32(mask)
- for i := 0; i != 32; i++ {
- if n == 0 {
- break
- }
- if (n & 0x80000000) == 0 {
- return false
- }
- n <<= 1
- }
- return true
-}
diff --git a/internal/dhcpd/http.go b/internal/dhcpd/http_unix.go
similarity index 78%
rename from internal/dhcpd/http.go
rename to internal/dhcpd/http_unix.go
index a8f0c108..8a32dab6 100644
--- a/internal/dhcpd/http.go
+++ b/internal/dhcpd/http_unix.go
@@ -1,3 +1,5 @@
+//go:build darwin || freebsd || linux || openbsd
+
package dhcpd
import (
@@ -8,14 +10,12 @@ import (
"net/http"
"os"
"strings"
- "time"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
- "github.com/AdguardTeam/golibs/timeutil"
)
type v4ServerConfJSON struct {
@@ -26,12 +26,12 @@ type v4ServerConfJSON struct {
LeaseDuration uint32 `json:"lease_duration"`
}
-func v4JSONToServerConf(j *v4ServerConfJSON) V4ServerConf {
+func (j *v4ServerConfJSON) toServerConf() *V4ServerConf {
if j == nil {
- return V4ServerConf{}
+ return &V4ServerConf{}
}
- return V4ServerConf{
+ return &V4ServerConf{
GatewayIP: j.GatewayIP,
SubnetMask: j.SubnetMask,
RangeStart: j.RangeStart,
@@ -66,7 +66,7 @@ type dhcpStatusResponse struct {
Enabled bool `json:"enabled"`
}
-func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
status := &dhcpStatusResponse{
Enabled: s.conf.Enabled,
IfaceName: s.conf.InterfaceName,
@@ -81,6 +81,7 @@ func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
status.StaticLeases = s.Leases(LeasesStatic)
w.Header().Set("Content-Type", "application/json")
+
err := json.NewEncoder(w).Encode(status)
if err != nil {
aghhttp.Error(
@@ -93,28 +94,26 @@ func (s *Server) handleDHCPStatus(w http.ResponseWriter, r *http.Request) {
}
}
-func (s *Server) enableDHCP(ifaceName string) (code int, err error) {
+func (s *server) enableDHCP(ifaceName string) (code int, err error) {
var hasStaticIP bool
hasStaticIP, err = aghnet.IfaceHasStaticIP(ifaceName)
if err != nil {
if errors.Is(err, os.ErrPermission) {
- // ErrPermission may happen here on Linux systems where
- // AdGuard Home is installed using Snap. That doesn't
- // necessarily mean that the machine doesn't have
- // a static IP, so we can assume that it has and go on.
- // If the machine doesn't, we'll get an error later.
+ // ErrPermission may happen here on Linux systems where AdGuard Home
+ // is installed using Snap. That doesn't necessarily mean that the
+ // machine doesn't have a static IP, so we can assume that it has
+ // and go on. If the machine doesn't, we'll get an error later.
//
// See https://github.com/AdguardTeam/AdGuardHome/issues/2667.
//
- // TODO(a.garipov): I was thinking about moving this
- // into IfaceHasStaticIP, but then we wouldn't be able
- // to log it. Think about it more.
+ // TODO(a.garipov): I was thinking about moving this into
+ // IfaceHasStaticIP, but then we wouldn't be able to log it. Think
+ // about it more.
log.Info("error while checking static ip: %s; "+
"assuming machine has static ip and going on", err)
hasStaticIP = true
} else if errors.Is(err, aghnet.ErrNoStaticIPInfo) {
- // Couldn't obtain a definitive answer. Assume static
- // IP an go on.
+ // Couldn't obtain a definitive answer. Assume static IP an go on.
log.Info("can't check for static ip; " +
"assuming machine has static ip and going on")
hasStaticIP = true
@@ -149,34 +148,39 @@ type dhcpServerConfigJSON struct {
Enabled aghalg.NullBool `json:"enabled"`
}
-func (s *Server) handleDHCPSetConfigV4(
+func (s *server) handleDHCPSetConfigV4(
conf *dhcpServerConfigJSON,
-) (srv4 DHCPServer, enabled bool, err error) {
+) (srv DHCPServer, enabled bool, err error) {
if conf.V4 == nil {
return nil, false, nil
}
- v4Conf := v4JSONToServerConf(conf.V4)
+ v4Conf := conf.V4.toServerConf()
v4Conf.Enabled = conf.Enabled == aghalg.NBTrue
if len(v4Conf.RangeStart) == 0 {
v4Conf.Enabled = false
}
- enabled = v4Conf.Enabled
v4Conf.InterfaceName = conf.InterfaceName
- c4 := V4ServerConf{}
- s.srv4.WriteDiskConfig4(&c4)
+ // Set the default values for the fields not configurable via web API.
+ c4 := &V4ServerConf{
+ notify: s.onNotify,
+ ICMPTimeout: s.conf.Conf4.ICMPTimeout,
+ Options: s.conf.Conf4.Options,
+ }
+
+ s.srv4.WriteDiskConfig4(c4)
v4Conf.notify = c4.notify
v4Conf.ICMPTimeout = c4.ICMPTimeout
v4Conf.Options = c4.Options
- srv4, err = v4Create(v4Conf)
+ srv4, err := v4Create(v4Conf)
- return srv4, enabled, err
+ return srv4, srv4.enabled(), err
}
-func (s *Server) handleDHCPSetConfigV6(
+func (s *server) handleDHCPSetConfigV6(
conf *dhcpServerConfigJSON,
) (srv6 DHCPServer, enabled bool, err error) {
if conf.V6 == nil {
@@ -205,7 +209,7 @@ func (s *Server) handleDHCPSetConfigV6(
return srv6, enabled, err
}
-func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
conf := &dhcpServerConfigJSON{}
conf.Enabled = aghalg.BoolToNullBool(s.conf.Enabled)
conf.InterfaceName = s.conf.InterfaceName
@@ -287,7 +291,7 @@ type netInterfaceJSON struct {
Addrs6 []net.IP `json:"ipv6_addresses"`
}
-func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
response := map[string]netInterfaceJSON{}
ifaces, err := net.Interfaces()
@@ -410,7 +414,7 @@ type dhcpSearchResult struct {
// . Search for another DHCP server running
// . Check if a static IP is configured for the network interface
// Respond with results
-func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Request) {
// This use of ReadAll is safe, because request's body is now limited.
body, err := io.ReadAll(r.Body)
if err != nil {
@@ -482,7 +486,7 @@ func (s *Server) handleDHCPFindActiveServer(w http.ResponseWriter, r *http.Reque
}
}
-func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request) {
l := &Lease{}
err := json.NewDecoder(r.Body).Decode(l)
if err != nil {
@@ -497,20 +501,16 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
return
}
- ip4 := l.IP.To4()
- if ip4 == nil {
+ var srv DHCPServer
+ if ip4 := l.IP.To4(); ip4 != nil {
+ l.IP = ip4
+ srv = s.srv4
+ } else {
l.IP = l.IP.To16()
-
- err = s.srv6.AddStaticLease(l)
- if err != nil {
- aghhttp.Error(r, w, http.StatusBadRequest, "%s", err)
- }
-
- return
+ srv = s.srv6
}
- l.IP = ip4
- err = s.srv4.AddStaticLease(l)
+ err = srv.AddStaticLease(l)
if err != nil {
aghhttp.Error(r, w, http.StatusBadRequest, "%s", err)
@@ -518,7 +518,7 @@ func (s *Server) handleDHCPAddStaticLease(w http.ResponseWriter, r *http.Request
}
}
-func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Request) {
l := &Lease{}
err := json.NewDecoder(r.Body).Decode(l)
if err != nil {
@@ -555,14 +555,7 @@ func (s *Server) handleDHCPRemoveStaticLease(w http.ResponseWriter, r *http.Requ
}
}
-const (
- // DefaultDHCPLeaseTTL is the default time-to-live for leases.
- DefaultDHCPLeaseTTL = uint32(timeutil.Day / time.Second)
- // DefaultDHCPTimeoutICMP is the default timeout for waiting ICMP responses.
- DefaultDHCPTimeoutICMP = 1000
-)
-
-func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleReset(w http.ResponseWriter, r *http.Request) {
err := s.Stop()
if err != nil {
aghhttp.Error(r, w, http.StatusInternalServerError, "stopping dhcp: %s", err)
@@ -586,7 +579,7 @@ func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) {
DBFilePath: s.conf.DBFilePath,
}
- v4conf := V4ServerConf{
+ v4conf := &V4ServerConf{
LeaseDuration: DefaultDHCPLeaseTTL,
ICMPTimeout: DefaultDHCPTimeoutICMP,
notify: s.onNotify,
@@ -602,7 +595,7 @@ func (s *Server) handleReset(w http.ResponseWriter, r *http.Request) {
s.conf.ConfigModified()
}
-func (s *Server) handleResetLeases(w http.ResponseWriter, r *http.Request) {
+func (s *server) handleResetLeases(w http.ResponseWriter, r *http.Request) {
err := s.resetLeases()
if err != nil {
msg := "resetting leases: %s"
@@ -612,7 +605,11 @@ func (s *Server) handleResetLeases(w http.ResponseWriter, r *http.Request) {
}
}
-func (s *Server) registerHandlers() {
+func (s *server) registerHandlers() {
+ if s.conf.HTTPRegister == nil {
+ return
+ }
+
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", s.handleDHCPStatus)
s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", s.handleDHCPInterfaces)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", s.handleDHCPSetConfig)
@@ -622,44 +619,3 @@ func (s *Server) registerHandlers() {
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", s.handleReset)
s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset_leases", s.handleResetLeases)
}
-
-// jsonError is a generic JSON error response.
-//
-// TODO(a.garipov): Merge together with the implementations in .../home and
-// other packages after refactoring the web handler registering.
-type jsonError struct {
- // Message is the error message, an opaque string.
- Message string `json:"message"`
-}
-
-// notImplemented returns a handler that replies to any request with an HTTP 501
-// Not Implemented status and a JSON error with the provided message msg.
-//
-// TODO(a.garipov): Either take the logger from the server after we've
-// refactored logging or make this not a method of *Server.
-func (s *Server) notImplemented(msg string) (f func(http.ResponseWriter, *http.Request)) {
- return func(w http.ResponseWriter, _ *http.Request) {
- w.Header().Set("Content-Type", "application/json")
- w.WriteHeader(http.StatusNotImplemented)
-
- err := json.NewEncoder(w).Encode(&jsonError{
- Message: msg,
- })
- if err != nil {
- log.Debug("writing 501 json response: %s", err)
- }
- }
-}
-
-func (s *Server) registerNotImplementedHandlers() {
- h := s.notImplemented("dhcp is not supported on windows")
-
- s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", h)
- s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", h)
- s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", h)
- s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/find_active_dhcp", h)
- s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/add_static_lease", h)
- s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/remove_static_lease", h)
- s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", h)
- s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset_leases", h)
-}
diff --git a/internal/dhcpd/http_windows.go b/internal/dhcpd/http_windows.go
new file mode 100644
index 00000000..5f7f73c1
--- /dev/null
+++ b/internal/dhcpd/http_windows.go
@@ -0,0 +1,55 @@
+//go:build windows
+
+package dhcpd
+
+import (
+ "encoding/json"
+ "net/http"
+
+ "github.com/AdguardTeam/AdGuardHome/internal/aghos"
+ "github.com/AdguardTeam/golibs/log"
+)
+
+// jsonError is a generic JSON error response.
+//
+// TODO(a.garipov): Merge together with the implementations in .../home and
+// other packages after refactoring the web handler registering.
+type jsonError struct {
+ // Message is the error message, an opaque string.
+ Message string `json:"message"`
+}
+
+// notImplemented is a handler that replies to any request with an HTTP 501 Not
+// Implemented status and a JSON error with the provided message msg.
+//
+// TODO(a.garipov): Either take the logger from the server after we've
+// refactored logging or make this not a method of *Server.
+func (s *server) notImplemented(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusNotImplemented)
+
+ err := json.NewEncoder(w).Encode(&jsonError{
+ Message: aghos.Unsupported("dhcp").Error(),
+ })
+ if err != nil {
+ log.Debug("writing 501 json response: %s", err)
+ }
+}
+
+// registerHandlers sets the handlers for DHCP HTTP API that always respond with
+// an HTTP 501, since DHCP server doesn't work on Windows yet.
+//
+// TODO(a.garipov): This needs refactoring. We shouldn't even try and
+// initialize a DHCP server on Windows, but there are currently too many
+// interconnected parts--such as HTTP handlers and frontend--to make that work
+// properly.
+func (s *server) registerHandlers() {
+ s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/status", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodGet, "/control/dhcp/interfaces", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/set_config", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/find_active_dhcp", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/add_static_lease", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/remove_static_lease", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset", s.notImplemented)
+ s.conf.HTTPRegister(http.MethodPost, "/control/dhcp/reset_leases", s.notImplemented)
+}
diff --git a/internal/dhcpd/http_test.go b/internal/dhcpd/http_windows_test.go
similarity index 60%
rename from internal/dhcpd/http_test.go
rename to internal/dhcpd/http_windows_test.go
index 120e02a3..12b9d7d9 100644
--- a/internal/dhcpd/http_test.go
+++ b/internal/dhcpd/http_windows_test.go
@@ -1,23 +1,28 @@
+//go:build windows
+
package dhcpd
import (
+ "fmt"
"net/http"
"net/http/httptest"
"testing"
+ "github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestServer_notImplemented(t *testing.T) {
- s := &Server{}
- h := s.notImplemented("never!")
+ s := &server{}
w := httptest.NewRecorder()
r, err := http.NewRequest(http.MethodGet, "/unsupported", nil)
require.NoError(t, err)
- h(w, r)
+ s.notImplemented(w, r)
assert.Equal(t, http.StatusNotImplemented, w.Code)
- assert.Equal(t, `{"message":"never!"}`+"\n", w.Body.String())
+
+ wantStr := fmt.Sprintf("{%q:%q}", "message", aghos.Unsupported("dhcp"))
+ assert.JSONEq(t, wantStr, w.Body.String())
}
diff --git a/internal/dhcpd/options_unix.go b/internal/dhcpd/options_unix.go
index dc06c429..6950604d 100644
--- a/internal/dhcpd/options_unix.go
+++ b/internal/dhcpd/options_unix.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
@@ -197,10 +196,10 @@ func parseDHCPOption(s string) (code dhcpv4.OptionCode, val dhcpv4.OptionValue,
// prepareOptions builds the set of DHCP options according to host requirements
// document and values from conf.
-func prepareOptions(conf V4ServerConf) (implicit, explicit dhcpv4.Options) {
+func (s *v4Server) prepareOptions() {
// Set default values of host configuration parameters listed in Appendix A
// of RFC-2131.
- implicit = dhcpv4.OptionsFromList(
+ s.implicitOpts = dhcpv4.OptionsFromList(
// IP-Layer Per Host
// An Internet host that includes embedded gateway code MUST have a
@@ -376,14 +375,14 @@ func prepareOptions(conf V4ServerConf) (implicit, explicit dhcpv4.Options) {
// Set the Router Option to working subnet's IP since it's initialized
// with the address of the gateway.
- dhcpv4.OptRouter(conf.subnet.IP),
+ dhcpv4.OptRouter(s.conf.subnet.IP),
- dhcpv4.OptSubnetMask(conf.subnet.Mask),
+ dhcpv4.OptSubnetMask(s.conf.subnet.Mask),
)
// Set values for explicitly configured options.
- explicit = dhcpv4.Options{}
- for i, o := range conf.Options {
+ s.explicitOpts = dhcpv4.Options{}
+ for i, o := range s.conf.Options {
code, val, err := parseDHCPOption(o)
if err != nil {
log.Error("dhcpv4: bad option string at index %d: %s", i, err)
@@ -391,17 +390,15 @@ func prepareOptions(conf V4ServerConf) (implicit, explicit dhcpv4.Options) {
continue
}
- explicit.Update(dhcpv4.Option{Code: code, Value: val})
+ s.explicitOpts.Update(dhcpv4.Option{Code: code, Value: val})
// Remove those from the implicit options.
- delete(implicit, code.Code())
+ delete(s.implicitOpts, code.Code())
}
- log.Debug("dhcpv4: implicit options:\n%s", implicit.Summary(nil))
- log.Debug("dhcpv4: explicit options:\n%s", explicit.Summary(nil))
+ log.Debug("dhcpv4: implicit options:\n%s", s.implicitOpts.Summary(nil))
+ log.Debug("dhcpv4: explicit options:\n%s", s.explicitOpts.Summary(nil))
- if len(explicit) == 0 {
- explicit = nil
+ if len(s.explicitOpts) == 0 {
+ s.explicitOpts = nil
}
-
- return implicit, explicit
}
diff --git a/internal/dhcpd/options_unix_test.go b/internal/dhcpd/options_unix_test.go
index e901284c..2b5a5cb0 100644
--- a/internal/dhcpd/options_unix_test.go
+++ b/internal/dhcpd/options_unix_test.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
@@ -250,17 +249,21 @@ func TestPrepareOptions(t *testing.T) {
}}
for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- implicit, explicit := prepareOptions(V4ServerConf{
+ s := &v4Server{
+ conf: &V4ServerConf{
// Just to avoid nil pointer dereference.
subnet: &net.IPNet{},
Options: tc.opts,
- })
+ },
+ }
- assert.Equal(t, tc.wantExplicit, explicit)
+ t.Run(tc.name, func(t *testing.T) {
+ s.prepareOptions()
- for c := range explicit {
- assert.NotContains(t, implicit, c)
+ assert.Equal(t, tc.wantExplicit, s.explicitOpts)
+
+ for c := range s.explicitOpts {
+ assert.NotContains(t, s.implicitOpts, c)
}
})
}
diff --git a/internal/dhcpd/os_windows.go b/internal/dhcpd/os_windows.go
index 33e5592b..ae016cfc 100644
--- a/internal/dhcpd/os_windows.go
+++ b/internal/dhcpd/os_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package dhcpd
diff --git a/internal/dhcpd/v46.go b/internal/dhcpd/v46.go
deleted file mode 100644
index 5e44eca3..00000000
--- a/internal/dhcpd/v46.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package dhcpd
-
-import (
- "time"
-)
-
-// Currently used defaults for ifaceDNSAddrs.
-const (
- defaultMaxAttempts int = 10
-
- defaultBackoff time.Duration = 500 * time.Millisecond
-)
diff --git a/internal/dhcpd/v46_windows.go b/internal/dhcpd/v46_windows.go
index 7f2c4121..624ec767 100644
--- a/internal/dhcpd/v46_windows.go
+++ b/internal/dhcpd/v46_windows.go
@@ -1,5 +1,4 @@
//go:build windows
-// +build windows
package dhcpd
@@ -9,15 +8,19 @@ import "net"
type winServer struct{}
-func (s *winServer) ResetLeases(_ []*Lease) (err error) { return nil }
-func (s *winServer) GetLeases(_ GetLeasesFlags) (leases []*Lease) { return nil }
-func (s *winServer) getLeasesRef() []*Lease { return nil }
-func (s *winServer) AddStaticLease(_ *Lease) (err error) { return nil }
-func (s *winServer) RemoveStaticLease(_ *Lease) (err error) { return nil }
-func (s *winServer) FindMACbyIP(ip net.IP) (mac net.HardwareAddr) { return nil }
-func (s *winServer) WriteDiskConfig4(c *V4ServerConf) {}
-func (s *winServer) WriteDiskConfig6(c *V6ServerConf) {}
-func (s *winServer) Start() (err error) { return nil }
-func (s *winServer) Stop() (err error) { return nil }
-func v4Create(conf V4ServerConf) (DHCPServer, error) { return &winServer{}, nil }
-func v6Create(conf V6ServerConf) (DHCPServer, error) { return &winServer{}, nil }
+// type check
+var _ DHCPServer = winServer{}
+
+func (winServer) ResetLeases(_ []*Lease) (err error) { return nil }
+func (winServer) GetLeases(_ GetLeasesFlags) (leases []*Lease) { return nil }
+func (winServer) getLeasesRef() []*Lease { return nil }
+func (winServer) AddStaticLease(_ *Lease) (err error) { return nil }
+func (winServer) RemoveStaticLease(_ *Lease) (err error) { return nil }
+func (winServer) FindMACbyIP(_ net.IP) (mac net.HardwareAddr) { return nil }
+func (winServer) WriteDiskConfig4(_ *V4ServerConf) {}
+func (winServer) WriteDiskConfig6(_ *V6ServerConf) {}
+func (winServer) Start() (err error) { return nil }
+func (winServer) Stop() (err error) { return nil }
+
+func v4Create(_ *V4ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
+func v6Create(_ V6ServerConf) (s DHCPServer, err error) { return winServer{}, nil }
diff --git a/internal/dhcpd/v4.go b/internal/dhcpd/v4_unix.go
similarity index 92%
rename from internal/dhcpd/v4.go
rename to internal/dhcpd/v4_unix.go
index 4d6c817b..3735ffdc 100644
--- a/internal/dhcpd/v4.go
+++ b/internal/dhcpd/v4_unix.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
@@ -30,8 +29,9 @@ import (
//
// TODO(a.garipov): Think about unifying this and v6Server.
type v4Server struct {
- conf V4ServerConf
- srv *server4.Server
+ conf *V4ServerConf
+
+ srv *server4.Server
// implicitOpts are the options listed in Appendix A of RFC 2131 initialized
// with default values. It must not have intersections with [explicitOpts].
@@ -55,9 +55,15 @@ type v4Server struct {
leases []*Lease
}
+func (s *v4Server) enabled() (ok bool) {
+ return s.conf != nil && s.conf.Enabled
+}
+
// WriteDiskConfig4 - write configuration
func (s *v4Server) WriteDiskConfig4(c *V4ServerConf) {
- *c = s.conf
+ if s.conf != nil {
+ *c = *s.conf
+ }
}
// WriteDiskConfig6 - write configuration
@@ -114,8 +120,8 @@ func (s *v4Server) validHostnameForClient(cliHostname string, ip net.IP) (hostna
func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
- if !s.conf.Enabled {
- return
+ if s.conf == nil {
+ return nil
}
s.leasedOffsets = newBitSet()
@@ -129,12 +135,7 @@ func (s *v4Server) ResetLeases(leases []*Lease) (err error) {
err = s.addLease(l)
if err != nil {
// TODO(a.garipov): Wrap and bubble up the error.
- log.Error(
- "dhcpv4: reset: re-adding a lease for %s (%s): %s",
- l.IP,
- l.HWAddr,
- err,
- )
+ log.Error("dhcpv4: reset: re-adding a lease for %s (%s): %s", l.IP, l.HWAddr, err)
continue
}
@@ -336,11 +337,19 @@ func (s *v4Server) rmLease(lease *Lease) (err error) {
return errors.Error("lease not found")
}
+// ErrUnconfigured is returned from the server's method when it requires the
+// server to be configured and it's not.
+const ErrUnconfigured errors.Error = "server is unconfigured"
+
// AddStaticLease implements the DHCPServer interface for *v4Server. It is safe
// for concurrent use.
func (s *v4Server) AddStaticLease(l *Lease) (err error) {
defer func() { err = errors.Annotate(err, "dhcpv4: adding static lease: %w") }()
+ if s.conf == nil {
+ return ErrUnconfigured
+ }
+
ip := l.IP.To4()
if ip == nil {
return fmt.Errorf("invalid ip %q, only ipv4 is supported", l.IP)
@@ -414,6 +423,10 @@ func (s *v4Server) AddStaticLease(l *Lease) (err error) {
func (s *v4Server) RemoveStaticLease(l *Lease) (err error) {
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
+ if s.conf == nil {
+ return ErrUnconfigured
+ }
+
if len(l.IP) != 4 {
return fmt.Errorf("invalid IP")
}
@@ -1086,12 +1099,6 @@ func (s *v4Server) packetHandler(conn net.PacketConn, peer net.Addr, req *dhcpv4
s.send(peer, conn, req, resp)
}
-// minDHCPMsgSize is the minimum length of the encoded DHCP message in bytes
-// according to RFC-2131.
-//
-// See https://datatracker.ietf.org/doc/html/rfc2131#section-2.
-const minDHCPMsgSize = 576
-
// send writes resp for peer to conn considering the req's parameters according
// to RFC-2131.
//
@@ -1133,16 +1140,6 @@ func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DH
}
pktData := resp.ToBytes()
- pktLen := len(pktData)
- if pktLen < minDHCPMsgSize {
- // Expand the packet to match the minimum DHCP message length. Although
- // the dhpcv4 package deals with the BOOTP's lower packet length
- // constraint, it seems some clients expecting the length being at least
- // 576 bytes as per RFC 2131 (and an obsolete RFC 1533).
- //
- // See https://github.com/AdguardTeam/AdGuardHome/issues/4337.
- pktData = append(pktData, make([]byte, minDHCPMsgSize-pktLen)...)
- }
log.Debug("dhcpv4: sending %d bytes to %s: %s", len(pktData), peer, resp.Summary())
@@ -1156,7 +1153,7 @@ func (s *v4Server) send(peer net.Addr, conn net.PacketConn, req, resp *dhcpv4.DH
func (s *v4Server) Start() (err error) {
defer func() { err = errors.Annotate(err, "dhcpv4: %w") }()
- if !s.conf.Enabled {
+ if !s.enabled() {
return nil
}
@@ -1248,62 +1245,20 @@ func (s *v4Server) Stop() (err error) {
}
// Create DHCPv4 server
-func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
- s := &v4Server{}
- s.conf = conf
- s.leaseHosts = stringutil.NewSet()
-
- // TODO(a.garipov): Don't use a disabled server in other places or just
- // use an interface.
- if !conf.Enabled {
- return s, nil
+func v4Create(conf *V4ServerConf) (srv *v4Server, err error) {
+ s := &v4Server{
+ leaseHosts: stringutil.NewSet(),
}
- var routerIP net.IP
- routerIP, err = tryTo4(s.conf.GatewayIP)
+ err = conf.Validate()
if err != nil {
- return s, fmt.Errorf("dhcpv4: %w", err)
+ // TODO(a.garipov): Don't use a disabled server in other places or just
+ // use an interface.
+ return s, err
}
- if s.conf.SubnetMask == nil {
- return s, fmt.Errorf("dhcpv4: invalid subnet mask: %v", s.conf.SubnetMask)
- }
-
- subnetMask := make([]byte, 4)
- copy(subnetMask, s.conf.SubnetMask.To4())
-
- s.conf.subnet = &net.IPNet{
- IP: routerIP,
- Mask: subnetMask,
- }
- s.conf.broadcastIP = aghnet.BroadcastFromIPNet(s.conf.subnet)
-
- s.conf.ipRange, err = newIPRange(conf.RangeStart, conf.RangeEnd)
- if err != nil {
- return s, fmt.Errorf("dhcpv4: %w", err)
- }
-
- if s.conf.ipRange.contains(routerIP) {
- return s, fmt.Errorf("dhcpv4: gateway ip %v in the ip range: %v-%v",
- routerIP,
- conf.RangeStart,
- conf.RangeEnd,
- )
- }
-
- if !s.conf.subnet.Contains(conf.RangeStart) {
- return s, fmt.Errorf("dhcpv4: range start %v is outside network %v",
- conf.RangeStart,
- s.conf.subnet,
- )
- }
-
- if !s.conf.subnet.Contains(conf.RangeEnd) {
- return s, fmt.Errorf("dhcpv4: range end %v is outside network %v",
- conf.RangeEnd,
- s.conf.subnet,
- )
- }
+ s.conf = &V4ServerConf{}
+ *s.conf = *conf
// TODO(a.garipov, d.seregin): Check that every lease is inside the IPRange.
s.leasedOffsets = newBitSet()
@@ -1315,7 +1270,7 @@ func v4Create(conf V4ServerConf) (srv DHCPServer, err error) {
s.conf.leaseTime = time.Second * time.Duration(conf.LeaseDuration)
}
- s.implicitOpts, s.explicitOpts = prepareOptions(s.conf)
+ s.prepareOptions()
return s, nil
}
diff --git a/internal/dhcpd/v4_test.go b/internal/dhcpd/v4_unix_test.go
similarity index 97%
rename from internal/dhcpd/v4_test.go
rename to internal/dhcpd/v4_unix_test.go
index 6d8f513e..c73009a2 100644
--- a/internal/dhcpd/v4_test.go
+++ b/internal/dhcpd/v4_unix_test.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
@@ -30,19 +29,16 @@ var (
DefaultSubnetMask = net.IP{255, 255, 255, 0}
)
-func notify4(flags uint32) {
-}
-
// defaultV4ServerConf returns the default configuration for *v4Server to use in
// tests.
-func defaultV4ServerConf() (conf V4ServerConf) {
- return V4ServerConf{
+func defaultV4ServerConf() (conf *V4ServerConf) {
+ return &V4ServerConf{
Enabled: true,
RangeStart: DefaultRangeStart,
RangeEnd: DefaultRangeEnd,
GatewayIP: DefaultGatewayIP,
SubnetMask: DefaultSubnetMask,
- notify: notify4,
+ notify: testNotify,
dnsIPAddrs: []net.IP{DefaultSelfIP},
}
}
@@ -350,13 +346,10 @@ func TestV4Server_handle_optionsPriority(t *testing.T) {
defer func() { s.implicitOpts.Update(dhcpv4.OptDNS(defaultIP)) }()
}
- ss, err := v4Create(conf)
+ var err error
+ s, err = v4Create(conf)
require.NoError(t, err)
- var ok bool
- s, ok = ss.(*v4Server)
- require.True(t, ok)
-
s.conf.dnsIPAddrs = []net.IP{defaultIP}
return s
@@ -490,10 +483,9 @@ func TestV4Server_updateOptions(t *testing.T) {
require.NoError(t, err)
require.IsType(t, (*v4Server)(nil), s)
- s4, _ := s.(*v4Server)
t.Run(tc.name, func(t *testing.T) {
- s4.updateOptions(req, resp)
+ s.updateOptions(req, resp)
for c, v := range tc.wantOpts {
if v == nil {
@@ -596,13 +588,9 @@ func TestV4DynamicLease_Get(t *testing.T) {
"82 ip 1.2.3.4",
}
- var err error
- sIface, err := v4Create(conf)
+ s, err := v4Create(conf)
require.NoError(t, err)
- s, ok := sIface.(*v4Server)
- require.True(t, ok)
-
s.conf.dnsIPAddrs = []net.IP{{192, 168, 10, 1}}
s.implicitOpts.Update(dhcpv4.OptDNS(s.conf.dnsIPAddrs...))
diff --git a/internal/dhcpd/v6.go b/internal/dhcpd/v6_unix.go
similarity index 98%
rename from internal/dhcpd/v6.go
rename to internal/dhcpd/v6_unix.go
index b483384d..96512ddb 100644
--- a/internal/dhcpd/v6.go
+++ b/internal/dhcpd/v6_unix.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
@@ -173,7 +172,7 @@ func (s *v6Server) rmDynamicLease(lease *Lease) (err error) {
func (s *v6Server) AddStaticLease(l *Lease) (err error) {
defer func() { err = errors.Annotate(err, "dhcpv6: %w") }()
- if len(l.IP) != 16 {
+ if len(l.IP) != net.IPv6len {
return fmt.Errorf("invalid IP")
}
diff --git a/internal/dhcpd/v6_test.go b/internal/dhcpd/v6_unix_test.go
similarity index 97%
rename from internal/dhcpd/v6_test.go
rename to internal/dhcpd/v6_unix_test.go
index 794b98e4..201f62a6 100644
--- a/internal/dhcpd/v6_test.go
+++ b/internal/dhcpd/v6_unix_test.go
@@ -1,5 +1,4 @@
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
-// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+//go:build darwin || freebsd || linux || openbsd
package dhcpd
diff --git a/internal/dnsforward/config.go b/internal/dnsforward/config.go
index e579e97a..8e2912bc 100644
--- a/internal/dnsforward/config.go
+++ b/internal/dnsforward/config.go
@@ -127,9 +127,14 @@ type FilteringConfig struct {
// IpsetList is the ipset configuration that allows AdGuard Home to add
// IP addresses of the specified domain names to an ipset list. Syntax:
//
- // DOMAIN[,DOMAIN].../IPSET_NAME
+ // DOMAIN[,DOMAIN].../IPSET_NAME
//
+ // This field is ignored if [IpsetListFileName] is set.
IpsetList []string `yaml:"ipset"`
+
+ // IpsetListFileName, if set, points to the file with ipset configuration.
+ // The format is the same as in [IpsetList].
+ IpsetListFileName string `yaml:"ipset_file"`
}
// TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS
@@ -399,6 +404,26 @@ func setProxyUpstreamMode(
}
}
+// prepareIpsetListSettings reads and prepares the ipset configuration either
+// from a file or from the data in the configuration file.
+func (s *Server) prepareIpsetListSettings() (err error) {
+ fn := s.conf.IpsetListFileName
+ if fn == "" {
+ return s.ipset.init(s.conf.IpsetList)
+ }
+
+ data, err := os.ReadFile(fn)
+ if err != nil {
+ return err
+ }
+
+ ipsets := stringutil.SplitTrimmed(string(data), "\n")
+
+ log.Debug("dns: using %d ipset rules from file %q", len(ipsets), fn)
+
+ return s.ipset.init(ipsets)
+}
+
// prepareTLS - prepares TLS configuration for the DNS proxy
func (s *Server) prepareTLS(proxyConfig *proxy.Config) error {
if len(s.conf.CertificateChainData) == 0 || len(s.conf.PrivateKeyData) == 0 {
diff --git a/internal/dnsforward/dns_test.go b/internal/dnsforward/dns_test.go
index 218edb1a..ebdc716c 100644
--- a/internal/dnsforward/dns_test.go
+++ b/internal/dnsforward/dns_test.go
@@ -267,7 +267,7 @@ func TestServer_ProcessDHCPHosts_localRestriction(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
s := &Server{
- dhcpServer: &testDHCP{},
+ dhcpServer: testDHCP,
localDomainSuffix: defaultLocalDomainSuffix,
tableHostToIP: hostToIPTable{
"example." + defaultLocalDomainSuffix: knownIP,
@@ -378,7 +378,7 @@ func TestServer_ProcessDHCPHosts(t *testing.T) {
for _, tc := range testCases {
s := &Server{
- dhcpServer: &testDHCP{},
+ dhcpServer: testDHCP,
localDomainSuffix: tc.suffix,
tableHostToIP: hostToIPTable{
"example." + tc.suffix: knownIP,
diff --git a/internal/dnsforward/dnsforward.go b/internal/dnsforward/dnsforward.go
index 33be1e83..3806ef5b 100644
--- a/internal/dnsforward/dnsforward.go
+++ b/internal/dnsforward/dnsforward.go
@@ -58,10 +58,10 @@ type hostToIPTable = map[string]net.IP
//
// The zero Server is empty and ready for use.
type Server struct {
- dnsProxy *proxy.Proxy // DNS proxy instance
- dnsFilter *filtering.DNSFilter // DNS filter instance
- dhcpServer dhcpd.ServerInterface // DHCP server instance (optional)
- queryLog querylog.QueryLog // Query log instance
+ dnsProxy *proxy.Proxy // DNS proxy instance
+ dnsFilter *filtering.DNSFilter // DNS filter instance
+ dhcpServer dhcpd.Interface // DHCP server instance (optional)
+ queryLog querylog.QueryLog // Query log instance
stats stats.Interface
access *accessCtx
@@ -110,7 +110,7 @@ type DNSCreateParams struct {
DNSFilter *filtering.DNSFilter
Stats stats.Interface
QueryLog querylog.QueryLog
- DHCPServer dhcpd.ServerInterface
+ DHCPServer dhcpd.Interface
PrivateNets netutil.SubnetSet
Anonymizer *aghnet.IPMut
LocalDomain string
@@ -446,10 +446,10 @@ func (s *Server) Prepare(conf *ServerConfig) (err error) {
s.initDefaultSettings()
- err = s.ipset.init(s.conf.IpsetList)
+ err = s.prepareIpsetListSettings()
if err != nil {
// Don't wrap the error, because it's informative enough as is.
- return err
+ return fmt.Errorf("preparing ipset settings: %w", err)
}
err = s.prepareUpstreamSettings()
diff --git a/internal/dnsforward/dnsforward_test.go b/internal/dnsforward/dnsforward_test.go
index a76d5a41..b11d1f65 100644
--- a/internal/dnsforward/dnsforward_test.go
+++ b/internal/dnsforward/dnsforward_test.go
@@ -72,7 +72,7 @@ func createTestServer(
var err error
s, err = NewServer(DNSCreateParams{
- DHCPServer: &testDHCP{},
+ DHCPServer: testDHCP,
DNSFilter: f,
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
})
@@ -776,7 +776,7 @@ func TestBlockedCustomIP(t *testing.T) {
f := filtering.New(&filtering.Config{}, filters)
s, err := NewServer(DNSCreateParams{
- DHCPServer: &testDHCP{},
+ DHCPServer: testDHCP,
DNSFilter: f,
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
})
@@ -910,7 +910,7 @@ func TestRewrite(t *testing.T) {
f.SetEnabled(true)
s, err := NewServer(DNSCreateParams{
- DHCPServer: &testDHCP{},
+ DHCPServer: testDHCP,
DNSFilter: f,
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
})
@@ -1005,26 +1005,36 @@ func publicKey(priv any) any {
}
}
-type testDHCP struct{}
-
-func (d *testDHCP) Enabled() (ok bool) { return true }
-
-func (d *testDHCP) Leases(flags dhcpd.GetLeasesFlags) (leases []*dhcpd.Lease) {
- return []*dhcpd.Lease{{
- IP: net.IP{192, 168, 12, 34},
- HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
- Hostname: "myhost",
- }}
+var testDHCP = &dhcpd.MockInterface{
+ OnStart: func() (err error) { panic("not implemented") },
+ OnStop: func() (err error) { panic("not implemented") },
+ OnEnabled: func() (ok bool) { return true },
+ OnLeases: func(flags dhcpd.GetLeasesFlags) (leases []*dhcpd.Lease) {
+ return []*dhcpd.Lease{{
+ IP: net.IP{192, 168, 12, 34},
+ HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
+ Hostname: "myhost",
+ }}
+ },
+ OnSetOnLeaseChanged: func(olct dhcpd.OnLeaseChangedT) {},
+ OnFindMACbyIP: func(ip net.IP) (mac net.HardwareAddr) { panic("not implemented") },
+ OnWriteDiskConfig: func(c *dhcpd.ServerConfig) { panic("not implemented") },
}
-func (d *testDHCP) SetOnLeaseChanged(onLeaseChanged dhcpd.OnLeaseChangedT) {}
+// func (*testDHCP) Leases(flags dhcpd.GetLeasesFlags) (leases []*dhcpd.Lease) {
+// return []*dhcpd.Lease{{
+// IP: net.IP{192, 168, 12, 34},
+// HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
+// Hostname: "myhost",
+// }}
+// }
func TestPTRResponseFromDHCPLeases(t *testing.T) {
const localDomain = "lan"
s, err := NewServer(DNSCreateParams{
DNSFilter: filtering.New(&filtering.Config{}, nil),
- DHCPServer: &testDHCP{},
+ DHCPServer: testDHCP,
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
LocalDomain: localDomain,
})
@@ -1097,7 +1107,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
var s *Server
s, err = NewServer(DNSCreateParams{
- DHCPServer: &testDHCP{},
+ DHCPServer: testDHCP,
DNSFilter: flt,
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
})
diff --git a/internal/dnsforward/filter_test.go b/internal/dnsforward/filter_test.go
index e25d4037..00c04252 100644
--- a/internal/dnsforward/filter_test.go
+++ b/internal/dnsforward/filter_test.go
@@ -39,7 +39,7 @@ func TestHandleDNSRequest_filterDNSResponse(t *testing.T) {
f.SetEnabled(true)
s, err := NewServer(DNSCreateParams{
- DHCPServer: &testDHCP{},
+ DHCPServer: testDHCP,
DNSFilter: f,
PrivateNets: netutil.SubnetSetFunc(netutil.IsLocallyServed),
})
diff --git a/internal/home/clients.go b/internal/home/clients.go
index e50b7904..7396e8c6 100644
--- a/internal/home/clients.go
+++ b/internal/home/clients.go
@@ -126,7 +126,7 @@ type clientsContainer struct {
allTags *stringutil.Set
// dhcpServer is used for looking up clients IP addresses by MAC addresses
- dhcpServer *dhcpd.Server
+ dhcpServer dhcpd.Interface
// dnsServer is used for checking clients IP status access list status
dnsServer *dnsforward.Server
@@ -146,7 +146,7 @@ type clientsContainer struct {
// Note: this function must be called only once
func (clients *clientsContainer) Init(
objects []*clientObject,
- dhcpServer *dhcpd.Server,
+ dhcpServer dhcpd.Interface,
etcHosts *aghnet.HostsContainer,
arpdb aghnet.ARPDB,
) {
diff --git a/internal/home/clients_test.go b/internal/home/clients_test.go
index 8afd5621..5b4ccdd3 100644
--- a/internal/home/clients_test.go
+++ b/internal/home/clients_test.go
@@ -279,8 +279,6 @@ func TestClientsAddExisting(t *testing.T) {
t.Skip("skipping dhcp test on windows")
}
- var err error
-
ip := net.IP{1, 2, 3, 4}
// First, init a DHCP server with a single static lease.
@@ -296,13 +294,15 @@ func TestClientsAddExisting(t *testing.T) {
},
}
- clients.dhcpServer, err = dhcpd.Create(config)
+ dhcpServer, err := dhcpd.Create(config)
require.NoError(t, err)
testutil.CleanupAndRequireSuccess(t, func() (err error) {
return os.Remove("leases.db")
})
- err = clients.dhcpServer.AddStaticLease(&dhcpd.Lease{
+ clients.dhcpServer = dhcpServer
+
+ err = dhcpServer.AddStaticLease(&dhcpd.Lease{
HWAddr: net.HardwareAddr{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA},
IP: ip,
Hostname: "testhost",
diff --git a/internal/home/config.go b/internal/home/config.go
index 7ac6470e..47027692 100644
--- a/internal/home/config.go
+++ b/internal/home/config.go
@@ -433,9 +433,7 @@ func (c *configuration) write() (err error) {
}
if Context.dhcpServer != nil {
- c := &dhcpd.ServerConfig{}
- Context.dhcpServer.WriteDiskConfig(c)
- config.DHCP = c
+ Context.dhcpServer.WriteDiskConfig(config.DHCP)
}
config.Clients.Persistent = Context.clients.forConfig()
diff --git a/internal/home/home.go b/internal/home/home.go
index 4eb71494..7c6c6e0a 100644
--- a/internal/home/home.go
+++ b/internal/home/home.go
@@ -52,7 +52,7 @@ type homeContext struct {
rdns *RDNS // rDNS module
whois *WHOIS // WHOIS module
dnsFilter *filtering.DNSFilter // DNS filtering module
- dhcpServer *dhcpd.Server // DHCP module
+ dhcpServer dhcpd.Interface // DHCP module
auth *Auth // HTTP authentication module
filters Filtering // DNS filtering module
web *Web // Web (HTTP, HTTPS) module
@@ -641,14 +641,9 @@ func configureLogger(args options) {
log.Fatalf("cannot initialize syslog: %s", err)
}
} else {
- logFilePath := filepath.Join(Context.workDir, ls.File)
- if filepath.IsAbs(ls.File) {
- logFilePath = ls.File
- }
-
- _, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o644)
- if err != nil {
- log.Fatalf("cannot create a log file: %s", err)
+ logFilePath := ls.File
+ if !filepath.IsAbs(logFilePath) {
+ logFilePath = filepath.Join(Context.workDir, logFilePath)
}
log.SetOutput(&lumberjack.Logger{
diff --git a/internal/home/service_linux.go b/internal/home/service_linux.go
index c885529b..39d572a0 100644
--- a/internal/home/service_linux.go
+++ b/internal/home/service_linux.go
@@ -1,5 +1,4 @@
//go:build linux
-// +build linux
package home
diff --git a/internal/home/service_openbsd.go b/internal/home/service_openbsd.go
index beeabd04..071775b9 100644
--- a/internal/home/service_openbsd.go
+++ b/internal/home/service_openbsd.go
@@ -1,5 +1,4 @@
//go:build openbsd
-// +build openbsd
package home
diff --git a/internal/home/service_others.go b/internal/home/service_others.go
index 6e2afd10..1be34317 100644
--- a/internal/home/service_others.go
+++ b/internal/home/service_others.go
@@ -1,5 +1,4 @@
//go:build !(openbsd || linux)
-// +build !openbsd,!linux
package home
diff --git a/internal/tools/go.mod b/internal/tools/go.mod
index ed3ed977..c4f78914 100644
--- a/internal/tools/go.mod
+++ b/internal/tools/go.mod
@@ -10,7 +10,7 @@ require (
github.com/kyoh86/looppointer v0.1.7
github.com/securego/gosec/v2 v2.13.1
golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3
- golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39
+ golang.org/x/vuln v0.0.0-20220912202342-0ed43f12cb05
honnef.co/go/tools v0.3.3
mvdan.cc/gofumpt v0.3.1
mvdan.cc/unparam v0.0.0-20220831102321-2fc90a84c7ec
@@ -25,10 +25,10 @@ require (
github.com/kyoh86/nolint v0.0.1 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
- golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
+ golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 // indirect
golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect
- golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 // indirect
+ golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/internal/tools/go.sum b/internal/tools/go.sum
index 0f43bb9f..367d3d53 100644
--- a/internal/tools/go.sum
+++ b/internal/tools/go.sum
@@ -55,8 +55,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
-golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
+golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
+golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 h1:Ic/qN6TEifvObMGQy72k0n1LlJr7DjWWEi+MOsDOiSk=
golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -86,8 +86,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77 h1:C1tElbkWrsSkn3IRl1GCW/gETw1TywWIPgwZtXTZbYg=
-golang.org/x/sys v0.0.0-20220906135438-9e1f76180b77/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho=
+golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -102,8 +102,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3 h1:aE4T3aJwdCNz+s35ScSQYUzeGu7BOLDHZ1bBHVurqqY=
golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39 h1:501+NfNjDh4IT4HOzdeezTOFD7njtY49aXJN1oY3E1s=
-golang.org/x/vuln v0.0.0-20220902211423-27dd78d2ca39/go.mod h1:7tDfEDtOLlzHQRi4Yzfg5seVBSvouUIjyPzBx4q5CxQ=
+golang.org/x/vuln v0.0.0-20220912202342-0ed43f12cb05 h1:NWQHMTdThZhCArzUbnu1Bh+l3LdwUfjZws+ivBR2sxM=
+golang.org/x/vuln v0.0.0-20220912202342-0ed43f12cb05/go.mod h1:7tDfEDtOLlzHQRi4Yzfg5seVBSvouUIjyPzBx4q5CxQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/version/norace.go b/internal/version/norace.go
index 38dec06f..326d32cc 100644
--- a/internal/version/norace.go
+++ b/internal/version/norace.go
@@ -1,5 +1,4 @@
//go:build !race
-// +build !race
package version
diff --git a/internal/version/race.go b/internal/version/race.go
index eb1c73a5..4a1ae92d 100644
--- a/internal/version/race.go
+++ b/internal/version/race.go
@@ -1,5 +1,4 @@
//go:build race
-// +build race
package version
diff --git a/openapi/CHANGELOG.md b/openapi/CHANGELOG.md
index 1e2852be..fbbe7169 100644
--- a/openapi/CHANGELOG.md
+++ b/openapi/CHANGELOG.md
@@ -4,6 +4,15 @@
## v0.108.0: API changes
+## v0.107.12: API changes
+
+### `GET /control/blocked_services/services`
+
+* The new `GET /control/blocked_services/services` HTTP API allows inspecting
+ all available services.
+
+## v0.107.7: API changes
+
### The new optional field `"ecs"` in `QueryLogItem`
* The new optional field `"ecs"` in `GET /control/querylog` contains the IP
diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml
index eb7b1894..ad57d807 100644
--- a/openapi/openapi.yaml
+++ b/openapi/openapi.yaml
@@ -874,6 +874,19 @@
'summary': 'Set (dis)allowed clients, blocked hosts, etc.'
'tags':
- 'clients'
+ '/blocked_services/services':
+ 'get':
+ 'tags':
+ - 'blocked_services'
+ 'operationId': 'blockedServicesAvailableServices'
+ 'summary': 'Get available services to use for blocking'
+ 'responses':
+ '200':
+ 'description': 'OK.'
+ 'content':
+ 'application/json':
+ 'schema':
+ '$ref': '#/components/schemas/BlockedServicesArray'
'/blocked_services/list':
'get':
'tags':
diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh
index 17ac9457..4cf24b5b 100644
--- a/scripts/make/go-lint.sh
+++ b/scripts/make/go-lint.sh
@@ -218,7 +218,10 @@ exit_on_output gofumpt --extra -e -l .
"$GO" vet ./...
-govulncheck ./...
+# TODO(a.garipov): Reenable this once https://github.com/golang/go/issues/55035
+# is fixed.
+#
+# govulncheck ./...
# Apply more lax standards to the code we haven't properly refactored yet.
gocyclo --over 17 ./internal/querylog/