From b5b2ddb84a04debbf39b633bf463db78547efec3 Mon Sep 17 00:00:00 2001 From: Nico D'Cotta <45274424+cottand@users.noreply.github.com> Date: Mon, 16 Dec 2024 19:18:31 +0000 Subject: [PATCH] api: (BREAKING) remove question cache (#81) This removes a feature inherited from grimd, which keeps track of historic dns queries and exposed them in the API. This is not to be confised with the response cache (which caches DNS queries' responses). The question 'cache' keeps only DNS questions and is not functional to answering DNS queries. Since inheriting this feature, leng now has metrics which achieve similar functionality - only it exposes it via a different API (prometheus). Thes endpoints are thus now deprecated. --- api.go | 47 +++++++---------------------------------------- cache.go | 43 ------------------------------------------- cache_test.go | 25 ------------------------- grimd_test.go | 10 +++------- handler.go | 28 ++++++++-------------------- main.go | 19 ++++++------------- server.go | 8 ++------ utils.go | 4 ---- 8 files changed, 26 insertions(+), 158 deletions(-) diff --git a/api.go b/api.go index eaa7e06..70e1ea0 100644 --- a/api.go +++ b/api.go @@ -8,7 +8,6 @@ import ( "net/http" "os" "path/filepath" - "strconv" "strings" "time" @@ -30,10 +29,7 @@ func isRunningInDockerContainer() bool { } // StartAPIServer starts the API server -func StartAPIServer(config *Config, - reloadChan chan bool, - blockCache *MemoryBlockCache, - questionCache *MemoryQuestionCache) (*http.Server, error) { +func StartAPIServer(config *Config, reloadChan chan bool, blockCache *MemoryBlockCache) (*http.Server, error) { if !config.APIDebug { gin.SetMode(gin.ReleaseMode) } @@ -167,53 +163,24 @@ func StartAPIServer(config *Config, }) router.GET("/questioncache", func(c *gin.Context) { - highWater, err := strconv.ParseInt(c.DefaultQuery("highWater", "-1"), 10, 64) - if err != nil { - highWater = -1 - } - c.IndentedJSON(http.StatusOK, gin.H{ - "length": questionCache.Length(), - "items": questionCache.GetOlder(highWater), - }) + c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "invalid request - endpoint has been deprecated"}) }) router.GET("/questioncache/length", func(c *gin.Context) { - c.IndentedJSON(http.StatusOK, gin.H{"length": questionCache.Length()}) + c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "invalid request - endpoint has been deprecated"}) }) router.GET("/questioncache/clear", func(c *gin.Context) { - questionCache.Clear() - c.IndentedJSON(http.StatusOK, gin.H{"success": true}) + c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "invalid request - endpoint has been deprecated"}) }) router.GET("/questioncache/client/:client", func(c *gin.Context) { - var filteredCache []QuestionCacheEntry - - questionCache.mu.RLock() - for _, entry := range questionCache.Backend { - if entry.Remote == c.Param("client") { - filteredCache = append(filteredCache, entry) - } - } - questionCache.mu.RUnlock() - - c.IndentedJSON(http.StatusOK, filteredCache) + c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "invalid request - endpoint has been deprecated"}) }) router.GET("/questioncache/client", func(c *gin.Context) { - clientList := make(map[string]bool) - questionCache.mu.RLock() - for _, entry := range questionCache.Backend { - if _, ok := clientList[entry.Remote]; !ok { - clientList[entry.Remote] = true - } - } - questionCache.mu.RUnlock() - var clients []string - for client := range clientList { - clients = append(clients, client) - } - c.IndentedJSON(http.StatusOK, clients) + c.IndentedJSON(http.StatusBadRequest, gin.H{"error": "invalid request - endpoint has been deprecated"}) + }) router.OPTIONS("/application/active", func(c *gin.Context) { diff --git a/cache.go b/cache.go index 3244f42..ba68ef2 100644 --- a/cache.go +++ b/cache.go @@ -73,13 +73,6 @@ type MemoryBlockCache struct { mu sync.RWMutex } -// MemoryQuestionCache type -type MemoryQuestionCache struct { - Backend []QuestionCacheEntry `json:"entry"` - Maxcount int - mu sync.RWMutex -} - // Get returns the entry for a key or an error func (c *MemoryCache) Get(key string) (*dns.Msg, bool, error) { key = strings.ToLower(key) @@ -278,39 +271,3 @@ func (c *MemoryBlockCache) Length() int { defer c.mu.RUnlock() return len(c.Backend) } - -// Add adds a question to the cache -func (c *MemoryQuestionCache) Add(q QuestionCacheEntry) { - c.mu.Lock() - if c.Maxcount != 0 && len(c.Backend) >= c.Maxcount { - c.Backend = nil - } - c.Backend = append(c.Backend, q) - c.mu.Unlock() -} - -// Clear clears the contents of the cache -func (c *MemoryQuestionCache) Clear() { - c.mu.Lock() - c.Backend = make([]QuestionCacheEntry, 0, 0) - c.mu.Unlock() -} - -// Length returns the caches length -func (c *MemoryQuestionCache) Length() int { - c.mu.RLock() - defer c.mu.RUnlock() - return len(c.Backend) -} - -// GetOlder eturns a slice of the entries older than `time` -func (c *MemoryQuestionCache) GetOlder(time int64) []QuestionCacheEntry { - c.mu.RLock() - defer c.mu.RUnlock() - for i, e := range c.Backend { - if e.Date > time { - return c.Backend[i:] - } - } - return []QuestionCacheEntry{} -} diff --git a/cache_test.go b/cache_test.go index 83a6296..3de1bb5 100644 --- a/cache_test.go +++ b/cache_test.go @@ -296,31 +296,6 @@ func TestExpirationRace(t *testing.T) { } */ -func addToCache(cache *MemoryQuestionCache, time int64) { - cache.Add(QuestionCacheEntry{ - Date: time, - Remote: fmt.Sprintf("%d", time), - Blocked: true, - Query: Question{}, - }) -} - -func TestQuestionCacheGetFromTimestamp(t *testing.T) { - memCache := makeQuestionCache(100) - for i := 0; i < 100; i++ { - addToCache(memCache, int64(i)) - } - - entries := memCache.GetOlder(50) - assert.Len(t, entries, 49) - entries = memCache.GetOlder(0) - assert.Len(t, entries, 99) - entries = memCache.GetOlder(-1) - assert.Len(t, entries, 100) - entries = memCache.GetOlder(200) - assert.Len(t, entries, 0) -} - func BenchmarkSetCache(b *testing.B) { cache := makeCache() diff --git a/grimd_test.go b/grimd_test.go index 3b04902..c96c461 100644 --- a/grimd_test.go +++ b/grimd_test.go @@ -59,13 +59,11 @@ func integrationTest(changeConfig func(c *Config), test func(client *dns.Client, for _, blocked := range config.Blocking.Blocklist { _ = blockCache.Set(blocked, true) } - // QuestionCache contains all queries to the dns server - questionCache := makeQuestionCache(config.QuestionCacheCap) reloadChan := make(chan bool) - _, _ = StartAPIServer(&config, reloadChan, blockCache, questionCache) + _, _ = StartAPIServer(&config, reloadChan, blockCache) defer close(reloadChan) - server.Run(&config, blockCache, questionCache) + server.Run(&config, blockCache) time.Sleep(200 * time.Millisecond) defer server.Stop() @@ -358,10 +356,8 @@ func TestConfigReloadForCustomRecords(t *testing.T) { // BlockCache contains all blocked domains blockCache := &MemoryBlockCache{Backend: make(map[string]bool)} - // QuestionCache contains all queries to the dns server - questionCache := makeQuestionCache(config.QuestionCacheCap) - server.Run(&config, blockCache, questionCache) + server.Run(&config, blockCache) time.Sleep(200 * time.Millisecond) defer server.Stop() diff --git a/handler.go b/handler.go index feaf7bf..ded8625 100644 --- a/handler.go +++ b/handler.go @@ -2,12 +2,10 @@ package main import ( "github.com/cottand/leng/internal/metric" + "github.com/miekg/dns" "net" "slices" "sync" - "time" - - "github.com/miekg/dns" ) const ( @@ -42,13 +40,12 @@ type EventLoop struct { resolver *Resolver cache Cache // negCache caches failures - negCache Cache - active bool - muActive sync.RWMutex - config *Config - blockCache *MemoryBlockCache - questionCache *MemoryQuestionCache - customDns *CustomRecordsResolver + negCache Cache + active bool + muActive sync.RWMutex + config *Config + blockCache *MemoryBlockCache + customDns *CustomRecordsResolver } // DNSOperationData type @@ -59,7 +56,7 @@ type DNSOperationData struct { } // NewEventLoop returns a new eventLoop -func NewEventLoop(config *Config, blockCache *MemoryBlockCache, questionCache *MemoryQuestionCache) *EventLoop { +func NewEventLoop(config *Config, blockCache *MemoryBlockCache) *EventLoop { var ( clientConfig *dns.ClientConfig resolver *Resolver @@ -84,7 +81,6 @@ func NewEventLoop(config *Config, blockCache *MemoryBlockCache, questionCache *M cache: cache, negCache: negCache, blockCache: blockCache, - questionCache: questionCache, active: true, config: config, customDns: NewCustomRecordsResolver(NewCustomDNSRecordsFromText(config.CustomDNSRecords)), @@ -194,10 +190,6 @@ func (h *EventLoop) responseFor(Net string, req *dns.Msg, _local net.Addr, _remo logger.Noticef("%s found in blocklist\n", Q.Qname) - // log query - NewEntry := QuestionCacheEntry{Date: time.Now().Unix(), Remote: remote.String(), Query: Q, Blocked: true} - go h.questionCache.Add(NewEntry) - // cache the block; we don't know the true TTL for blocked entries: we just enforce our config err := h.cache.Set(key, m, true) if err != nil { @@ -209,10 +201,6 @@ func (h *EventLoop) responseFor(Net string, req *dns.Msg, _local net.Addr, _remo logger.Debugf("%s not found in blocklist\n", Q.Qname) } - // log query - NewEntry := QuestionCacheEntry{Date: time.Now().Unix(), Remote: remote.String(), Query: Q, Blocked: false} - go h.questionCache.Add(NewEntry) - mesg, err := h.resolver.Lookup(Net, req, h.config.Timeout, h.config.Interval, h.config.Upstream.Nameservers, h.config.Upstream.DoH) if err != nil { diff --git a/main.go b/main.go index 2d80838..bf01625 100644 --- a/main.go +++ b/main.go @@ -18,12 +18,7 @@ var ( lengActive bool ) -func reloadBlockCache(config *Config, - blockCache *MemoryBlockCache, - questionCache *MemoryQuestionCache, - apiServer *http.Server, - server *Server, - reloadChan chan bool) (*MemoryBlockCache, *http.Server, error) { +func reloadBlockCache(config *Config, blockCache *MemoryBlockCache, apiServer *http.Server, server *Server, reloadChan chan bool) (*MemoryBlockCache, *http.Server, error) { logger.Debug("Reloading the blockcache") blockCache = PerformUpdate(config, true) @@ -33,8 +28,8 @@ func reloadBlockCache(config *Config, logger.Debugf("error shutting down api server: %v", err) } } - server.Run(config, blockCache, questionCache) - apiServer, err := StartAPIServer(config, reloadChan, blockCache, questionCache) + server.Run(config, blockCache) + apiServer, err := StartAPIServer(config, reloadChan, blockCache) if err != nil { logger.Fatal(err) return nil, nil, err @@ -81,18 +76,16 @@ func main() { // BlockCache contains all blocked domains blockCache := &MemoryBlockCache{Backend: make(map[string]bool)} - // QuestionCache contains all queries to the dns server - questionCache := makeQuestionCache(config.QuestionCacheCap) reloadChan := make(chan bool) // The server will start with an empty blockcache soe we can dowload the lists if leng is the // system's dns server. - server.Run(config, blockCache, questionCache) + server.Run(config, blockCache) var apiServer *http.Server // Load the block cache, restart the server with the new context - blockCache, apiServer, err = reloadBlockCache(config, blockCache, questionCache, apiServer, server, reloadChan) + blockCache, apiServer, err = reloadBlockCache(config, blockCache, apiServer, server, reloadChan) if err != nil { logger.Fatalf("Cannot start the API server %s", err) @@ -122,7 +115,7 @@ forever: reloadConfigFromFile(server) } case <-reloadChan: - blockCache, apiServer, err = reloadBlockCache(config, blockCache, questionCache, apiServer, server, reloadChan) + blockCache, apiServer, err = reloadBlockCache(config, blockCache, apiServer, server, reloadChan) if err != nil { logger.Fatalf("Cannot start the API server %s", err) } diff --git a/server.go b/server.go index 08bb816..025101b 100644 --- a/server.go +++ b/server.go @@ -22,13 +22,9 @@ type Server struct { } // Run starts the server -func (s *Server) Run( - config *Config, - blockCache *MemoryBlockCache, - questionCache *MemoryQuestionCache, -) { +func (s *Server) Run(config *Config, blockCache *MemoryBlockCache) { - s.eventLoop = NewEventLoop(config, blockCache, questionCache) + s.eventLoop = NewEventLoop(config, blockCache) tcpHandler := dns.NewServeMux() tcpHandler.HandleFunc(".", s.eventLoop.DoTCP) diff --git a/utils.go b/utils.go index e4bc57f..69387fd 100644 --- a/utils.go +++ b/utils.go @@ -7,10 +7,6 @@ func makeCache() MemoryCache { } } -func makeQuestionCache(maxCount int) *MemoryQuestionCache { - return &MemoryQuestionCache{Backend: make([]QuestionCacheEntry, 0), Maxcount: maxCount} -} - // Difference between to lists: A - B func difference[T comparable](a, b []T) (diff []T) { m := make(map[T]bool)