Skip to content

Query Logs (PostgreSQL): strip null bytes from answer field before insert#2049

Open
daedaevibin wants to merge 4 commits into
TechnitiumSoftware:developfrom
Veridian-Zenith:fix/null-byte-sanitization
Open

Query Logs (PostgreSQL): strip null bytes from answer field before insert#2049
daedaevibin wants to merge 4 commits into
TechnitiumSoftware:developfrom
Veridian-Zenith:fix/null-byte-sanitization

Conversation

@daedaevibin

@daedaevibin daedaevibin commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Closes #2048

Problem

The Query Logs (PostgreSQL) app throws Npgsql.PostgresException (22021) when bulk-inserting DNS query logs containing null bytes (0x00) in the answer field. PostgreSQL rejects these as invalid UTF-8, causing the entire batch insert to fail and query logs to be lost.

Reproduction

  1. Create a TXT record with a null byte via the API:
curl -sk 'https://server:7742/api/zones/records/add' \
  -H 'Authorization: Bearer <token>' \
  -d 'domain=null.test.local&zone=test.local&type=TXT&characterStringsBase64=aGVsbG8Ad29ybGQ='
  1. Query it through the DNS server: dig @127.0.0.1 null.test.local TXT

  2. The query log app throws:

Npgsql.PostgresException (0x80004005): 22021: invalid byte sequence for encoding "UTF8": 0x00
  Where: unnamed portal parameter $11

Root Cause

DnsTXTRecordData.ToZoneFileEntry() calls Encoding.UTF8.GetString() on raw TXT record bytes. When the wire data contains 0x00, this produces a C# string with an embedded null character. Npgsql passes it to PostgreSQL which rejects it.

QNAME is safe — the DNS wire format prevents null bytes in domain names. Only the answer field (built from record.RDATA.ToString()) is affected.

Fix

Strip null bytes from the answer field in BulkInsertLogsAsync before passing it as a Npgsql parameter:

paramAnswer.Value = answer?.Replace("\0", "");

Verified

  • Full solution build succeeds (TechnitiumLibrary + DnsServer)
  • Reproduction confirmed on Technitium DNS Server v15.4 with PostgreSQL

Note: I tested this against a live v15.4 instance. The null byte only appeared in the answer field during reproduction; other fields were clean.

DNS query data can contain null bytes (0x00) from malformed or adversarial
packets. PostgreSQL rejects these in text/varchar columns, causing batch
insert failures with Npgsql.PostgresException (22021).

Sanitize by calling .Replace("\0", "") on qname and answer values in
BulkInsertLogsAsync before passing them as Npgsql parameters.
…query log apps

Same fix applied to the remaining database logger apps for consistency.
All four apps (PostgreSQL, MySQL, SQL Server, SQLite) now sanitize
null bytes from qname and answer fields before insertion.
@daedaevibin daedaevibin changed the title Query Logs (PostgreSQL): strip null bytes from string fields before insert Query Logs: strip null bytes from string fields before insert Jul 17, 2026
QNAME cannot contain null bytes per DNS wire format. Only the answer
field (from TXT record RDATA) is affected.
@daedaevibin daedaevibin changed the title Query Logs: strip null bytes from string fields before insert Query Logs (PostgreSQL): strip null bytes from answer field before insert Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant