From 77d04d44eb080500f79e1329f943decb976d1817 Mon Sep 17 00:00:00 2001 From: Ainar Garipov Date: Wed, 14 Sep 2022 16:36:29 +0300 Subject: [PATCH] all: sync with master --- .github/workflows/build.yml | 10 +- .github/workflows/lint.yml | 8 +- CHANGELOG.md | 38 +++- client/src/__locales/be.json | 4 +- client/src/__locales/uk.json | 2 +- internal/aghnet/arpdb_bsd.go | 1 - internal/aghnet/arpdb_bsd_test.go | 1 - internal/aghnet/arpdb_linux.go | 1 - internal/aghnet/arpdb_linux_test.go | 1 - internal/aghnet/arpdb_openbsd.go | 1 - internal/aghnet/arpdb_openbsd_test.go | 1 - internal/aghnet/arpdb_windows.go | 1 - internal/aghnet/arpdb_windows_test.go | 1 - internal/aghnet/dhcp_unix.go | 3 +- internal/aghnet/dhcp_windows.go | 1 - internal/aghnet/hostscontainer_linux.go | 1 - internal/aghnet/hostscontainer_others.go | 1 - internal/aghnet/hostscontainer_windows.go | 1 - internal/aghnet/interfaces_linux.go | 1 - internal/aghnet/interfaces_unix.go | 3 +- internal/aghnet/interfaces_windows.go | 1 - internal/aghnet/ipset_linux.go | 1 - internal/aghnet/ipset_linux_test.go | 1 - internal/aghnet/ipset_others.go | 1 - internal/aghnet/net_bsd.go | 1 - internal/aghnet/net_darwin.go | 1 - internal/aghnet/net_freebsd.go | 1 - internal/aghnet/net_freebsd_test.go | 1 - internal/aghnet/net_linux.go | 1 - internal/aghnet/net_linux_test.go | 1 - internal/aghnet/net_openbsd.go | 1 - internal/aghnet/net_openbsd_test.go | 1 - internal/aghnet/net_unix.go | 3 +- internal/aghnet/net_windows.go | 1 - internal/aghnet/systemresolvers_others.go | 1 - .../aghnet/systemresolvers_others_test.go | 1 - internal/aghnet/systemresolvers_windows.go | 1 - .../aghnet/systemresolvers_windows_test.go | 1 - internal/aghos/endian_big.go | 1 - internal/aghos/endian_little.go | 1 - internal/aghos/os_bsd.go | 3 +- internal/aghos/os_freebsd.go | 1 - internal/aghos/os_linux.go | 1 - internal/aghos/os_unix.go | 1 - internal/aghos/os_windows.go | 1 - internal/aghos/syslog_others.go | 3 +- internal/aghos/syslog_windows.go | 3 +- internal/aghos/user_unix.go | 3 +- internal/aghos/user_windows.go | 1 - internal/dhcpd/broadcast_bsd.go | 10 +- internal/dhcpd/broadcast_bsd_test.go | 1 - internal/dhcpd/broadcast_others.go | 3 +- internal/dhcpd/broadcast_others_test.go | 3 +- internal/dhcpd/{server.go => config.go} | 110 ++++++++++ internal/dhcpd/conn_unix.go | 3 +- internal/dhcpd/conn_unix_test.go | 3 +- internal/dhcpd/db.go | 4 +- internal/dhcpd/dhcpd.go | 191 ++++++++++-------- .../{dhcpd_test.go => dhcpd_unix_test.go} | 35 +--- internal/dhcpd/helpers.go | 36 ---- internal/dhcpd/{http.go => http_unix.go} | 144 +++++-------- internal/dhcpd/http_windows.go | 55 +++++ .../{http_test.go => http_windows_test.go} | 13 +- internal/dhcpd/options_unix.go | 29 ++- internal/dhcpd/options_unix_test.go | 19 +- internal/dhcpd/os_windows.go | 1 - internal/dhcpd/v46.go | 12 -- internal/dhcpd/v46_windows.go | 29 +-- internal/dhcpd/{v4.go => v4_unix.go} | 119 ++++------- .../dhcpd/{v4_test.go => v4_unix_test.go} | 28 +-- internal/dhcpd/{v6.go => v6_unix.go} | 5 +- .../dhcpd/{v6_test.go => v6_unix_test.go} | 3 +- internal/dnsforward/config.go | 27 ++- internal/dnsforward/dns_test.go | 4 +- internal/dnsforward/dnsforward.go | 14 +- internal/dnsforward/dnsforward_test.go | 42 ++-- internal/dnsforward/filter_test.go | 2 +- internal/home/clients.go | 4 +- internal/home/clients_test.go | 8 +- internal/home/config.go | 4 +- internal/home/home.go | 13 +- internal/home/service_linux.go | 1 - internal/home/service_openbsd.go | 1 - internal/home/service_others.go | 1 - internal/tools/go.mod | 6 +- internal/tools/go.sum | 12 +- internal/version/norace.go | 1 - internal/version/race.go | 1 - openapi/CHANGELOG.md | 9 + openapi/openapi.yaml | 13 ++ scripts/make/go-lint.sh | 5 +- 91 files changed, 591 insertions(+), 553 deletions(-) rename internal/dhcpd/{server.go => config.go} (55%) rename internal/dhcpd/{dhcpd_test.go => dhcpd_unix_test.go} (84%) delete mode 100644 internal/dhcpd/helpers.go rename internal/dhcpd/{http.go => http_unix.go} (78%) create mode 100644 internal/dhcpd/http_windows.go rename internal/dhcpd/{http_test.go => http_windows_test.go} (60%) delete mode 100644 internal/dhcpd/v46.go rename internal/dhcpd/{v4.go => v4_unix.go} (92%) rename internal/dhcpd/{v4_test.go => v4_unix_test.go} (97%) rename internal/dhcpd/{v6.go => v6_unix.go} (98%) rename internal/dhcpd/{v6_test.go => v6_unix_test.go} (97%) 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}}. Каб выкарыстоўваць DHCP-сервер трэба ўсталяваць статычны IP-адрас. Ваш бягучы IP-адрас – <0>{{ipAddress}}. Мы аўтаматычна ўсталюем яго як статычны, калі вы націснеце кнопку Ўключыць DHCP.", + "dhcp_dynamic_ip_found": "Ваша сістэма выкарыстоўвае дынамічны IP-адрас для інтэрфейсу <0>{{interfaceName}}. Каб выкарыстоўваць DHCP-сервер трэба ўсталяваць статычны IP-адрас. Ваш бягучы IP-адрас – <0>{{ipAddress}}. Мы аўтаматычна ўсталюем яго як статычны, калі вы націснеце кнопку «Ўключыць 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/