diff --git a/README.md b/README.md index 8c9b4cc..cf3219b 100644 --- a/README.md +++ b/README.md @@ -54,158 +54,6 @@ include `asn`. Unmapped countries use `ZZ`; unmapped ASNs use `0`. - `dnstt_bytes_out_total` - `dnstt_sessions_total` -## Grafana Queries - -Use `$domain` as a Grafana variable for the DNSTT domain, for example -`t2.bypasscensorship.org`. Replace `$__rate_interval` with a fixed range such -as `5m` if you are not using Grafana's built-in interval variables. - -- Title: Current active clients -- Description: Current number of active DNSTT sessions for the selected domain. -- Visualization: Stat or gauge. - -```promql -sum(dnstt_active_clients{domain="$domain"}) -``` - -- Title: Peak active clients -- Description: Highest active DNSTT session count observed since the exporter -started. -- Visualization: Stat. - -```promql -sum(dnstt_peak_clients{domain="$domain"}) -``` - -- Title: Active clients by country -- Description: Current active DNSTT sessions grouped by resolver country. -- Visualization: Geomap, bar chart, or table. - -```promql -sum by (country) (dnstt_active_clients{domain="$domain"}) -``` - -- Title: Top countries by active clients -- Description: Countries with the most active DNSTT sessions right now. -- Visualization: Bar chart. - -```promql -topk(10, sum by (country) (dnstt_active_clients{domain="$domain"})) -``` - -- Title: Active clients by ASN -- Description: Current active DNSTT sessions grouped by resolver ASN. -- Visualization: Bar chart or table. - -```promql -sum by (asn) (dnstt_active_clients{domain="$domain"}) -``` - -- Title: Top ASNs by active clients -- Description: Resolver ASNs with the most active DNSTT sessions right now. -- Visualization: Bar chart. - -```promql -topk(10, sum by (asn) (dnstt_active_clients{domain="$domain"})) -``` - -- Title: Active clients by country and ASN -- Description: Current active DNSTT sessions split by both resolver country and -resolver ASN. -- Visualization: Table. - -```promql -sum by (country, asn) (dnstt_active_clients{domain="$domain"}) -``` - -- Title: Top country/ASN pairs by active clients -- Description: Country and ASN combinations with the most active DNSTT sessions -right now. -- Visualization: Bar chart or table. - -```promql -topk(20, sum by (country, asn) (dnstt_active_clients{domain="$domain"})) -``` - -- Title: DNS query rate -- Description: Total observed DNSTT DNS queries per second for the selected -domain. -- Visualization: Time series. - -```promql -sum(rate(dnstt_queries_total{domain="$domain"}[$__rate_interval])) -``` - -- Title: DNS query rate by country -- Description: Observed DNSTT DNS queries per second grouped by resolver country. -- Visualization: Stacked time series or bar chart. Use stacked time series for -trends over time, and bar chart for current top countries. - -```promql -sum by (country) (rate(dnstt_queries_total{domain="$domain"}[$__rate_interval])) -``` - -- Title: Top ASNs by DNS query rate -- Description: Resolver ASNs producing the highest DNSTT DNS query rates. -- Visualization: Bar chart. - -```promql -topk(10, sum by (asn) (rate(dnstt_queries_total{domain="$domain"}[$__rate_interval]))) -``` - -- Title: Inbound DNS traffic rate -- Description: Bytes per second received in DNSTT DNS queries. -- Visualization: Time series. - -```promql -sum(rate(dnstt_bytes_in_total{domain="$domain"}[$__rate_interval])) -``` - -- Title: Outbound DNS traffic rate -- Description: Bytes per second sent in DNSTT DNS responses. -- Visualization: Time series. - -```promql -sum(rate(dnstt_bytes_out_total{domain="$domain"}[$__rate_interval])) -``` - -- Title: DNS traffic rate by country -- Description: Combined inbound and outbound DNSTT DNS bytes per second grouped -by resolver country. -- Visualization: Geomap, stacked time series, or bar chart. - -```promql -sum by (country) ( - rate(dnstt_bytes_in_total{domain="$domain"}[$__rate_interval]) - + - rate(dnstt_bytes_out_total{domain="$domain"}[$__rate_interval]) -) -``` - -- Title: Total observed sessions -- Description: Total unique DNSTT sessions observed since the exporter started. -- Visualization: Stat. - -```promql -sum(dnstt_sessions_total{domain="$domain"}) -``` - -- Title: New session rate -- Description: New DNSTT sessions observed per second. -- Visualization: Time series. - -```promql -sum(rate(dnstt_sessions_total{domain="$domain"}[$__rate_interval])) -``` - -- Title: New session rate by country -- Description: New DNSTT sessions per second grouped by resolver country. -- Visualization: Stacked time series, geomap, or bar chart. - -```promql -sum by (country) (rate(dnstt_sessions_total{domain="$domain"}[$__rate_interval])) -``` - ## Development ```sh diff --git a/flake.lock b/flake.lock index be257e5..24eab79 100644 --- a/flake.lock +++ b/flake.lock @@ -2,18 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1779622335, - "narHash": "sha256-ViA62qtL5za7V3d5I8OA9q9JcFhsVAiL5jVHwEclWqk=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "705e9929918b43bd7b715dc0a878ac870449bb03", - "type": "github" + "lastModified": 1777578337, + "narHash": "sha256-Ad49moKWeXtKBJNy2ebiTQUEgdLyvGmTeykAQ9xM+Z4=", + "rev": "15f4ee454b1dce334612fa6843b3e05cf546efab", + "revCount": 990025, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.990025%2Brev-15f4ee454b1dce334612fa6843b3e05cf546efab/019de756-85a1-7400-84a3-d277a7ed191b/source.tar.gz" }, "original": { - "owner": "nixos", - "ref": "nixos-26.05", - "repo": "nixpkgs", - "type": "github" + "type": "tarball", + "url": "https://flakehub.com/f/NixOS/nixpkgs/0.1" } }, "root": { diff --git a/flake.nix b/flake.nix index ca0eb0b..af586d9 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-26.05"; + inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1"; outputs = { self, nixpkgs }: let diff --git a/internal/dnstt/collector.go b/internal/dnstt/collector.go index 175b712..4928c16 100644 --- a/internal/dnstt/collector.go +++ b/internal/dnstt/collector.go @@ -167,12 +167,9 @@ func (c *Collector) RecordQueryFrom(domain string, clientID string, resolverIP n now := c.now() client, exists := tunnel.clients[clientID] - updatePeak := !exists if !exists { client = &clientState{firstSeen: now, firstKey: key} tunnel.clients[clientID] = client - } else if now.Sub(client.lastSeen) >= ClientTimeout || client.lastKey != key { - updatePeak = true } client.lastSeen = now client.lastKey = key @@ -181,9 +178,7 @@ func (c *Collector) RecordQueryFrom(domain string, clientID string, resolverIP n client.bytesIn += uint64(size) } - if updatePeak { - updatePeaks(tunnel, now) - } + updatePeaks(tunnel, now) } // RecordResponse records an observed DNSTT DNS response. @@ -216,6 +211,7 @@ func (c *Collector) Snapshot() Snapshot { snapshot := Snapshot{Tunnels: make(map[string]TunnelSnapshot, len(c.tunnels))} for _, domain := range c.domains { tunnel := c.tunnels[domain] + updatePeaks(tunnel, now) series := c.seriesSnapshotsLocked(domain, tunnel, now) tunnelSnapshot := TunnelSnapshot{Domain: domain, Series: series} diff --git a/internal/dnstt/collector_test.go b/internal/dnstt/collector_test.go index 8f31044..d46c923 100644 --- a/internal/dnstt/collector_test.go +++ b/internal/dnstt/collector_test.go @@ -1,7 +1,6 @@ package dnstt import ( - "net/netip" "testing" "time" ) @@ -60,36 +59,3 @@ func TestCollectorMatchesSubdomainsToRegisteredTunnel(t *testing.T) { t.Fatalf("active clients = %d, want 1", tunnel.ActiveClients) } } - -func TestCollectorUpdatesPeakWhenActiveClientChangesGeoKey(t *testing.T) { - now := time.Unix(1000, 0) - firstResolver := netip.MustParseAddr("192.0.2.53") - secondResolver := netip.MustParseAddr("198.51.100.53") - c := NewCollector( - []string{"tunnel.example.com"}, - WithNow(func() time.Time { return now }), - WithGeoResolver(fakeGeoResolver{ - labelNames: []string{"asn"}, - labels: map[netip.Addr]GeoLabels{ - firstResolver: {ASN: "64500"}, - secondResolver: {ASN: "64501"}, - }, - }), - ) - - c.RecordQueryFrom("tunnel.example.com", "client-a", firstResolver, 120) - c.RecordQueryFrom("tunnel.example.com", "client-a", secondResolver, 120) - - foundChangedASN := false - for _, series := range c.Snapshot().Tunnels["tunnel.example.com"].Series { - if series.ASN == "64501" && series.PeakClients != 1 { - t.Fatalf("peak clients for changed ASN = %d, want 1", series.PeakClients) - } - if series.ASN == "64501" { - foundChangedASN = true - } - } - if !foundChangedASN { - t.Fatal("series for changed ASN not found") - } -}