NSD seems to force PTR RDATA to lower-case

Hello, NSD Developers.

I’m seeing, to my surprise, that NSD seems to be forcing PTR RDATA
to lower case when loading zone data from a file. Details follow
further on below.

Data specified in mixed case as “SSID-ORselves” appears in a DNS
response as “ssid-orselves”. Packet capture seems to confirm that what
I am seeing is not an artefact of the third-party test tool (dig) used.

This seems to be at odds with at least the spirit of both RFCs 1034 and
4343. It seems to me that transferring a zone from a master file to the
database should (even SHOULD) follow as thoroughly as possible the
same rules as apply to an over-the-wire transfer.

Perhaps I’m missing some configuration option, or just have a peculiar
reading of the scriptures, but I think this behaviour is erroneous.

Best regards,

Niall O’Reilly

$ uname -a
FreeBSD sand.no8.be 12.1-RELEASE-p6 FreeBSD 12.1-RELEASE-p6 GENERIC  amd64

$ nsd -v
NSD version 4.3.1
Written by NLnet Labs.

Copyright (C) 2001-2006 NLnet Labs.  This is free software.
There is NO warranty; not even for MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.

$ grep -i '\.f\.ip6.* ssid' /usr/local/etc/nsd/no8.be.internal-zone
*.0.2.e.d.3.f.6.2.7.8.0.0.b.1.d.f.ip6 IN PTR SSID-ORselves
*.0.1.e.d.3.f.6.2.7.8.0.0.b.1.d.f.ip6 IN PTR SSID-ORguests
$ echo ${SSH_CLIENT%% *}
fd1b:87:26f3:de20:c4c:c229:aaf9:f66a

$ dig @::1 +norec -x ${SSH_CLIENT%% *}

; <<>> DiG 9.16.4 <<>> @::1 +norec -x fd1b:87:26f3:de20:c4c:c229:aaf9:f66a
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53140
;; flags: qr aa; QUERY: 1, ANSWER: 3, AUTHORITY: 1, ADDITIONAL: 4

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;a.6.6.f.9.f.a.a.9.2.2.c.c.4.c.0.0.2.e.d.3.f.6.2.7.8.0.0.b.1.d.f.ip6.arpa. IN PTR

;; ANSWER SECTION:
3.f.6.2.7.8.0.0.b.1.d.f.ip6.arpa. 300 IN DNAME    3.f.6.2.7.8.0.0.b.1.d.f.ip6.no8.be.
a.6.6.f.9.f.a.a.9.2.2.c.c.4.c.0.0.2.e.d.3.f.6.2.7.8.0.0.b.1.d.f.ip6.arpa. 300 IN CNAME a.6.6.f.9.f.a.a.9.2.2.c.c.4.c.0.0.2.e.d.3.f.6.2.7.8.0.0.b.1.d.f.ip6.no8.be.
a.6.6.f.9.f.a.a.9.2.2.c.c.4.c.0.0.2.e.d.3.f.6.2.7.8.0.0.b.1.d.f.ip6.no8.be. 300    IN PTR ssid-orselves.no8.be.

;; AUTHORITY SECTION:
no8.be.            300    IN    NS    int-ns1.no8.be.

;; ADDITIONAL SECTION:
int-ns1.no8.be.        300    IN    AAAA    2001:bb6:572:b800::35:d
int-ns1.no8.be.        300    IN    AAAA    fd1b:87:26f3:de00::35:d
int-ns1.no8.be.        300    IN    A    10.0.16.13

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Sun Jul 05 08:01:20 UTC 2020
;; MSG SIZE  rcvd: 359

$

Hi Niall,

Yes, NSD lowercases the zone data. It always has done that. It does
this so that compares are not case insensitive any more in the code,
that is faster.

In any case you cannot (reliably) transfer it, because compression is
case insensitive. And so is lookup of data.

If the user uses 0x20 type, change of case of the query to add entropy
to the question, then this may remove or overwrite the case of the
answer. This could also happen if the user uses uppercase for the
query. For example in your example if you dig for ...NO8.BE. likely
this will then also appear in the answer PTR data.

Also zone transfers use (a lot of) name compression.

It is not impossible to preserve case, although that makes packets
bigger. I think BIND may do this for you or have an option. But other
tools may not.

Best regards, Wouter

Yes, NSD lowercases the zone data. It always has done that.

Thanks for the information.

It does
this so that compares are not case insensitive any more in the code,
that is faster.

So when is RDATA an object of comparison?

In any case you cannot (reliably) transfer it, because compression is
case insensitive.

This statement seems to be at odds with (Standards Track) RFC5936:
"Hence, name compression in an AXFR message SHOULD be performed in a
case-preserving manner"

And so is lookup of data.

I don't understand.
The argument to DNS lookup is a tuple (name, class, type).
RDATA is part of the result.

Best regards,
Niall

Hi Niall,

Yes, NSD lowercases the zone data. It always has done that.

Thanks for the information.

So, NSD is not case sensitive for domain names. It is not a DNS server
that keeps upper and lower case in the data. NSD supports 0x20 style
lookups where the upper/lowercase of the query qname is copied into the
answer.

It does
this so that compares are not case insensitive any more in the code,
that is faster.

So when is RDATA an object of comparison?

You seem to want NSD to be case sensitive. But it is not. And it
lowercases the input.

You are of course right that RDATA is not the object of comparison for
query lookups, but it is when comparing duplicates for RRs and when
performing name compression. Case sensitivity also plays a
(complicated) role in DNSSEC signatures (if you want more items for when
RDATA is an object of comparison).

You mean to argue that, case could be preserved because it is RDATA not
the domain name, but NSD uses the same routines and data structures to
handle it and does not have the upper/lowercase distinctions for this
RDATA piece. Other RDATA pieces could have case support in NSD, as it
may be stored as a binary data segment in NSD, and not used, eg. also
not a compression domain name, or not stored as a domain-name in NSD's
internal structures, and also no additional data lookups based on the
rdata name. But most names are compressable, not all recent ones and if
the binary format is awkward, NSD may have a binary segment for the
data, that could just as well be upper/lowercase preserving. Case for
that may be the RRSIG zone name. And we have had errors for that where
we had bugs because the zone name case changed in the upstream data
provision, and comparisons failed to check for equality. So, in
retrospect, we may have been better off lowercasing that too.

In any case you cannot (reliably) transfer it, because compression is
case insensitive.

This statement seems to be at odds with (Standards Track) RFC5936:
"Hence, name compression in an AXFR message SHOULD be performed in a
case-preserving manner"

Well, it both proves the 'not reliably' with the SHOULD, and says you
want case sensitive answers. I am not sure without checking the code if
NSD performs case preserving compression for zone transfer, but I think
since it lowercases the input zone, that may not matter.

And so is lookup of data.

I don't understand.
The argument to DNS lookup is a tuple (name, class, type).
RDATA is part of the result.

NSD stores the PTR rdata as pointers into the domain tree. The items in
the domain tree are by that tuple, and lowercased. And this is used for
name compression.

Best regards, Wouter