commit: 896802def8a7c3fc495cfd3c534bf773f1e17af7 Author: Rahil Bhimjiani <me <AT> rahil <DOT> rocks> AuthorDate: Thu Mar 13 07:37:55 2025 +0000 Commit: Rahil Bhimjiani <rahil3108 <AT> gmail <DOT> com> CommitDate: Thu Mar 13 07:38:33 2025 +0000 URL: https://gitweb.gentoo.org/repo/proj/guru.git/commit/?id=896802de
net-dns/blocky: remove 0.22 Signed-off-by: Rahil Bhimjiani <me <AT> rahil.rocks> net-dns/blocky/Manifest | 3 - net-dns/blocky/blocky-0.22.ebuild | 104 - .../blocky/files/disable-failed-tests-0.22.patch | 2272 -------------------- 3 files changed, 2379 deletions(-) diff --git a/net-dns/blocky/Manifest b/net-dns/blocky/Manifest index 7ad31430d..3bac1ddd7 100644 --- a/net-dns/blocky/Manifest +++ b/net-dns/blocky/Manifest @@ -1,6 +1,3 @@ -DIST blocky-0.22-deps.tar.xz 163869124 BLAKE2B e98614feaeb11604866d08003147871096c993cdb90c85bba46ea999a339570ca1500a80bddee202595372ec5d22baa6ec0345d8cf50ffee6d61dd8d6495d49f SHA512 883e5dd66cf974c6d8c73a94c7677d5003ceb7a3ba68001c2d9d36e1e4d1ea64f0818d30240fe77f192ad3f95ede93127bed9adc9647da07a9b9bebc958ffd33 -DIST blocky-0.22-docs.tar.gz 5639822 BLAKE2B e177790deb7493f84d8217661e4e4296004a9db7e00ff8d37dbd3c4ed8b7ba0a7cf431067c103f25784e46ca7a8bf80532cdd8f305f3e4ce119890027f0eb186 SHA512 3eed0ff726479826fbefb4140c36bb26825124134d1fbbecf74a31b2fbdde993630adc645ea2e582ce8d415736cc85b20f64a835c87da98700b715c03d368e75 -DIST blocky-0.22.tar.gz 712644 BLAKE2B d74881026421337a0fc32a6af2cf6bff736e0130ac599cd80714f0cafff1e81864e0327bc773f8377106421642cf545b76407fca94f07425c428ff8512a7113b SHA512 928ba882cb567f80b9b00c1ab74ba2fba0324b9e5fb6439789d50d8fd438a26f84772d36f91ef9c3a2351c798a399c15aa1b69927a2da11795edd576b7bae6a4 DIST blocky-0.23-deps.tar.xz 191529448 BLAKE2B fbad27f70b73832e0862b32267be0e9956c39c570f4e8d16be6a1b7eaa8ea779df52d1da533486d2b0d3e5b163602b62283ac006de4adc0861ec208fd9f50bd8 SHA512 89441e8082260b7c8a850b91029540554fc8af4bdba1996adb07ff57781c0e92ee439b915cd1473d16fba9bd31612b6c267c2fe6f96096a4f9ed4fa23d46165d DIST blocky-0.23-docs.tar.gz 6773940 BLAKE2B 8114e49c8c8b7c01a1376dd0ef15b5eee966fc18c84d8645aa91c3524876167de810a17d63f2e287a3fe4c56906076783e135cf0c209886870588f40190e9d78 SHA512 aec00c88ea97f7f2d145020e666f77f992b53cd8867d4d4c5bc5a094b06889c35d7019d0e491fe02fb1dd803912613ec7f874f4d7a9f0d06e41c7bb8c609d956 DIST blocky-0.23.tar.gz 7236537 BLAKE2B 4dd8b4a9587ed2b768ff2cf8809e14242032d7e8be3d3c422eb5518df33c32c0f767ba8e7490f353e81ede8c150cf3175621ea35ad3aa682f62c7d169c511b63 SHA512 22431da4c2f259411b7eb790e8f05a7264d0aa96fe4774722bbe71cf9459a3ed7f434b4b295c95b80f2efc6de55ff645f860443838fe793bc413d74b77e395be diff --git a/net-dns/blocky/blocky-0.22.ebuild b/net-dns/blocky/blocky-0.22.ebuild deleted file mode 100644 index 5b601c882..000000000 --- a/net-dns/blocky/blocky-0.22.ebuild +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 1999-2024 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -inherit fcaps go-module systemd shell-completion - -DESCRIPTION="Fast and lightweight DNS proxy as ad-blocker with many features written in Go" -HOMEPAGE="https://github.com/0xERR0R/blocky/" - -DOCUMENTATION_COMMIT=9c6a86eb163e758686c5d6d4d5259deb086a8aa9 - -if [[ ${PV} == 9999* ]]; then - inherit git-r3 - EGIT_REPO_URI="https://github.com/0xERR0R/blocky.git" -else - SRC_URI=" - https://github.com/0xERR0R/blocky/archive/v${PV}.tar.gz -> ${P}.tar.gz - https://github.com/rahilarious/gentoo-distfiles/releases/download/${P}/deps.tar.xz -> ${P}-deps.tar.xz - doc? ( https://github.com/0xERR0R/blocky/archive/${DOCUMENTATION_COMMIT}.tar.gz -> ${P}-docs.tar.gz ) -" - KEYWORDS="~amd64" -fi - -# main -LICENSE="Apache-2.0" -# deps -LICENSE+=" AGPL-3 BSD-2 BSD ISC MIT MPL-2.0" -SLOT="0" -IUSE="doc" - -# RESTRICT="test" - -RDEPEND=" - acct-user/blocky - acct-group/blocky -" - -PATCHES=( - "${FILESDIR}"/disable-failed-tests-0.22.patch -) - -FILECAPS=( - -m 755 'cap_net_bind_service=+ep' usr/bin/"${PN}" -) - -src_unpack() { - if [[ ${PV} == 9999* ]]; then - git-r3_src_unpack - go-module_live_vendor - if use doc; then - EGIT_BRANCH="gh-pages" - EGIT_CHECKOUT_DIR="${WORKDIR}/${P}-doc" - git-r3_src_unpack - fi - else - go-module_src_unpack - fi -} - -src_compile() { - [[ ${PV} != 9999* ]] && export VERSION="${PV}" - - # mimicking project's Dockerfile - emake GO_SKIP_GENERATE=yes GO_BUILD_FLAGS="-tags static -v " build - - local shell - for shell in bash fish zsh; do - bin/"${PN}" completion "${shell}" > "${PN}"."${shell}" || die - done -} - -src_test() { - # mimcking make test - ego run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --coverprofile=coverage.txt --covermode=atomic --cover -r -p - ego tool cover -html coverage.txt -o coverage.html -} - -src_install() { - # primary program - dobin bin/"${PN}" - - # secondary supplements - insinto /etc/"${PN}" - newins docs/config.yml config.yml.sample - - newbashcomp "${PN}".bash "${PN}" - dofishcomp "${PN}".fish - newzshcomp "${PN}".zsh _"${PN}" - - # TODO openrc services - systemd_newunit "${FILESDIR}"/blocky-0.22.service "${PN}".service - - # docs - einstalldocs - - if use doc; then - if [[ ${PV} == 9999* ]]; then - dodoc -r ../"${P}"-doc/main/* - else - dodoc -r ../"${PN}"-"${DOCUMENTATION_COMMIT}"/v"${PV}"/* - fi - fi -} diff --git a/net-dns/blocky/files/disable-failed-tests-0.22.patch b/net-dns/blocky/files/disable-failed-tests-0.22.patch deleted file mode 100644 index 98883469d..000000000 --- a/net-dns/blocky/files/disable-failed-tests-0.22.patch +++ /dev/null @@ -1,2272 +0,0 @@ -diff --git a/cache/stringcache/chained_grouped_cache_test.go b/cache/stringcache/chained_grouped_cache_test.go -deleted file mode 100644 -index e83f956..0000000 ---- a/cache/stringcache/chained_grouped_cache_test.go -+++ /dev/null -@@ -1,93 +0,0 @@ --package stringcache_test -- --import ( -- "github.com/0xERR0R/blocky/cache/stringcache" -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" --) -- --var _ = Describe("Chained grouped cache", func() { -- Describe("Empty cache", func() { -- When("empty cache was created", func() { -- cache := stringcache.NewChainedGroupedCache() -- -- It("should have element count of 0", func() { -- Expect(cache.ElementCount("someGroup")).Should(BeNumerically("==", 0)) -- }) -- -- It("should not find any string", func() { -- Expect(cache.Contains("searchString", []string{"someGroup"})).Should(BeEmpty()) -- }) -- }) -- }) -- Describe("Delegation", func() { -- When("Chained cache contains delegates", func() { -- inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() -- inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() -- cache := stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) -- -- factory := cache.Refresh("group1") -- -- factory.AddEntry("string1") -- factory.AddEntry("string2") -- -- It("cache should still have 0 element, since finish was not executed", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) -- }) -- -- It("factory has 4 elements (both caches)", func() { -- Expect(factory.Count()).Should(BeNumerically("==", 4)) -- }) -- -- It("should have element count of 4", func() { -- factory.Finish() -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 4)) -- }) -- -- It("should find strings", func() { -- Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("string2", []string{"group1", "someOtherGroup"})).Should(ConsistOf("group1")) -- }) -- }) -- }) -- -- Describe("Cache refresh", func() { -- When("cache with 2 groups was created", func() { -- inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() -- inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() -- cache := stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) -- -- factory := cache.Refresh("group1") -- -- factory.AddEntry("g1") -- factory.AddEntry("both") -- factory.Finish() -- -- factory = cache.Refresh("group2") -- factory.AddEntry("g2") -- factory.AddEntry("both") -- factory.Finish() -- -- It("should contain 4 elements in 2 groups", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 4)) -- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 4)) -- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) -- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group1", "group2")) -- }) -- -- It("Should replace group content on refresh", func() { -- factory := cache.Refresh("group1") -- factory.AddEntry("newString") -- factory.Finish() -- -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) -- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 4)) -- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(BeEmpty()) -- Expect(cache.Contains("newString", []string{"group1", "group2"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) -- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group2")) -- }) -- }) -- }) --}) -diff --git a/cache/stringcache/in_memory_grouped_cache_test.go b/cache/stringcache/in_memory_grouped_cache_test.go -deleted file mode 100644 -index 7692935..0000000 ---- a/cache/stringcache/in_memory_grouped_cache_test.go -+++ /dev/null -@@ -1,130 +0,0 @@ --package stringcache_test -- --import ( -- "github.com/0xERR0R/blocky/cache/stringcache" -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" --) -- --var _ = Describe("In-Memory grouped cache", func() { -- Describe("Empty cache", func() { -- When("empty cache was created", func() { -- cache := stringcache.NewInMemoryGroupedStringCache() -- -- It("should have element count of 0", func() { -- Expect(cache.ElementCount("someGroup")).Should(BeNumerically("==", 0)) -- }) -- -- It("should not find any string", func() { -- Expect(cache.Contains("searchString", []string{"someGroup"})).Should(BeEmpty()) -- }) -- }) -- When("cache with one empty group", func() { -- cache := stringcache.NewInMemoryGroupedStringCache() -- factory := cache.Refresh("group1") -- factory.Finish() -- -- It("should have element count of 0", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) -- }) -- -- It("should not find any string", func() { -- Expect(cache.Contains("searchString", []string{"group1"})).Should(BeEmpty()) -- }) -- }) -- }) -- Describe("Cache creation", func() { -- When("cache with 1 group was created", func() { -- cache := stringcache.NewInMemoryGroupedStringCache() -- -- factory := cache.Refresh("group1") -- -- factory.AddEntry("string1") -- factory.AddEntry("string2") -- -- It("cache should still have 0 element, since finish was not executed", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) -- }) -- -- It("factory has 2 elements", func() { -- Expect(factory.Count()).Should(BeNumerically("==", 2)) -- }) -- -- It("should have element count of 2", func() { -- factory.Finish() -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) -- }) -- -- It("should find strings", func() { -- Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("string2", []string{"group1", "someOtherGroup"})).Should(ConsistOf("group1")) -- }) -- }) -- When("String grouped cache is used", func() { -- cache := stringcache.NewInMemoryGroupedStringCache() -- factory := cache.Refresh("group1") -- -- factory.AddEntry("string1") -- factory.AddEntry("/string2/") -- factory.Finish() -- -- It("should ignore regex", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) -- Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) -- }) -- }) -- When("Regex grouped cache is used", func() { -- cache := stringcache.NewInMemoryGroupedRegexCache() -- factory := cache.Refresh("group1") -- -- factory.AddEntry("string1") -- factory.AddEntry("/string2/") -- factory.Finish() -- -- It("should ignore non-regex", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) -- Expect(cache.Contains("string1", []string{"group1"})).Should(BeEmpty()) -- Expect(cache.Contains("string2", []string{"group1"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("shouldalsomatchstring2", []string{"group1"})).Should(ConsistOf("group1")) -- }) -- }) -- }) -- -- Describe("Cache refresh", func() { -- When("cache with 2 groups was created", func() { -- cache := stringcache.NewInMemoryGroupedStringCache() -- -- factory := cache.Refresh("group1") -- -- factory.AddEntry("g1") -- factory.AddEntry("both") -- factory.Finish() -- -- factory = cache.Refresh("group2") -- factory.AddEntry("g2") -- factory.AddEntry("both") -- factory.Finish() -- -- It("should contain 4 elements in 2 groups", func() { -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) -- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 2)) -- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) -- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group1", "group2")) -- }) -- -- It("Should replace group content on refresh", func() { -- factory := cache.Refresh("group1") -- factory.AddEntry("newString") -- factory.Finish() -- -- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) -- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 2)) -- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(BeEmpty()) -- Expect(cache.Contains("newString", []string{"group1", "group2"})).Should(ConsistOf("group1")) -- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) -- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group2")) -- }) -- }) -- }) --}) -diff --git a/lists/downloader_test.go b/lists/downloader_test.go -deleted file mode 100644 -index 5387c86..0000000 ---- a/lists/downloader_test.go -+++ /dev/null -@@ -1,218 +0,0 @@ --package lists -- --import ( -- "errors" -- "io" -- "net" -- "net/http" -- "net/http/httptest" -- "strings" -- "sync/atomic" -- "time" -- -- "github.com/0xERR0R/blocky/config" -- . "github.com/0xERR0R/blocky/evt" -- . "github.com/0xERR0R/blocky/helpertest" -- "github.com/0xERR0R/blocky/log" -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" -- "github.com/sirupsen/logrus/hooks/test" --) -- --var _ = Describe("Downloader", func() { -- var ( -- sutConfig config.DownloaderConfig -- sut *httpDownloader -- failedDownloadCountEvtChannel chan string -- loggerHook *test.Hook -- ) -- BeforeEach(func() { -- var err error -- -- sutConfig, err = config.WithDefaults[config.DownloaderConfig]() -- Expect(err).Should(Succeed()) -- -- failedDownloadCountEvtChannel = make(chan string, 5) -- // collect received events in the channel -- fn := func(url string) { -- failedDownloadCountEvtChannel <- url -- } -- Expect(Bus().Subscribe(CachingFailedDownloadChanged, fn)).Should(Succeed()) -- DeferCleanup(func() { -- Expect(Bus().Unsubscribe(CachingFailedDownloadChanged, fn)) -- }) -- -- loggerHook = test.NewGlobal() -- log.Log().AddHook(loggerHook) -- DeferCleanup(loggerHook.Reset) -- }) -- -- JustBeforeEach(func() { -- sut = newDownloader(sutConfig, nil) -- }) -- -- Describe("NewDownloader", func() { -- It("Should use provided parameters", func() { -- transport := &http.Transport{} -- -- sut = NewDownloader( -- config.DownloaderConfig{ -- Attempts: 5, -- Cooldown: config.Duration(2 * time.Second), -- Timeout: config.Duration(5 * time.Second), -- }, -- transport, -- ).(*httpDownloader) -- -- Expect(sut.cfg.Attempts).Should(BeNumerically("==", 5)) -- Expect(sut.cfg.Timeout).Should(BeNumerically("==", 5*time.Second)) -- Expect(sut.cfg.Cooldown).Should(BeNumerically("==", 2*time.Second)) -- Expect(sut.client.Transport).Should(BeIdenticalTo(transport)) -- }) -- }) -- -- Describe("Download of a file", func() { -- var server *httptest.Server -- When("Download was successful", func() { -- BeforeEach(func() { -- server = TestServer("line.one\nline.two") -- DeferCleanup(server.Close) -- -- sut = newDownloader(sutConfig, nil) -- }) -- It("Should return all lines from the file", func() { -- reader, err := sut.DownloadFile(server.URL) -- -- Expect(err).Should(Succeed()) -- Expect(reader).Should(Not(BeNil())) -- DeferCleanup(reader.Close) -- buf := new(strings.Builder) -- _, err = io.Copy(buf, reader) -- Expect(err).Should(Succeed()) -- Expect(buf.String()).Should(Equal("line.one\nline.two")) -- }) -- }) -- When("Server returns NOT_FOUND (404)", func() { -- BeforeEach(func() { -- server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { -- rw.WriteHeader(http.StatusNotFound) -- })) -- DeferCleanup(server.Close) -- -- sutConfig.Attempts = 3 -- }) -- It("Should return error", func() { -- reader, err := sut.DownloadFile(server.URL) -- -- Expect(err).Should(HaveOccurred()) -- Expect(reader).Should(BeNil()) -- Expect(err.Error()).Should(Equal("got status code 404")) -- Expect(failedDownloadCountEvtChannel).Should(HaveLen(3)) -- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal(server.URL))) -- }) -- }) -- When("Wrong URL is defined", func() { -- BeforeEach(func() { -- sutConfig.Attempts = 1 -- }) -- It("Should return error", func() { -- _, err := sut.DownloadFile("somewrongurl") -- -- Expect(err).Should(HaveOccurred()) -- Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("Can't download file: ")) -- // failed download event was emitted only once -- Expect(failedDownloadCountEvtChannel).Should(HaveLen(1)) -- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal("somewrongurl"))) -- }) -- }) -- -- When("If timeout occurs on first request", func() { -- var attempt uint64 = 1 -- -- BeforeEach(func() { -- sutConfig = config.DownloaderConfig{ -- Timeout: config.Duration(20 * time.Millisecond), -- Attempts: 3, -- Cooldown: config.Duration(time.Millisecond), -- } -- -- // should produce a timeout on first attempt -- server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { -- a := atomic.LoadUint64(&attempt) -- atomic.AddUint64(&attempt, 1) -- if a == 1 { -- time.Sleep(500 * time.Millisecond) -- } else { -- _, err := rw.Write([]byte("blocked1.com")) -- Expect(err).Should(Succeed()) -- } -- })) -- DeferCleanup(server.Close) -- }) -- It("Should perform a retry and return file content", func() { -- reader, err := sut.DownloadFile(server.URL) -- Expect(err).Should(Succeed()) -- Expect(reader).Should(Not(BeNil())) -- DeferCleanup(reader.Close) -- -- buf := new(strings.Builder) -- _, err = io.Copy(buf, reader) -- Expect(err).Should(Succeed()) -- Expect(buf.String()).Should(Equal("blocked1.com")) -- -- // failed download event was emitted only once -- Expect(failedDownloadCountEvtChannel).Should(HaveLen(1)) -- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal(server.URL))) -- Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("Temporary network err / Timeout occurred: ")) -- }) -- }) -- When("If timeout occurs on all request", func() { -- BeforeEach(func() { -- sutConfig = config.DownloaderConfig{ -- Timeout: config.Duration(10 * time.Millisecond), -- Attempts: 3, -- Cooldown: config.Duration(time.Millisecond), -- } -- -- // should always produce a timeout -- server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { -- time.Sleep(20 * time.Millisecond) -- })) -- DeferCleanup(server.Close) -- }) -- It("Should perform a retry until max retry attempt count is reached and return TransientError", func() { -- reader, err := sut.DownloadFile(server.URL) -- Expect(err).Should(HaveOccurred()) -- Expect(errors.As(err, new(*TransientError))).Should(BeTrue()) -- Expect(err.Error()).Should(ContainSubstring("Timeout")) -- Expect(reader).Should(BeNil()) -- -- // failed download event was emitted 3 times -- Expect(failedDownloadCountEvtChannel).Should(HaveLen(3)) -- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal(server.URL))) -- }) -- }) -- When("DNS resolution of passed URL fails", func() { -- BeforeEach(func() { -- sutConfig = config.DownloaderConfig{ -- Timeout: config.Duration(500 * time.Millisecond), -- Attempts: 3, -- Cooldown: 200 * config.Duration(time.Millisecond), -- } -- }) -- It("Should perform a retry until max retry attempt count is reached and return DNSError", func() { -- reader, err := sut.DownloadFile("http://some.domain.which.does.not.exist") -- Expect(err).Should(HaveOccurred()) -- -- var dnsError *net.DNSError -- Expect(errors.As(err, &dnsError)).Should(BeTrue(), "received error %w", err) -- Expect(reader).Should(BeNil()) -- -- // failed download event was emitted 3 times -- Expect(failedDownloadCountEvtChannel).Should(HaveLen(3)) -- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal("http://some.domain.which.does.not.exist"))) -- Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("Name resolution err: ")) -- }) -- }) -- }) --}) -diff --git a/lists/list_cache_benchmark_test.go b/lists/list_cache_benchmark_test.go -deleted file mode 100644 -index fedf2fd..0000000 ---- a/lists/list_cache_benchmark_test.go -+++ /dev/null -@@ -1,29 +0,0 @@ --package lists -- --import ( -- "testing" -- -- "github.com/0xERR0R/blocky/config" --) -- --func BenchmarkRefresh(b *testing.B) { -- file1, _ := createTestListFile(b.TempDir(), 100000) -- file2, _ := createTestListFile(b.TempDir(), 150000) -- file3, _ := createTestListFile(b.TempDir(), 130000) -- lists := map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(file1, file2, file3), -- } -- -- cfg := config.SourceLoadingConfig{ -- Concurrency: 5, -- RefreshPeriod: config.Duration(-1), -- } -- downloader := NewDownloader(config.DownloaderConfig{}, nil) -- cache, _ := NewListCache(ListCacheTypeBlacklist, cfg, lists, downloader) -- -- b.ReportAllocs() -- -- for n := 0; n < b.N; n++ { -- cache.Refresh() -- } --} -diff --git a/lists/list_cache_test.go b/lists/list_cache_test.go -deleted file mode 100644 -index 2d08cfb..0000000 ---- a/lists/list_cache_test.go -+++ /dev/null -@@ -1,496 +0,0 @@ --package lists -- --import ( -- "bufio" -- "context" -- "errors" -- "fmt" -- "io" -- "math/rand" -- "net/http/httptest" -- "os" -- "strings" -- -- "github.com/0xERR0R/blocky/config" -- . "github.com/0xERR0R/blocky/evt" -- "github.com/0xERR0R/blocky/lists/parsers" -- "github.com/0xERR0R/blocky/log" -- "github.com/0xERR0R/blocky/util" -- "github.com/sirupsen/logrus" -- -- . "github.com/0xERR0R/blocky/helpertest" -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" --) -- --var _ = Describe("ListCache", func() { -- var ( -- tmpDir *TmpFolder -- emptyFile, file1, file2, file3 *TmpFile -- server1, server2, server3 *httptest.Server -- -- sut *ListCache -- sutConfig config.SourceLoadingConfig -- -- listCacheType ListCacheType -- lists map[string][]config.BytesSource -- downloader FileDownloader -- mockDownloader *MockDownloader -- ) -- -- BeforeEach(func() { -- var err error -- -- listCacheType = ListCacheTypeBlacklist -- -- sutConfig, err = config.WithDefaults[config.SourceLoadingConfig]() -- Expect(err).Should(Succeed()) -- -- sutConfig.RefreshPeriod = -1 -- -- downloader = NewDownloader(config.DownloaderConfig{}, nil) -- mockDownloader = nil -- -- server1 = TestServer("blocked1.com\nblocked1a.com\n192.168.178.55") -- DeferCleanup(server1.Close) -- server2 = TestServer("blocked2.com") -- DeferCleanup(server2.Close) -- server3 = TestServer("blocked3.com\nblocked1a.com") -- DeferCleanup(server3.Close) -- -- tmpDir = NewTmpFolder("ListCache") -- Expect(tmpDir.Error).Should(Succeed()) -- DeferCleanup(tmpDir.Clean) -- -- emptyFile = tmpDir.CreateStringFile("empty", "#empty file") -- Expect(emptyFile.Error).Should(Succeed()) -- -- emptyFile = tmpDir.CreateStringFile("empty", "#empty file") -- Expect(emptyFile.Error).Should(Succeed()) -- file1 = tmpDir.CreateStringFile("file1", "blocked1.com", "blocked1a.com") -- Expect(file1.Error).Should(Succeed()) -- file2 = tmpDir.CreateStringFile("file2", "blocked2.com") -- Expect(file2.Error).Should(Succeed()) -- file3 = tmpDir.CreateStringFile("file3", "blocked3.com", "blocked1a.com") -- Expect(file3.Error).Should(Succeed()) -- }) -- -- JustBeforeEach(func() { -- var err error -- -- Expect(lists).ShouldNot(BeNil(), "bad test: forgot to set `lists`") -- -- if mockDownloader != nil { -- downloader = mockDownloader -- } -- -- sut, err = NewListCache(listCacheType, sutConfig, lists, downloader) -- Expect(err).Should(Succeed()) -- }) -- -- Describe("List cache and matching", func() { -- When("List is empty", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr0": config.NewBytesSources(emptyFile.Path), -- } -- }) -- -- When("Query with empty", func() { -- It("should not panic", func() { -- group := sut.Match("", []string{"gr0"}) -- Expect(group).Should(BeEmpty()) -- }) -- }) -- -- It("should not match anything", func() { -- group := sut.Match("google.com", []string{"gr1"}) -- Expect(group).Should(BeEmpty()) -- }) -- }) -- When("List becomes empty on refresh", func() { -- BeforeEach(func() { -- mockDownloader = newMockDownloader(func(res chan<- string, err chan<- error) { -- res <- "blocked1.com" -- res <- "# nothing" -- }) -- -- lists = map[string][]config.BytesSource{ -- "gr1": {mockDownloader.ListSource()}, -- } -- }) -- -- It("should delete existing elements from group cache", func(ctx context.Context) { -- group := sut.Match("blocked1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- -- err := sut.refresh(ctx) -- Expect(err).Should(Succeed()) -- -- group = sut.Match("blocked1.com", []string{"gr1"}) -- Expect(group).Should(BeEmpty()) -- }) -- }) -- When("List has invalid lines", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": { -- config.TextBytesSource( -- "inlinedomain1.com", -- "invaliddomain!", -- "inlinedomain2.com", -- ), -- }, -- } -- }) -- -- It("should still other domains", func() { -- group := sut.Match("inlinedomain1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("inlinedomain2.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- When("a temporary/transient err occurs on download", func() { -- BeforeEach(func() { -- // should produce a transient error on second and third attempt -- mockDownloader = newMockDownloader(func(res chan<- string, err chan<- error) { -- res <- "blocked1.com\nblocked2.com\n" -- err <- &TransientError{inner: errors.New("boom")} -- err <- &TransientError{inner: errors.New("boom")} -- }) -- -- lists = map[string][]config.BytesSource{ -- "gr1": {mockDownloader.ListSource()}, -- } -- }) -- -- It("should not delete existing elements from group cache", func(ctx context.Context) { -- By("Lists loaded without timeout", func() { -- Eventually(func(g Gomega) { -- group := sut.Match("blocked1.com", []string{"gr1"}) -- g.Expect(group).Should(ContainElement("gr1")) -- }, "1s").Should(Succeed()) -- }) -- -- Expect(sut.refresh(ctx)).Should(HaveOccurred()) -- -- By("List couldn't be loaded due to timeout", func() { -- group := sut.Match("blocked1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- -- sut.Refresh() -- -- By("List couldn't be loaded due to timeout", func() { -- group := sut.Match("blocked1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- }) -- When("non transient err occurs on download", func() { -- BeforeEach(func() { -- // should produce a non transient error on second attempt -- mockDownloader = newMockDownloader(func(res chan<- string, err chan<- error) { -- res <- "blocked1.com" -- err <- errors.New("boom") -- }) -- -- lists = map[string][]config.BytesSource{ -- "gr1": {mockDownloader.ListSource()}, -- } -- }) -- -- It("should keep existing elements from group cache", func(ctx context.Context) { -- By("Lists loaded without err", func() { -- group := sut.Match("blocked1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- -- Expect(sut.refresh(ctx)).Should(HaveOccurred()) -- -- By("Lists from first load is kept", func() { -- group := sut.Match("blocked1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- }) -- When("Configuration has 3 external working urls", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(server1.URL, server2.URL), -- "gr2": config.NewBytesSources(server3.URL), -- } -- }) -- -- It("should download the list and match against", func() { -- group := sut.Match("blocked1.com", []string{"gr1", "gr2"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("blocked1a.com", []string{"gr1", "gr2"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("blocked1a.com", []string{"gr2"}) -- Expect(group).Should(ContainElement("gr2")) -- }) -- }) -- When("Configuration has some faulty urls", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(server1.URL, server2.URL, "doesnotexist"), -- "gr2": config.NewBytesSources(server3.URL, "someotherfile"), -- } -- }) -- -- It("should download the list and match against", func() { -- group := sut.Match("blocked1.com", []string{"gr1", "gr2"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("blocked1a.com", []string{"gr1", "gr2"}) -- Expect(group).Should(ContainElements("gr1", "gr2")) -- -- group = sut.Match("blocked1a.com", []string{"gr2"}) -- Expect(group).Should(ContainElement("gr2")) -- }) -- }) -- When("List will be updated", func() { -- resultCnt := 0 -- -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(server1.URL), -- } -- -- _ = Bus().SubscribeOnce(BlockingCacheGroupChanged, func(listType ListCacheType, group string, cnt int) { -- resultCnt = cnt -- }) -- }) -- -- It("event should be fired and contain count of elements in downloaded lists", func() { -- group := sut.Match("blocked1.com", []string{}) -- Expect(group).Should(BeEmpty()) -- Expect(resultCnt).Should(Equal(3)) -- }) -- }) -- When("multiple groups are passed", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(file1.Path, file2.Path), -- "gr2": config.NewBytesSources("file://" + file3.Path), -- } -- }) -- -- It("should match", func() { -- Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(3)) -- Expect(sut.groupedCache.ElementCount("gr2")).Should(Equal(2)) -- -- group := sut.Match("blocked1.com", []string{"gr1", "gr2"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("blocked1a.com", []string{"gr1", "gr2"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("blocked1a.com", []string{"gr2"}) -- Expect(group).Should(ContainElement("gr2")) -- }) -- }) -- When("group with bigger files", func() { -- It("should match", func() { -- file1, lines1 := createTestListFile(GinkgoT().TempDir(), 10000) -- file2, lines2 := createTestListFile(GinkgoT().TempDir(), 15000) -- file3, lines3 := createTestListFile(GinkgoT().TempDir(), 13000) -- lists := map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(file1, file2, file3), -- } -- -- sut, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) -- Expect(err).Should(Succeed()) -- -- Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(lines1 + lines2 + lines3)) -- }) -- }) -- When("inline list content is defined", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": {config.TextBytesSource( -- "inlinedomain1.com", -- "#some comment", -- "inlinedomain2.com", -- )}, -- } -- }) -- -- It("should match", func() { -- Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(2)) -- group := sut.Match("inlinedomain1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("inlinedomain2.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- When("Text file can't be parsed", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": { -- config.TextBytesSource( -- "inlinedomain1.com", -- "lineTooLong"+strings.Repeat("x", bufio.MaxScanTokenSize), // too long -- ), -- }, -- } -- }) -- -- It("should still match already imported strings", func() { -- group := sut.Match("inlinedomain1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- When("Text file has too many errors", func() { -- BeforeEach(func() { -- sutConfig.MaxErrorsPerSource = 0 -- sutConfig.Strategy = config.StartStrategyTypeFailOnError -- }) -- It("should fail parsing", func() { -- lists := map[string][]config.BytesSource{ -- "gr1": { -- config.TextBytesSource("invaliddomain!"), // too many errors since `maxErrorsPerSource` is 0 -- }, -- } -- -- _, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) -- Expect(err).ShouldNot(Succeed()) -- Expect(err).Should(MatchError(parsers.ErrTooManyErrors)) -- }) -- }) -- When("file has end of line comment", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": {config.TextBytesSource("inlinedomain1.com#a comment")}, -- } -- }) -- -- It("should still parse the domain", func() { -- group := sut.Match("inlinedomain1.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- When("inline regex content is defined", func() { -- BeforeEach(func() { -- lists = map[string][]config.BytesSource{ -- "gr1": {config.TextBytesSource("/^apple\\.(de|com)$/")}, -- } -- }) -- -- It("should match", func() { -- group := sut.Match("apple.com", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- -- group = sut.Match("apple.de", []string{"gr1"}) -- Expect(group).Should(ContainElement("gr1")) -- }) -- }) -- }) -- Describe("LogConfig", func() { -- var ( -- logger *logrus.Entry -- hook *log.MockLoggerHook -- ) -- -- BeforeEach(func() { -- logger, hook = log.NewMockEntry() -- }) -- -- It("should print list configuration", func() { -- lists := map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources(server1.URL, server2.URL), -- "gr2": {config.TextBytesSource("inline", "definition")}, -- } -- -- sut, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) -- Expect(err).Should(Succeed()) -- -- sut.LogConfig(logger) -- Expect(hook.Calls).ShouldNot(BeEmpty()) -- Expect(hook.Messages).Should(ContainElement(ContainSubstring("gr1:"))) -- Expect(hook.Messages).Should(ContainElement(ContainSubstring("gr2:"))) -- Expect(hook.Messages).Should(ContainElement(ContainSubstring("TOTAL:"))) -- }) -- }) -- -- Describe("StartStrategy", func() { -- When("async load is enabled", func() { -- BeforeEach(func() { -- sutConfig.Strategy = config.StartStrategyTypeFast -- }) -- -- It("should never return an error", func() { -- lists := map[string][]config.BytesSource{ -- "gr1": config.NewBytesSources("doesnotexist"), -- } -- -- _, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) -- Expect(err).Should(Succeed()) -- }) -- }) -- }) --}) -- --type MockDownloader struct { -- util.MockCallSequence[string] --} -- --func newMockDownloader(driver func(res chan<- string, err chan<- error)) *MockDownloader { -- return &MockDownloader{util.NewMockCallSequence(driver)} --} -- --func (m *MockDownloader) DownloadFile(_ string) (io.ReadCloser, error) { -- str, err := m.Call() -- if err != nil { -- return nil, err -- } -- -- return io.NopCloser(strings.NewReader(str)), nil --} -- --func (m *MockDownloader) ListSource() config.BytesSource { -- return config.BytesSource{ -- Type: config.BytesSourceTypeHttp, -- From: "http://mock-downloader", -- } --} -- --func createTestListFile(dir string, totalLines int) (string, int) { -- file, err := os.CreateTemp(dir, "blocky") -- if err != nil { -- log.Log().Fatal(err) -- } -- -- w := bufio.NewWriter(file) -- for i := 0; i < totalLines; i++ { -- fmt.Fprintln(w, RandStringBytes(8+rand.Intn(10))+".com") -- } -- w.Flush() -- -- return file.Name(), totalLines --} -- --const ( -- initCharpool = "abcdefghijklmnopqrstuvwxyz" -- contCharpool = initCharpool + "0123456789-" --) -- --func RandStringBytes(n int) string { -- b := make([]byte, n) -- -- pool := initCharpool -- -- for i := range b { -- b[i] = pool[rand.Intn(len(pool))] -- -- pool = contCharpool -- } -- -- return string(b) --} -diff --git a/server/server_test.go b/server/server_test.go -deleted file mode 100644 -index 65b30bc..0000000 ---- a/server/server_test.go -+++ /dev/null -@@ -1,888 +0,0 @@ --package server -- --import ( -- "bytes" -- "encoding/base64" -- "encoding/json" -- "io" -- "net" -- "net/http" -- "strings" -- "sync/atomic" -- "time" -- -- "github.com/0xERR0R/blocky/api" -- "github.com/0xERR0R/blocky/config" -- . "github.com/0xERR0R/blocky/helpertest" -- . "github.com/0xERR0R/blocky/log" -- "github.com/0xERR0R/blocky/model" -- "github.com/0xERR0R/blocky/resolver" -- "github.com/0xERR0R/blocky/util" -- "github.com/creasty/defaults" -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" -- -- "github.com/miekg/dns" --) -- --var ( -- mockClientName atomic.Value -- sut *Server -- err error --) -- --var _ = BeforeSuite(func() { -- var upstreamGoogle, upstreamFritzbox, upstreamClient config.Upstream -- googleMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { -- if request.Question[0].Name == "error." { -- return nil -- } -- response, err := util.NewMsgWithAnswer( -- util.ExtractDomain(request.Question[0]), 123, A, "123.124.122.122", -- ) -- -- Expect(err).Should(Succeed()) -- -- return response -- }) -- DeferCleanup(googleMockUpstream.Close) -- -- fritzboxMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { -- response, err := util.NewMsgWithAnswer( -- util.ExtractDomain(request.Question[0]), 3600, A, "192.168.178.2", -- ) -- -- Expect(err).Should(Succeed()) -- -- return response -- }) -- DeferCleanup(fritzboxMockUpstream.Close) -- -- clientMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { -- var clientName string -- client := mockClientName.Load() -- -- if client != nil { -- clientName = mockClientName.Load().(string) -- } -- -- response, err := util.NewMsgWithAnswer( -- util.ExtractDomain(request.Question[0]), 3600, dns.Type(dns.TypePTR), clientName, -- ) -- -- Expect(err).Should(Succeed()) -- -- return response -- }) -- DeferCleanup(clientMockUpstream.Close) -- -- upstreamClient = clientMockUpstream.Start() -- upstreamFritzbox = fritzboxMockUpstream.Start() -- upstreamGoogle = googleMockUpstream.Start() -- -- tmpDir := NewTmpFolder("server") -- Expect(tmpDir.Error).Should(Succeed()) -- DeferCleanup(tmpDir.Clean) -- -- certPem := writeCertPem(tmpDir) -- Expect(certPem.Error).Should(Succeed()) -- -- keyPem := writeKeyPem(tmpDir) -- Expect(keyPem.Error).Should(Succeed()) -- -- doubleclickFile := tmpDir.CreateStringFile("doubleclick.net.txt", "doubleclick.net", "doubleclick.net.cn") -- Expect(doubleclickFile.Error).Should(Succeed()) -- -- bildFile := tmpDir.CreateStringFile("www.bild.de.txt", "www.bild.de") -- Expect(bildFile.Error).Should(Succeed()) -- -- heiseFile := tmpDir.CreateStringFile("heise.de.txt", "heise.de") -- Expect(heiseFile.Error).Should(Succeed()) -- -- youtubeFile := tmpDir.CreateStringFile("youtube.com.txt", "youtube.com") -- Expect(youtubeFile.Error).Should(Succeed()) -- -- // create server -- sut, err = NewServer(&config.Config{ -- CustomDNS: config.CustomDNSConfig{ -- CustomTTL: config.Duration(3600 * time.Second), -- Mapping: config.CustomDNSMapping{ -- HostIPs: map[string][]net.IP{ -- "custom.lan": {net.ParseIP("192.168.178.55")}, -- "lan.home": {net.ParseIP("192.168.178.56")}, -- }, -- }, -- }, -- Conditional: config.ConditionalUpstreamConfig{ -- Mapping: config.ConditionalUpstreamMapping{ -- Upstreams: map[string][]config.Upstream{ -- "net.cn": {upstreamClient}, -- "fritz.box": {upstreamFritzbox}, -- }, -- }, -- }, -- Blocking: config.BlockingConfig{ -- BlackLists: map[string][]config.BytesSource{ -- "ads": config.NewBytesSources( -- doubleclickFile.Path, -- bildFile.Path, -- heiseFile.Path, -- ), -- "youtube": config.NewBytesSources(youtubeFile.Path), -- }, -- WhiteLists: map[string][]config.BytesSource{ -- "ads": config.NewBytesSources(heiseFile.Path), -- "whitelist": config.NewBytesSources(heiseFile.Path), -- }, -- ClientGroupsBlock: map[string][]string{ -- "default": {"ads"}, -- "clWhitelistOnly": {"whitelist"}, -- "clAdsAndYoutube": {"ads", "youtube"}, -- "clYoutubeOnly": {"youtube"}, -- }, -- BlockType: "zeroIp", -- BlockTTL: config.Duration(6 * time.Hour), -- }, -- Upstreams: config.UpstreamsConfig{ -- Groups: map[string][]config.Upstream{"default": {upstreamGoogle}}, -- }, -- ClientLookup: config.ClientLookupConfig{ -- Upstream: upstreamClient, -- }, -- -- Ports: config.PortsConfig{ -- DNS: config.ListenConfig{"55555"}, -- TLS: config.ListenConfig{"8853"}, -- HTTP: config.ListenConfig{"4000"}, -- HTTPS: config.ListenConfig{"4443"}, -- }, -- CertFile: certPem.Path, -- KeyFile: keyPem.Path, -- Prometheus: config.MetricsConfig{ -- Enable: true, -- Path: "/metrics", -- }, -- }) -- -- Expect(err).Should(Succeed()) -- -- errChan := make(chan error, 10) -- -- // start server -- go func() { -- sut.Start(errChan) -- }() -- DeferCleanup(sut.Stop) -- -- Consistently(errChan, "1s").ShouldNot(Receive()) --}) -- --var _ = Describe("Running DNS server", func() { -- Describe("performing DNS request with running server", func() { -- BeforeEach(func() { -- mockClientName.Store("") -- // reset client cache -- res := sut.queryResolver -- for res != nil { -- if t, ok := res.(*resolver.ClientNamesResolver); ok { -- t.FlushCache() -- -- break -- } -- if c, ok := res.(resolver.ChainedResolver); ok { -- res = c.GetNext() -- } else { -- break -- } -- } -- }) -- -- Context("DNS query is resolvable via external DNS", func() { -- It("should return valid answer", func() { -- Expect(requestServer(util.NewMsgWithQuestion("google.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("google.de.", A, "123.124.122.122"), -- HaveTTL(BeNumerically("==", 123)), -- )) -- }) -- }) -- Context("Custom DNS entry with exact match", func() { -- It("should return valid answer", func() { -- Expect(requestServer(util.NewMsgWithQuestion("custom.lan.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("custom.lan.", A, "192.168.178.55"), -- HaveTTL(BeNumerically("==", 3600)), -- )) -- }) -- }) -- Context("Custom DNS entry with sub domain", func() { -- It("should return valid answer", func() { -- Expect(requestServer(util.NewMsgWithQuestion("host.lan.home.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("host.lan.home.", A, "192.168.178.56"), -- HaveTTL(BeNumerically("==", 3600)), -- )) -- }) -- }) -- Context("Conditional upstream", func() { -- It("should resolve query via conditional upstream resolver", func() { -- Expect(requestServer(util.NewMsgWithQuestion("host.fritz.box.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("host.fritz.box.", A, "192.168.178.2"), -- HaveTTL(BeNumerically("==", 3600)), -- )) -- }) -- }) -- Context("Conditional upstream blocking", func() { -- It("Query should be blocked, domain is in default group", func() { -- Expect(requestServer(util.NewMsgWithQuestion("doubleclick.net.cn.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("doubleclick.net.cn.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- }) -- }) -- Context("Blocking default group", func() { -- It("Query should be blocked, domain is in default group", func() { -- Expect(requestServer(util.NewMsgWithQuestion("doubleclick.net.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("doubleclick.net.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- }) -- }) -- Context("Blocking default group with sub domain", func() { -- It("Query with subdomain should be blocked, domain is in default group", func() { -- Expect(requestServer(util.NewMsgWithQuestion("www.bild.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("www.bild.de.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- }) -- }) -- Context("no blocking default group with sub domain", func() { -- It("Query with should not be blocked, sub domain is not in blacklist", func() { -- Expect(requestServer(util.NewMsgWithQuestion("bild.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("bild.de.", A, "123.124.122.122"), -- HaveTTL(BeNumerically("<=", 123)), -- )) -- }) -- }) -- Context("domain is on white and blacklist default group", func() { -- It("Query with should not be blocked, domain is on white and blacklist", func() { -- Expect(requestServer(util.NewMsgWithQuestion("heise.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("heise.de.", A, "123.124.122.122"), -- HaveTTL(BeNumerically("<=", 123)), -- )) -- }) -- }) -- Context("domain is on client specific white list", func() { -- It("Query with should not be blocked, domain is on client's white list", func() { -- mockClientName.Store("clWhitelistOnly") -- Expect(requestServer(util.NewMsgWithQuestion("heise.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("heise.de.", A, "123.124.122.122"), -- HaveTTL(BeNumerically("<=", 123)), -- )) -- }) -- }) -- Context("block client whitelist only", func() { -- It("Query with should be blocked, client has only whitelist, domain is not on client's white list", func() { -- mockClientName.Store("clWhitelistOnly") -- Expect(requestServer(util.NewMsgWithQuestion("google.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("google.de.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- }) -- }) -- Context("block client with 2 groups", func() { -- It("Query with should be blocked, domain is on black list", func() { -- mockClientName.Store("clAdsAndYoutube") -- -- Expect(requestServer(util.NewMsgWithQuestion("www.bild.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("www.bild.de.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- -- Expect(requestServer(util.NewMsgWithQuestion("youtube.com.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("youtube.com.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- }) -- }) -- Context("client with 1 group: no block if domain in other group", func() { -- It("Query with should not be blocked, domain is on black list in another group", func() { -- mockClientName.Store("clYoutubeOnly") -- -- Expect(requestServer(util.NewMsgWithQuestion("www.bild.de.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("www.bild.de.", A, "123.124.122.122"), -- HaveTTL(BeNumerically("<=", 123)), -- )) -- }) -- }) -- Context("block client with 1 group", func() { -- It("Query with should not blocked, domain is on black list in client's group", func() { -- mockClientName.Store("clYoutubeOnly") -- -- Expect(requestServer(util.NewMsgWithQuestion("youtube.com.", A))). -- Should( -- SatisfyAll( -- BeDNSRecord("youtube.com.", A, "0.0.0.0"), -- HaveTTL(BeNumerically("==", 21600)), -- )) -- }) -- }) -- Context("health check", func() { -- It("Should always return dummy response", func() { -- resp := requestServer(util.NewMsgWithQuestion("healthcheck.blocky.", A)) -- -- Expect(resp.Answer).Should(BeEmpty()) -- }) -- }) -- }) -- -- Describe("Prometheus endpoint", func() { -- When("Prometheus URL is called", func() { -- It("should return prometheus data", func() { -- resp, err := http.Get("http://localhost:4000/metrics") -- Expect(err).Should(Succeed()) -- Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) -- }) -- }) -- }) -- Describe("Root endpoint", func() { -- When("Root URL is called", func() { -- It("should return root page", func() { -- resp, err := http.Get("http://localhost:4000/") -- Expect(err).Should(Succeed()) -- Expect(resp).Should( -- SatisfyAll( -- HaveHTTPStatus(http.StatusOK), -- HaveHTTPHeaderWithValue("Content-type", "text/html; charset=UTF-8"), -- )) -- }) -- }) -- }) -- -- Describe("Query Rest API", func() { -- When("Query API is called", func() { -- It("Should process the query", func() { -- req := api.QueryRequest{ -- Query: "google.de", -- Type: "A", -- } -- jsonValue, err := json.Marshal(req) -- Expect(err).Should(Succeed()) -- -- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) -- -- Expect(err).Should(Succeed()) -- defer resp.Body.Close() -- -- Expect(resp).Should( -- SatisfyAll( -- HaveHTTPStatus(http.StatusOK), -- HaveHTTPHeaderWithValue("Content-type", "application/json"), -- )) -- -- var result api.QueryResult -- err = json.NewDecoder(resp.Body).Decode(&result) -- Expect(err).Should(Succeed()) -- Expect(result.Response).Should(Equal("A (123.124.122.122)")) -- }) -- }) -- When("Wrong request type is used", func() { -- It("Should return internal error", func() { -- req := api.QueryRequest{ -- Query: "google.de", -- Type: "WrongType", -- } -- jsonValue, err := json.Marshal(req) -- Expect(err).Should(Succeed()) -- -- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) -- -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) -- }) -- }) -- When("Internal error occurs", func() { -- It("Should return internal error", func() { -- req := api.QueryRequest{ -- Query: "error.", -- Type: "A", -- } -- jsonValue, err := json.Marshal(req) -- Expect(err).Should(Succeed()) -- -- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) -- }) -- }) -- When("Request is malformed", func() { -- It("Should return internal error", func() { -- jsonValue := []byte("") -- -- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) -- -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) -- }) -- }) -- }) -- -- Describe("DOH endpoint", func() { -- Context("DOH over GET (RFC 8484)", func() { -- When("DOH get request with 'example.com' is performed", func() { -- It("should get a valid response", func() { -- resp, err := http.Get("http://localhost:4000/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB") -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) -- Expect(resp).Should(HaveHTTPHeaderWithValue("Content-type", "application/dns-message")) -- -- rawMsg, err := io.ReadAll(resp.Body) -- Expect(err).Should(Succeed()) -- -- msg := new(dns.Msg) -- err = msg.Unpack(rawMsg) -- Expect(err).Should(Succeed()) -- -- Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) -- }) -- }) -- When("Request does not contain a valid DNS message", func() { -- It("should return 'Bad Request'", func() { -- resp, err := http.Get("http://localhost:4000/dns-query?dns=xxxx") -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusBadRequest)) -- }) -- }) -- When("Request's parameter does not contain a valid base64'", func() { -- It("should return 'Bad Request'", func() { -- resp, err := http.Get("http://localhost:4000/dns-query?dns=äöä") -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusBadRequest)) -- }) -- }) -- When("Request does not contain a dns parameter", func() { -- It("should return 'Bad Request'", func() { -- resp, err := http.Get("http://localhost:4000/dns-query?test") -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusBadRequest)) -- }) -- }) -- When("Request's dns parameter is too long'", func() { -- It("should return 'URI Too Long'", func() { -- longBase64msg := base64.StdEncoding.EncodeToString([]byte(strings.Repeat("t", 513))) -- -- resp, err := http.Get("http://localhost:4000/dns-query?dns=" + longBase64msg) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusRequestURITooLong)) -- }) -- }) -- }) -- Context("DOH over POST (RFC 8484)", func() { -- When("DOH post request with 'example.com' is performed", func() { -- It("should get a valid response", func() { -- msg := util.NewMsgWithQuestion("www.example.com.", A) -- rawDNSMessage, err := msg.Pack() -- Expect(err).Should(Succeed()) -- -- resp, err := http.Post("http://localhost:4000/dns-query", -- "application/dns-message", bytes.NewReader(rawDNSMessage)) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should( -- SatisfyAll( -- HaveHTTPStatus(http.StatusOK), -- HaveHTTPHeaderWithValue("Content-type", "application/dns-message"), -- )) -- -- rawMsg, err := io.ReadAll(resp.Body) -- Expect(err).Should(Succeed()) -- -- msg = new(dns.Msg) -- err = msg.Unpack(rawMsg) -- Expect(err).Should(Succeed()) -- -- Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) -- }) -- It("should get a valid response, clientId is passed", func() { -- msg := util.NewMsgWithQuestion("www.example.com.", A) -- rawDNSMessage, err := msg.Pack() -- Expect(err).Should(Succeed()) -- -- resp, err := http.Post("http://localhost:4000/dns-query/client123", -- "application/dns-message", bytes.NewReader(rawDNSMessage)) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should( -- SatisfyAll( -- HaveHTTPStatus(http.StatusOK), -- HaveHTTPHeaderWithValue("Content-type", "application/dns-message"), -- )) -- rawMsg, err := io.ReadAll(resp.Body) -- Expect(err).Should(Succeed()) -- -- msg = new(dns.Msg) -- err = msg.Unpack(rawMsg) -- Expect(err).Should(Succeed()) -- -- Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) -- }) -- }) -- When("POST payload exceeds 512 bytes", func() { -- It("should return 'Payload Too Large'", func() { -- largeMessage := []byte(strings.Repeat("t", 513)) -- -- resp, err := http.Post("http://localhost:4000/dns-query", "application/dns-message", bytes.NewReader(largeMessage)) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusRequestEntityTooLarge)) -- }) -- }) -- When("Request has wrong type", func() { -- It("should return 'Unsupported Media Type'", func() { -- resp, err := http.Post("http://localhost:4000/dns-query", "application/text", bytes.NewReader([]byte("a"))) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusUnsupportedMediaType)) -- }) -- }) -- When("Internal error occurs", func() { -- It("should return 'Internal server error'", func() { -- msg := util.NewMsgWithQuestion("error.", A) -- rawDNSMessage, err := msg.Pack() -- Expect(err).Should(Succeed()) -- -- resp, err := http.Post("http://localhost:4000/dns-query", -- "application/dns-message", bytes.NewReader(rawDNSMessage)) -- Expect(err).Should(Succeed()) -- DeferCleanup(resp.Body.Close) -- -- Expect(resp).Should(HaveHTTPStatus(http.StatusInternalServerError)) -- }) -- }) -- }) -- }) -- -- Describe("Server create", func() { -- var ( -- cfg config.Config -- cErr error -- ) -- BeforeEach(func() { -- cErr = defaults.Set(&cfg) -- -- Expect(cErr).Should(Succeed()) -- -- cfg.Upstreams.Groups = map[string][]config.Upstream{ -- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "1.1.1.1", Port: 53}}, -- } -- -- cfg.Redis.Address = "test-fail" -- }) -- When("Server is created", func() { -- It("is created without redis connection", func() { -- _, err := NewServer(&cfg) -- -- Expect(err).Should(Succeed()) -- }) -- It("can't be created if redis server is unavailable", func() { -- cfg.Redis.Required = true -- -- _, err := NewServer(&cfg) -- -- Expect(err).ShouldNot(Succeed()) -- }) -- }) -- }) -- -- Describe("Server start", Label("XX"), func() { -- When("Server start is called", func() { -- It("start was called 2 times, start should fail", func() { -- // create server -- server, err := NewServer(&config.Config{ -- Upstreams: config.UpstreamsConfig{ -- Groups: map[string][]config.Upstream{ -- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "4.4.4.4", Port: 53}}, -- }, -- }, -- CustomDNS: config.CustomDNSConfig{ -- Mapping: config.CustomDNSMapping{ -- HostIPs: map[string][]net.IP{ -- "custom.lan": {net.ParseIP("192.168.178.55")}, -- "lan.home": {net.ParseIP("192.168.178.56")}, -- }, -- }, -- }, -- Blocking: config.BlockingConfig{BlockType: "zeroIp"}, -- Ports: config.PortsConfig{ -- DNS: config.ListenConfig{":55556"}, -- }, -- }) -- -- Expect(err).Should(Succeed()) -- -- errChan := make(chan error, 10) -- -- // start server -- go server.Start(errChan) -- -- DeferCleanup(server.Stop) -- -- Consistently(errChan, "1s").ShouldNot(Receive()) -- -- // start again -> should fail -- server.Start(errChan) -- -- Eventually(errChan).Should(Receive()) -- }) -- }) -- }) -- Describe("Server stop", func() { -- When("Stop is called", func() { -- It("stop was called 2 times, start should fail", func() { -- // create server -- server, err := NewServer(&config.Config{ -- Upstreams: config.UpstreamsConfig{ -- Groups: map[string][]config.Upstream{ -- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "4.4.4.4", Port: 53}}, -- }, -- }, -- CustomDNS: config.CustomDNSConfig{ -- Mapping: config.CustomDNSMapping{ -- HostIPs: map[string][]net.IP{ -- "custom.lan": {net.ParseIP("192.168.178.55")}, -- "lan.home": {net.ParseIP("192.168.178.56")}, -- }, -- }, -- }, -- Blocking: config.BlockingConfig{BlockType: "zeroIp"}, -- Ports: config.PortsConfig{ -- DNS: config.ListenConfig{"127.0.0.1:55557"}, -- }, -- }) -- -- Expect(err).Should(Succeed()) -- -- errChan := make(chan error, 10) -- -- // start server -- go func() { -- server.Start(errChan) -- }() -- -- time.Sleep(100 * time.Millisecond) -- -- err = server.Stop() -- -- // stop server, should be ok -- Expect(err).Should(Succeed()) -- -- // stop again, should raise error -- err = server.Stop() -- -- Expect(err).Should(HaveOccurred()) -- }) -- }) -- }) -- -- Describe("NewServer with strict upstream strategy", func() { -- It("successfully returns upstream branches", func() { -- branches, err := createUpstreamBranches(&config.Config{ -- Upstreams: config.UpstreamsConfig{ -- Strategy: config.UpstreamStrategyStrict, -- Groups: config.UpstreamGroups{ -- "default": {{Host: "0.0.0.0"}}, -- }, -- }, -- }, -- nil) -- -- Expect(err).ToNot(HaveOccurred()) -- Expect(branches).ToNot(BeNil()) -- Expect(branches).To(HaveLen(1)) -- _ = branches["default"].(*resolver.StrictResolver) -- }) -- }) -- -- Describe("create query resolver", func() { -- When("some upstream returns error", func() { -- It("create query resolver should return error", func() { -- r, err := createQueryResolver(&config.Config{ -- StartVerifyUpstream: true, -- Upstreams: config.UpstreamsConfig{ -- Groups: config.UpstreamGroups{ -- "default": {{Host: "0.0.0.0"}}, -- }, -- }, -- }, -- nil, nil) -- -- Expect(err).To(HaveOccurred()) -- Expect(err).To(MatchError(ContainSubstring("creation of upstream branches failed: "))) -- Expect(r).To(BeNil()) -- }) -- }) -- }) -- -- Describe("resolve client IP", func() { -- Context("UDP address", func() { -- It("should correct resolve client IP", func() { -- ip, protocol := resolveClientIPAndProtocol(&net.UDPAddr{IP: net.ParseIP("192.168.178.88")}) -- Expect(ip).Should(Equal(net.ParseIP("192.168.178.88"))) -- Expect(protocol).Should(Equal(model.RequestProtocolUDP)) -- }) -- }) -- Context("TCP address", func() { -- It("should correct resolve client IP", func() { -- ip, protocol := resolveClientIPAndProtocol(&net.TCPAddr{IP: net.ParseIP("192.168.178.88")}) -- Expect(ip).Should(Equal(net.ParseIP("192.168.178.88"))) -- Expect(protocol).Should(Equal(model.RequestProtocolTCP)) -- }) -- }) -- }) -- -- Describe("self-signed certificate creation", func() { -- var ( -- cfg config.Config -- cErr error -- ) -- BeforeEach(func() { -- cErr = defaults.Set(&cfg) -- -- Expect(cErr).Should(Succeed()) -- -- cfg.Upstreams.Groups = map[string][]config.Upstream{ -- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "1.1.1.1", Port: 53}}, -- } -- }) -- -- It("should create self-signed certificate if key/cert files are not provided", func() { -- cfg.KeyFile = "" -- cfg.CertFile = "" -- cfg.Ports = config.PortsConfig{ -- HTTPS: []string{":14443"}, -- } -- -- sut, err := NewServer(&cfg) -- Expect(err).Should(Succeed()) -- Expect(sut.cert.Certificate).ShouldNot(BeNil()) -- }) -- }) --}) -- --func requestServer(request *dns.Msg) *dns.Msg { -- conn, err := net.Dial("udp", ":55555") -- if err != nil { -- Log().Fatal("could not connect to server: ", err) -- } -- defer conn.Close() -- -- msg, err := request.Pack() -- if err != nil { -- Log().Fatal("can't pack request: ", err) -- } -- -- _, err = conn.Write(msg) -- if err != nil { -- Log().Fatal("can't send request to server: ", err) -- } -- -- out := make([]byte, 1024) -- -- if _, err := conn.Read(out); err == nil { -- response := new(dns.Msg) -- -- err = response.Unpack(out) -- -- if err != nil { -- Log().Fatal("can't unpack response: ", err) -- } -- -- return response -- } -- -- Log().Fatal("could not read from connection", err) -- -- return nil --} -- --func writeCertPem(tmpDir *TmpFolder) *TmpFile { -- return tmpDir.CreateStringFile("cert.pem", -- "-----BEGIN CERTIFICATE-----", -- "MIICMzCCAZygAwIBAgIRAJCCrDTGEtZfRpxDY1KAoswwDQYJKoZIhvcNAQELBQAw", -- "EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2", -- "MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw", -- "gYkCgYEA4mEaF5yWYYrTfMgRXdBpgGnqsHIADQWlw7BIJWD/gNp+fgp4TUZ/7ggV", -- "rrvRORvRFjw14avd9L9EFP7XLi8ViU3uoE1UWI32MlrKqLbGNCXyUIApIoqlbRg6", -- "iErxIk5+ChzFuysQOx01S2yv/ML6dx7NOGHs1S38MUzRZtcXBH8CAwEAAaOBhjCB", -- "gzAOBgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/", -- "BAUwAwEB/zAdBgNVHQ4EFgQUslNI6tYIv909RttHaZVMS/u/VYYwLAYDVR0RBCUw", -- "I4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEB", -- "CwUAA4GBAJ2gRpQHr5Qj7dt26bYVMdN4JGXTsvjbVrJfKI0VfPGJ+SUY/uTVBUeX", -- "+Cwv4DFEPBlNx/lzuUkwmRaExC4/w81LWwxe5KltYsjyJuYowiUbLZ6tzLaQ9Bcx", -- "jxClAVvgj90TGYOwsv6ESOX7GWteN1FlD3+jk7vefjFagaKKFYR9", -- "-----END CERTIFICATE-----") --} -- --func writeKeyPem(tmpDir *TmpFolder) *TmpFile { -- return tmpDir.CreateStringFile("key.pem", -- "-----BEGIN PRIVATE KEY-----", -- "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOJhGheclmGK03zI", -- "EV3QaYBp6rByAA0FpcOwSCVg/4Dafn4KeE1Gf+4IFa670Tkb0RY8NeGr3fS/RBT+", -- "1y4vFYlN7qBNVFiN9jJayqi2xjQl8lCAKSKKpW0YOohK8SJOfgocxbsrEDsdNUts", -- "r/zC+ncezThh7NUt/DFM0WbXFwR/AgMBAAECgYEA1exixstPhI+2+OTrHFc1S4dL", -- "oz+ncqbSlZEBLGl0KWTQQfVM5+FmRR7Yto1/0lLKDBQL6t0J2x3fjWOhHmCaHKZA", -- "VAvZ8+OKxwofih3hlO0tGCB8szUJygp2FAmd0rOUqvPQ+PTohZEUXyDaB8MOIbX+", -- "qoo7g19+VlbyKqmM8HkCQQDs4GQJwEn7GXKllSMyOfiYnjQM2pwsqO0GivXkH+p3", -- "+h5KDp4g3O4EbmbrvZyZB2euVsBjW3pFMu+xPXuOXf91AkEA9KfC7LGLD2OtLmrM", -- "iCZAqHlame+uEEDduDmqjTPnNKUWVeRtYKMF5Hltbeo1jMXMSbVZ+fRWKfQ+HAhQ", -- "xjFJowJAV6U7PqRoe0FSO1QwXrA2fHnk9nCY4qlqckZObyckAVqJhIteFPjKFNeo", -- "u0dAPxsPUOGGc/zwA9Sx/ZmrMuUy1QJBALl7bqawO/Ng6G0mfwZBqgeQaYYHVnnw", -- "E6iV353J2eHpvzNDSUFYlyEOhk4soIindSf0m9CK08Be8a+jBkocF+0CQQC+Hi7L", -- "kZV1slpW82BxYIhs9Gb0OQgK8SsI4aQPTFGUarQXXAm4eRqBO0kaG+jGX6TtW353", -- "EHK784GIxwVXKej/", -- "-----END PRIVATE KEY-----") --} -diff --git a/resolver/hosts_file_resolver_test.go b/resolver/hosts_file_resolver_test.go -deleted file mode 100644 -index eef4591..0000000 ---- a/resolver/hosts_file_resolver_test.go -+++ /dev/null -@@ -1,376 +0,0 @@ --package resolver -- --import ( -- "context" -- "time" -- -- "github.com/0xERR0R/blocky/config" -- . "github.com/0xERR0R/blocky/helpertest" -- "github.com/0xERR0R/blocky/log" -- . "github.com/0xERR0R/blocky/model" -- "github.com/miekg/dns" -- . "github.com/onsi/ginkgo/v2" -- . "github.com/onsi/gomega" -- "github.com/stretchr/testify/mock" --) -- --var _ = Describe("HostsFileResolver", func() { -- var ( -- TTL = uint32(time.Now().Second()) -- -- sut *HostsFileResolver -- sutConfig config.HostsFileConfig -- m *mockResolver -- tmpDir *TmpFolder -- tmpFile *TmpFile -- ) -- -- Describe("Type", func() { -- It("follows conventions", func() { -- expectValidResolverType(sut) -- }) -- }) -- -- BeforeEach(func() { -- tmpDir = NewTmpFolder("HostsFileResolver") -- Expect(tmpDir.Error).Should(Succeed()) -- DeferCleanup(tmpDir.Clean) -- -- tmpFile = writeHostFile(tmpDir) -- Expect(tmpFile.Error).Should(Succeed()) -- -- sutConfig = config.HostsFileConfig{ -- Sources: config.NewBytesSources(tmpFile.Path), -- HostsTTL: config.Duration(time.Duration(TTL) * time.Second), -- FilterLoopback: true, -- Loading: config.SourceLoadingConfig{ -- RefreshPeriod: -1, -- MaxErrorsPerSource: 5, -- }, -- } -- }) -- -- JustBeforeEach(func() { -- var err error -- -- sut, err = NewHostsFileResolver(sutConfig, systemResolverBootstrap) -- Expect(err).Should(Succeed()) -- -- m = &mockResolver{} -- m.On("Resolve", mock.Anything).Return(&Response{Res: new(dns.Msg)}, nil) -- sut.Next(m) -- }) -- -- Describe("IsEnabled", func() { -- It("is true", func() { -- Expect(sut.IsEnabled()).Should(BeTrue()) -- }) -- }) -- -- Describe("LogConfig", func() { -- It("should log something", func() { -- logger, hook := log.NewMockEntry() -- -- sut.LogConfig(logger) -- -- Expect(hook.Calls).ShouldNot(BeEmpty()) -- }) -- }) -- -- Describe("Using hosts file", func() { -- When("Hosts file cannot be located", func() { -- BeforeEach(func() { -- sutConfig = config.HostsFileConfig{ -- Sources: config.NewBytesSources("/this/file/does/not/exist"), -- HostsTTL: config.Duration(time.Duration(TTL) * time.Second), -- } -- }) -- It("should not parse any hosts", func() { -- Expect(sut.cfg.Sources).ShouldNot(BeEmpty()) -- Expect(sut.hosts.v4.hosts).Should(BeEmpty()) -- Expect(sut.hosts.v6.hosts).Should(BeEmpty()) -- Expect(sut.hosts.v4.aliases).Should(BeEmpty()) -- Expect(sut.hosts.v6.aliases).Should(BeEmpty()) -- Expect(sut.hosts.isEmpty()).Should(BeTrue()) -- }) -- It("should go to next resolver on query", func() { -- Expect(sut.Resolve(newRequest("example.com.", A))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeRESOLVED), -- HaveReturnCode(dns.RcodeSuccess), -- )) -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- -- When("Hosts file is not set", func() { -- BeforeEach(func() { -- sutConfig.Deprecated.Filepath = new(config.BytesSource) -- sutConfig.Sources = nil -- -- m = &mockResolver{} -- m.On("Resolve", mock.Anything).Return(&Response{Res: new(dns.Msg)}, nil) -- sut.Next(m) -- }) -- It("should not return an error", func() { -- err := sut.loadSources(context.Background()) -- Expect(err).Should(Succeed()) -- }) -- It("should go to next resolver on query", func() { -- Expect(sut.Resolve(newRequest("example.com.", A))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeRESOLVED), -- HaveReturnCode(dns.RcodeSuccess), -- )) -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- -- When("Hosts file can be located", func() { -- It("should parse it successfully", func() { -- Expect(sut).ShouldNot(BeNil()) -- Expect(sut.hosts.v4.hosts).Should(HaveLen(5)) -- Expect(sut.hosts.v6.hosts).Should(HaveLen(2)) -- Expect(sut.hosts.v4.aliases).Should(HaveLen(4)) -- Expect(sut.hosts.v6.aliases).Should(HaveLen(2)) -- }) -- -- When("filterLoopback is false", func() { -- BeforeEach(func() { -- sutConfig.FilterLoopback = false -- }) -- -- It("should parse it successfully", func() { -- Expect(sut).ShouldNot(BeNil()) -- Expect(sut.hosts.v4.hosts).Should(HaveLen(7)) -- Expect(sut.hosts.v6.hosts).Should(HaveLen(3)) -- Expect(sut.hosts.v4.aliases).Should(HaveLen(5)) -- Expect(sut.hosts.v6.aliases).Should(HaveLen(2)) -- }) -- }) -- }) -- -- When("Hosts file has too many errors", func() { -- BeforeEach(func() { -- tmpFile = tmpDir.CreateStringFile("hosts-too-many-errors.txt", -- "invalidip localhost", -- "127.0.0.1 localhost", // ok -- "127.0.0.1 # no host", -- "127.0.0.1 invalidhost!", -- "a.b.c.d localhost", -- "127.0.0.x localhost", -- "256.0.0.1 localhost", -- ) -- Expect(tmpFile.Error).Should(Succeed()) -- -- sutConfig.Sources = config.NewBytesSources(tmpFile.Path) -- }) -- -- It("should not be used", func() { -- Expect(sut).ShouldNot(BeNil()) -- Expect(sut.cfg.Sources).ShouldNot(BeEmpty()) -- Expect(sut.hosts.v4.hosts).Should(BeEmpty()) -- Expect(sut.hosts.v6.hosts).Should(BeEmpty()) -- Expect(sut.hosts.v4.aliases).Should(BeEmpty()) -- Expect(sut.hosts.v6.aliases).Should(BeEmpty()) -- }) -- }) -- -- When("IPv4 mapping is defined for a host", func() { -- It("defined ipv4 query should be resolved", func() { -- Expect(sut.Resolve(newRequest("ipv4host.", A))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- BeDNSRecord("ipv4host.", A, "192.168.2.1"), -- HaveTTL(BeNumerically("==", TTL)), -- )) -- }) -- It("defined ipv4 query for alias should be resolved", func() { -- Expect(sut.Resolve(newRequest("router2.", A))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- BeDNSRecord("router2.", A, "10.0.0.1"), -- HaveTTL(BeNumerically("==", TTL)), -- )) -- }) -- It("ipv4 query should return NOERROR and empty result", func() { -- Expect(sut.Resolve(newRequest("does.not.exist.", A))). -- Should( -- SatisfyAll( -- HaveNoAnswer(), -- HaveReturnCode(dns.RcodeSuccess), -- HaveResponseType(ResponseTypeRESOLVED), -- )) -- }) -- }) -- -- When("IPv6 mapping is defined for a host", func() { -- It("defined ipv6 query should be resolved", func() { -- Expect(sut.Resolve(newRequest("ipv6host.", AAAA))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- BeDNSRecord("ipv6host.", AAAA, "faaf:faaf:faaf:faaf::1"), -- HaveTTL(BeNumerically("==", TTL)), -- )) -- }) -- It("ipv6 query should return NOERROR and empty result", func() { -- Expect(sut.Resolve(newRequest("does.not.exist.", AAAA))). -- Should( -- SatisfyAll( -- HaveNoAnswer(), -- HaveReturnCode(dns.RcodeSuccess), -- HaveResponseType(ResponseTypeRESOLVED), -- )) -- }) -- }) -- -- When("the domain is not known", func() { -- It("calls the next resolver", func() { -- resp, err := sut.Resolve(newRequest("not-in-hostsfile.tld.", A)) -- Expect(err).Should(Succeed()) -- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- -- When("the question type is not handled", func() { -- It("calls the next resolver", func() { -- resp, err := sut.Resolve(newRequest("localhost.", MX)) -- Expect(err).Should(Succeed()) -- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- -- When("Reverse DNS request is received", func() { -- It("should resolve the defined domain name", func() { -- By("ipv4 with one hostname", func() { -- Expect(sut.Resolve(newRequest("2.0.0.10.in-addr.arpa.", PTR))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- BeDNSRecord("2.0.0.10.in-addr.arpa.", PTR, "router3."), -- HaveTTL(BeNumerically("==", TTL)), -- )) -- }) -- By("ipv4 with aliases", func() { -- Expect(sut.Resolve(newRequest("1.0.0.10.in-addr.arpa.", PTR))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- WithTransform(ToAnswer, ContainElements( -- BeDNSRecord("1.0.0.10.in-addr.arpa.", PTR, "router0."), -- BeDNSRecord("1.0.0.10.in-addr.arpa.", PTR, "router1."), -- BeDNSRecord("1.0.0.10.in-addr.arpa.", PTR, "router2."), -- )), -- )) -- }) -- By("ipv6", func() { -- Expect(sut.Resolve(newRequest("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.a.a.f.f.a.a.f.f.a.a.f.f.a.a.f.ip6.arpa.", PTR))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- WithTransform(ToAnswer, ContainElements( -- BeDNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.a.a.f.f.a.a.f.f.a.a.f.f.a.a.f.ip6.arpa.", -- PTR, "ipv6host."), -- BeDNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.a.a.f.f.a.a.f.f.a.a.f.f.a.a.f.ip6.arpa.", -- PTR, "ipv6host.local.lan."), -- )), -- )) -- }) -- }) -- -- It("should ignore invalid PTR", func() { -- resp, err := sut.Resolve(newRequest("2.0.0.10.in-addr.fail.arpa.", PTR)) -- Expect(err).Should(Succeed()) -- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) -- m.AssertExpectations(GinkgoT()) -- }) -- -- When("filterLoopback is true", func() { -- It("calls the next resolver", func() { -- resp, err := sut.Resolve(newRequest("1.0.0.127.in-addr.arpa.", PTR)) -- Expect(err).Should(Succeed()) -- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- -- When("the IP is not known", func() { -- It("calls the next resolver", func() { -- resp, err := sut.Resolve(newRequest("255.255.255.255.in-addr.arpa.", PTR)) -- Expect(err).Should(Succeed()) -- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- -- When("filterLoopback is false", func() { -- BeforeEach(func() { -- sutConfig.FilterLoopback = false -- }) -- -- It("resolve the defined domain name", func() { -- Expect(sut.Resolve(newRequest("1.1.0.127.in-addr.arpa.", PTR))). -- Should( -- SatisfyAll( -- HaveResponseType(ResponseTypeHOSTSFILE), -- HaveReturnCode(dns.RcodeSuccess), -- WithTransform(ToAnswer, ContainElements( -- BeDNSRecord("1.1.0.127.in-addr.arpa.", PTR, "localhost2."), -- BeDNSRecord("1.1.0.127.in-addr.arpa.", PTR, "localhost2.local.lan."), -- )), -- )) -- }) -- }) -- }) -- }) -- -- Describe("Delegating to next resolver", func() { -- When("no hosts file is provided", func() { -- It("should delegate to next resolver", func() { -- _, err := sut.Resolve(newRequest("example.com.", A)) -- Expect(err).Should(Succeed()) -- // delegate was executed -- m.AssertExpectations(GinkgoT()) -- }) -- }) -- }) --}) -- --func writeHostFile(tmpDir *TmpFolder) *TmpFile { -- return tmpDir.CreateStringFile("hosts.txt", -- "# Random comment", -- "127.0.0.1 localhost", -- "127.0.1.1 localhost2 localhost2.local.lan", -- "::1 localhost", -- "# Two empty lines to follow", -- "", -- "", -- "faaf:faaf:faaf:faaf::1 ipv6host ipv6host.local.lan", -- "192.168.2.1 ipv4host ipv4host.local.lan", -- "faaf:faaf:faaf:faaf::2 dualhost dualhost.local.lan", -- "192.168.2.2 dualhost dualhost.local.lan", -- "10.0.0.1 router0 router1 router2", -- "10.0.0.2 router3 # Another comment", -- "10.0.0.3 router4#comment without a space", -- "10.0.0.4 # Invalid entry", -- "300.300.300.300 invalid4 # Invalid IPv4", -- "abcd:efgh:ijkl::1 invalid6 # Invalid IPv6", -- "1.2.3.4 localhost", // localhost name but not localhost IP -- -- // from https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts -- "fe80::1%lo0 localhost", // interface name -- ) --}
