technitium 0.4.0

Typed async Rust client for the Technitium DNS Server API
Documentation
# Query Logs

## Endpoint

`/api/logs/query`

**Obsolete Path:** `/api/queryLogs`

## Method

GET

## Description

Queries DNS query logs from a specified installed DNS app. Supports pagination, ordering, date range filtering, and filtering by multiple DNS-specific fields (client IP, protocol, response type, response code, query name, query type, query class).

## Authentication

Required. A valid session `token` from `login` or `createToken`.

**Permission:** Logs: View

## Parameters

| Name | Type | Required | Conditional | Description |
|------|------|----------|-------------|-------------|
| `token` | string | Yes | No | Session token generated by `login` or `createToken`. |
| `node` | string | No | No | The node domain name to target. Only usable when Clustering is initialized. When unspecified, the current node is used. |
| `name` | string | Yes | No | The name of the installed DNS app to query logs from. |
| `classPath` | string | Yes | No | The class path of the DNS app. |
| `pageNumber` | integer | No | No | The page number of the data set to retrieve. Used for pagination. |
| `entriesPerPage` | integer | No | No | The number of log entries per page. Used for pagination. |
| `descendingOrder` | boolean | No | No | When `true`, orders the result set in descending order (newest first). |
| `start` | string | No | No | Start date/time filter in ISO 8601 format (e.g. `yyyy-MM-dd HH:mm:ss`). Only entries on or after this timestamp are included. |
| `end` | string | No | No | End date/time filter in ISO 8601 format (e.g. `yyyy-MM-dd HH:mm:ss`). Only entries on or before this timestamp are included. |
| `clientIpAddress` | string | No | No | Filter by client IP address. |
| `protocol` | string (enum) | No | No | Filter by DNS transport protocol. Valid values: `Udp`, `Tcp`, `Tls`, `Https`, `Quic`. |
| `responseType` | string (enum) | No | No | Filter by DNS server response type. Valid values: `Authoritative`, `Recursive`, `Cached`, `Blocked`, `UpstreamBlocked`, `CacheBlocked`. |
| `rcode` | string | No | No | Filter by DNS response code (e.g. `NoError`, `NxDomain`, `ServerFailure`). |
| `qname` | string | No | No | Filter by query name (QNAME) in the request question section. |
| `qtype` | string | No | No | Filter by DNS resource record type (QTYPE) in the request question section (e.g. `A`, `AAAA`, `CNAME`, `MX`). |
| `qclass` | string | No | No | Filter by DNS class (QCLASS) in the request question section (e.g. `IN`). |

## Response Fields

| Field | Type | Description |
|-------|------|-------------|
| `status` | string | `"ok"` on success. |
| `response.pageNumber` | integer | Current page number in the result set. |
| `response.totalPages` | integer | Total number of pages available. |
| `response.totalEntries` | integer | Total number of matching log entries across all pages. |
| `response.entries` | array | Array of log entry objects for the current page. |
| `response.entries[].rowNumber` | integer | Sequential row number of the entry. |
| `response.entries[].timestamp` | string | Timestamp of the log entry in ISO 8601 format (e.g. `"2021-09-10T12:22:52Z"`). |
| `response.entries[].clientIpAddress` | string | IP address of the client that made the DNS query. |
| `response.entries[].protocol` | string | DNS transport protocol used (e.g. `Udp`, `Tcp`, `Tls`, `Https`, `Quic`). |
| `response.entries[].responseType` | string | The server's response classification (e.g. `Authoritative`, `Recursive`, `Cached`, `Blocked`, `UpstreamBlocked`, `CacheBlocked`). |
| `response.entries[].responseRtt` | float | Round-trip time of the response in milliseconds. **Only present for certain response types** (e.g. `Recursive`). Absent for `Blocked`, `Authoritative` with failures, etc. |
| `response.entries[].rcode` | string | DNS response code (e.g. `NoError`, `NxDomain`, `ServerFailure`). |
| `response.entries[].qname` | string | Query name from the request question section. |
| `response.entries[].qtype` | string | DNS resource record type from the request question section (e.g. `A`, `AAAA`). |
| `response.entries[].qclass` | string | DNS class from the request question section (e.g. `IN`). |
| `response.entries[].answer` | string | The answer data. May be an IP address, empty string, or other record data depending on the response. |

## Conditional Logic Notes

- The `name` and `classPath` parameters are **both required** and must identify a valid installed DNS app that supports query logging. If the app is not installed or does not support logging, the behavior is undefined in the docs.
- The `responseRtt` field is **conditionally present** in response entries. It appears when the server performed an upstream query (e.g. `Recursive` responses) but is absent for locally resolved entries (e.g. `Blocked`, failed `Authoritative`).
- The `start` and `end` parameters form an inclusive date range filter. Either, both, or neither can be provided independently.
- All filter parameters are independently optional and can be combined. When multiple filters are specified, they are applied conjunctively (AND logic) -- an entry must match all specified filters to be included.
- The `protocol` parameter accepts exactly one of the five enum values; behavior with invalid values is not documented.
- The `responseType` parameter accepts exactly one of the six enum values; behavior with invalid values is not documented.
- The `node` parameter is only meaningful when Clustering is initialized.
- The URL in the docs contains a typo: `&=pageNumber=1` (extra `=` before `pageNumber`). The actual parameter name is `pageNumber`.

## Edge Cases

- The `responseRtt` field is optional/conditional. Deserializing code must handle its absence (e.g. use `Option<f64>` in Rust).
- The `answer` field can be an empty string (e.g. when a query was blocked or failed), not just absent. Client code should handle empty strings.
- The date/time format in the URL example uses `yyyy-MM-dd HH:mm:ss` (with a space), which requires URL encoding of the space character (`%20` or `+`) when sent as a query parameter.
- The URL example in the API docs has a typo: `&=pageNumber=1` -- the leading `=` before `pageNumber` is erroneous and should be ignored.
- Default values for `pageNumber`, `entriesPerPage`, and `descendingOrder` are not explicitly documented; the server presumably uses sensible defaults (page 1, some default page size, ascending order).
- The `rcode` parameter is a free-form string (not an enum in the docs), so any valid DNS RCODE name could be used. Standard values include `NoError`, `FormError`, `ServerFailure`, `NxDomain`, `NotImp`, `Refused`, etc.
- Query results depend entirely on the DNS app specified by `name` and `classPath`. Different apps may store different data or support different subsets of filter parameters.