milestone 28: query provenance — every logged query is exactly explainable
Gates / frontend (push) Successful in 1m36s
Gates / test (push) Successful in 1m56s
Gates / test-aarch64 (push) Successful in 7m37s
Gates / package (push) Successful in 9m12s
Gates / container (push) Successful in 13s
CI / gates (push) Successful in 19m4s
Gates / frontend (push) Successful in 1m36s
Gates / test (push) Successful in 1m56s
Gates / test-aarch64 (push) Successful in 7m37s
Gates / package (push) Successful in 9m12s
Gates / container (push) Successful in 13s
CI / gates (push) Successful in 19m4s
query rows gain qclass, rcode, group, policy action and reason, the matched rule or list entry with its source, cname and safe-search targets, route kind, forward zone, and the resolver that actually answered — the pool and local markers die. servfails are logged and name the resolver that lost; post-parse protocol refusals become rows. a detail page at /queries/:id renders the ordered explanation, and coverage watermarks distinguish an empty history from a missing one. the schema fingerprint changes: existing query history is recreated with the old file kept aside and the reset filed as a resolved diagnostic. fixes an oversized udp reply being rebuilt as noerror, which handed clients a truncated nxdomain as success.
This commit is contained in:
@@ -29,6 +29,7 @@ import type {
|
||||
LookupResult,
|
||||
PauseState,
|
||||
QueriesPage,
|
||||
QueryDetail,
|
||||
Rule,
|
||||
RuleEcho,
|
||||
SettingsEnvelope,
|
||||
@@ -415,76 +416,139 @@ export const sample_get_upstream_health: UpstreamHealth = {
|
||||
};
|
||||
|
||||
export const sample_get_queries: QueriesPage = {
|
||||
coverage: {
|
||||
available_since: 0,
|
||||
complete: false,
|
||||
},
|
||||
next_before: 0,
|
||||
queries: [
|
||||
{
|
||||
block_reason: "",
|
||||
blocked: true,
|
||||
cache_hit: null,
|
||||
client_ip: "192.0.2.11",
|
||||
domain: "shop.example",
|
||||
id: 0,
|
||||
policy_action: "block",
|
||||
policy_reason: "blocklist_wildcard",
|
||||
qclass: 0,
|
||||
qtype: 0,
|
||||
rcode: 0,
|
||||
response_time_us: 0,
|
||||
route_kind: "blocked",
|
||||
ts: 0,
|
||||
upstream: "",
|
||||
},
|
||||
{
|
||||
blocked: false,
|
||||
cache_hit: false,
|
||||
client_ip: "192.0.2.10",
|
||||
domain: "news.example",
|
||||
id: 0,
|
||||
policy_action: "allow",
|
||||
policy_reason: "no_match",
|
||||
qclass: 0,
|
||||
qtype: 0,
|
||||
rcode: 0,
|
||||
response_time_us: 0,
|
||||
route_kind: "upstream",
|
||||
ts: 0,
|
||||
upstream: "https://dns.example/dns-query",
|
||||
},
|
||||
{
|
||||
blocked: false,
|
||||
cache_hit: true,
|
||||
client_ip: "192.0.2.10",
|
||||
domain: "d24.example",
|
||||
id: 0,
|
||||
policy_action: "allow",
|
||||
policy_reason: "no_match",
|
||||
qclass: 0,
|
||||
qtype: 0,
|
||||
rcode: 0,
|
||||
response_time_us: 0,
|
||||
route_kind: "cache",
|
||||
ts: 0,
|
||||
upstream: "https://dns.example/dns-query",
|
||||
upstream: "",
|
||||
},
|
||||
{
|
||||
block_reason: "",
|
||||
blocked: false,
|
||||
cache_hit: false,
|
||||
client_ip: "192.0.2.10",
|
||||
domain: "d23.example",
|
||||
id: 0,
|
||||
policy_action: "allow",
|
||||
policy_reason: "no_match",
|
||||
qclass: 0,
|
||||
qtype: 0,
|
||||
rcode: 0,
|
||||
response_time_us: 0,
|
||||
route_kind: "upstream",
|
||||
ts: 0,
|
||||
upstream: "https://dns.example/dns-query",
|
||||
},
|
||||
{
|
||||
block_reason: "",
|
||||
blocked: false,
|
||||
cache_hit: true,
|
||||
client_ip: "192.0.2.10",
|
||||
domain: "d22.example",
|
||||
id: 0,
|
||||
policy_action: "allow",
|
||||
policy_reason: "no_match",
|
||||
qclass: 0,
|
||||
qtype: 0,
|
||||
rcode: 0,
|
||||
response_time_us: 0,
|
||||
ts: 0,
|
||||
upstream: "https://dns.example/dns-query",
|
||||
},
|
||||
{
|
||||
block_reason: "",
|
||||
blocked: false,
|
||||
cache_hit: false,
|
||||
client_ip: "192.0.2.10",
|
||||
domain: "d21.example",
|
||||
id: 0,
|
||||
qtype: 0,
|
||||
response_time_us: 0,
|
||||
ts: 0,
|
||||
upstream: "https://dns.example/dns-query",
|
||||
},
|
||||
{
|
||||
block_reason: "blocklist_domain",
|
||||
blocked: true,
|
||||
cache_hit: null,
|
||||
client_ip: "192.0.2.10",
|
||||
domain: "d20.example",
|
||||
id: 0,
|
||||
qtype: 0,
|
||||
response_time_us: 0,
|
||||
route_kind: "cache",
|
||||
ts: 0,
|
||||
upstream: "",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const sample_get_query_detail: QueryDetail = {
|
||||
group: {
|
||||
id: 0,
|
||||
name: "kids",
|
||||
},
|
||||
id: 0,
|
||||
policy: {
|
||||
action: "block",
|
||||
matched: "||tracker.example^",
|
||||
reason: "blocklist_wildcard",
|
||||
source_id: 0,
|
||||
source_name: "StevenBlack",
|
||||
},
|
||||
request: {
|
||||
client: "192.0.2.11",
|
||||
domain: "shop.example",
|
||||
qclass: 0,
|
||||
qtype: 0,
|
||||
time: 0,
|
||||
},
|
||||
response: {
|
||||
duration_us: 0,
|
||||
rcode: 0,
|
||||
},
|
||||
rewrites: {
|
||||
cname_target: "cdn.tracker.example",
|
||||
safe_search_target: "",
|
||||
},
|
||||
route: {
|
||||
forward_zone: "",
|
||||
kind: "blocked",
|
||||
upstream: "",
|
||||
},
|
||||
};
|
||||
|
||||
export const sample_get_stats: StatsTotals = {
|
||||
avg_response_time_us: null,
|
||||
blocked: 0,
|
||||
cached: 0,
|
||||
clients: 0,
|
||||
coverage: {
|
||||
available_since: 0,
|
||||
complete: true,
|
||||
},
|
||||
period: "1h",
|
||||
queries: 0,
|
||||
since: 0,
|
||||
@@ -501,6 +565,10 @@ export const sample_get_stats_timeseries: StatsTimeseries = {
|
||||
ts: 0,
|
||||
},
|
||||
],
|
||||
coverage: {
|
||||
available_since: 0,
|
||||
complete: true,
|
||||
},
|
||||
period: "1h",
|
||||
since: 0,
|
||||
until: 0,
|
||||
|
||||
Reference in New Issue
Block a user