|
|
ee1d55 |
From 623bb196ca62f513345a93fffd77a60704261f38 Mon Sep 17 00:00:00 2001
|
|
|
ee1d55 |
From: Stepan Broz <sbroz@redhat.com>
|
|
|
ee1d55 |
Date: Mon, 6 May 2024 19:40:19 +0200
|
|
|
ee1d55 |
Subject: [PATCH] Use hashtable when parsing a message
|
|
|
ee1d55 |
|
|
|
ee1d55 |
When parsing messages use a hashtable instead of a linear search to reduce
|
|
|
ee1d55 |
the amount of work done in findname when there's more than one name in
|
|
|
ee1d55 |
the section.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
There are two hashtables:
|
|
|
ee1d55 |
|
|
|
ee1d55 |
1) hashtable for owner names - that's constructed for each section when we
|
|
|
ee1d55 |
hit the second name in the section and destroyed right after parsing
|
|
|
ee1d55 |
that section;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
2) per-name hashtable - for each name in the section, we construct a new
|
|
|
ee1d55 |
hashtable for that name if there are more than one rdataset for that
|
|
|
ee1d55 |
particular name.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit b8a96317544c7b310b4f74360825a87b6402ddc2)
|
|
|
ee1d55 |
(cherry picked from commit 0ceed03ebea395da1a39ad1cb39205ce75a3f768)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
Backport isc_ht API changes from BIND 9.18
|
|
|
ee1d55 |
|
|
|
ee1d55 |
To prevent allocating large hashtable in dns_message, we need to
|
|
|
ee1d55 |
backport the improvements to isc_ht API from BIND 9.18+ that includes
|
|
|
ee1d55 |
support for case insensitive keys and incremental rehashing of the
|
|
|
ee1d55 |
hashtables.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit a4baf324159ec3764195c949cb56c861d9f173ff)
|
|
|
ee1d55 |
(cherry picked from commit 2fc28056b33018f7f78b625409eb44c32d5c9b11)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
fix a message parsing regression
|
|
|
ee1d55 |
|
|
|
ee1d55 |
the fix for CVE-2023-4408 introduced a regression in the message
|
|
|
ee1d55 |
parser, which could cause a crash if duplicate rdatasets were found
|
|
|
ee1d55 |
in the question section. this commit ensures that rdatasets are
|
|
|
ee1d55 |
correctly disassociated and freed when this occurs.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit 4c19d35614f8cd80d8748156a5bad361e19abc28)
|
|
|
ee1d55 |
(cherry picked from commit 98ab8c81cc7739dc220aa3f50efa3061774de8ba)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
fix another message parsing regression
|
|
|
ee1d55 |
|
|
|
ee1d55 |
The fix for CVE-2023-4408 introduced a regression in the message
|
|
|
ee1d55 |
parser, which could cause a crash if an rdata type that can only
|
|
|
ee1d55 |
occur in the question was found in another section.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit 510f1de8a6add516b842a55750366944701d3d9a)
|
|
|
ee1d55 |
(cherry picked from commit bbbcaf8b2ec17d2cad28841ea86078168072ae2f)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
Apply various tweaks specific to BIND 9.11
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit c6026cbbaa9d297910af350fa6cc45788cc9f397)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
Fix case insensitive matching in isc_ht hash table implementation
|
|
|
ee1d55 |
|
|
|
ee1d55 |
The case insensitive matching in isc_ht was basically completely broken
|
|
|
ee1d55 |
as only the hashvalue computation was case insensitive, but the key
|
|
|
ee1d55 |
comparison was always case sensitive.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit c462d65b2fd0db362947db4a18a87df78f8d8e5d)
|
|
|
ee1d55 |
(cherry picked from commit 418b3793598a1e1c7e391bb317866d405cd03501)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
Add a system test for mixed-case data for the same owner
|
|
|
ee1d55 |
|
|
|
ee1d55 |
We were missing a test where a single owner name would have multiple
|
|
|
ee1d55 |
types with a different case. The generated RRSIGs and NSEC records will
|
|
|
ee1d55 |
then have different case than the signed records and message parser have
|
|
|
ee1d55 |
to cope with that and treat everything as the same owner.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit c8b623d87f0fb8f9cba8dea5c6a4b600953895e7)
|
|
|
ee1d55 |
(cherry picked from commit 1f9bbe1fe34b7a2c9765431e8a86b460afc9b323)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
6315. [security] Speed up parsing of DNS messages with many different
|
|
|
ee1d55 |
names. (CVE-2023-4408) [GL #4234]
|
|
|
ee1d55 |
|
|
|
ee1d55 |
Fix assertion failure in nslookup/dig/mdig when message has
|
|
|
ee1d55 |
multiple SIG(0) options.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
When parsing message with DNS_MESSAGE_BESTEFFORT (used exclusively in
|
|
|
ee1d55 |
tools, never in named itself) if we hit an invalid SIG(0) in wrong
|
|
|
ee1d55 |
place we continue parsing the message, and put the sig0 in msg->sig0.
|
|
|
ee1d55 |
If we then hit another sig0 in a proper place we see that msg->sig0
|
|
|
ee1d55 |
is already 'taken' and we don't free name and rdataset, and we don't
|
|
|
ee1d55 |
set seen_problem. This causes an assertion failure.
|
|
|
ee1d55 |
This fixes that issue by setting seen_problem if we hit second sig0,
|
|
|
ee1d55 |
tsig or opt, which causes name and rdataset to be always freed.
|
|
|
ee1d55 |
|
|
|
ee1d55 |
(cherry picked from commit 51a55ddbb73f8707de3d1b8cda15c8f61585bacb)
|
|
|
ee1d55 |
(cherry picked from commit 736d8c5b80d02f10555f324abef920a7257f9f43)
|
|
|
ee1d55 |
---
|
|
|
ee1d55 |
.../system/dnssec/ns3/secure.example.db.in | 5 +
|
|
|
ee1d55 |
bin/tests/system/dnssec/ns3/sign.sh | 112 ++--
|
|
|
ee1d55 |
bin/tests/system/dnssec/tests.sh | 15 +
|
|
|
ee1d55 |
lib/dns/catz.c | 50 +-
|
|
|
ee1d55 |
lib/dns/include/dns/message.h | 39 --
|
|
|
ee1d55 |
lib/dns/include/dns/name.h | 9 +-
|
|
|
ee1d55 |
lib/dns/message.c | 624 +++++++++++-------
|
|
|
ee1d55 |
lib/dns/name.c | 1 +
|
|
|
ee1d55 |
lib/isc/ht.c | 598 ++++++++++++-----
|
|
|
ee1d55 |
lib/isc/include/isc/ht.h | 45 +-
|
|
|
ee1d55 |
lib/isc/tests/ht_test.c | 75 ++-
|
|
|
ee1d55 |
11 files changed, 1032 insertions(+), 541 deletions(-)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
diff --git a/bin/tests/system/dnssec/ns3/secure.example.db.in b/bin/tests/system/dnssec/ns3/secure.example.db.in
|
|
|
ee1d55 |
index 9d310d8..3b713d8 100644
|
|
|
ee1d55 |
--- a/bin/tests/system/dnssec/ns3/secure.example.db.in
|
|
|
ee1d55 |
+++ b/bin/tests/system/dnssec/ns3/secure.example.db.in
|
|
|
ee1d55 |
@@ -44,3 +44,8 @@ rrsigonly A 10.0.0.29
|
|
|
ee1d55 |
cnameandkey CNAME @
|
|
|
ee1d55 |
cnamenokey CNAME @
|
|
|
ee1d55 |
dnameandkey DNAME @
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+mixedcase A 10.0.0.30
|
|
|
ee1d55 |
+mixedCASE TXT "mixed case"
|
|
|
ee1d55 |
+MIXEDcase AAAA 2002::
|
|
|
ee1d55 |
+mIxEdCaSe LOC 37 52 56.788 N 121 54 55.02 W 1120m 10m 100m 10m
|
|
|
ee1d55 |
diff --git a/bin/tests/system/dnssec/ns3/sign.sh b/bin/tests/system/dnssec/ns3/sign.sh
|
|
|
ee1d55 |
index 99e9b49..ce5b2ee 100644
|
|
|
ee1d55 |
--- a/bin/tests/system/dnssec/ns3/sign.sh
|
|
|
ee1d55 |
+++ b/bin/tests/system/dnssec/ns3/sign.sh
|
|
|
ee1d55 |
@@ -28,7 +28,9 @@ keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone`
|
|
|
ee1d55 |
|
|
|
ee1d55 |
cat $infile $cnameandkey.key $dnameandkey.key $keyname.key >$zonefile
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-$SIGNER -P -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -D -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
+cat "$zonefile" "$zonefile".signed >"$zonefile".tmp
|
|
|
ee1d55 |
+mv "$zonefile".tmp "$zonefile".signed
|
|
|
ee1d55 |
|
|
|
ee1d55 |
zone=bogus.example.
|
|
|
ee1d55 |
infile=bogus.example.db.in
|
|
|
ee1d55 |
@@ -313,11 +315,11 @@ zone=rsasha512.example.
|
|
|
ee1d55 |
infile=rsasha512.example.db.in
|
|
|
ee1d55 |
zonefile=rsasha512.example.db
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA512 -b 1024 -n zone $zone`
|
|
|
ee1d55 |
+keyname=$($KEYGEN -q -r $RANDFILE -a RSASHA512 -b 1024 -n zone $zone)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
cat $infile $keyname.key >$zonefile
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-$SIGNER -P -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# A zone with the DNSKEY set only signed by the KSK
|
|
|
ee1d55 |
@@ -326,10 +328,10 @@ zone=kskonly.example.
|
|
|
ee1d55 |
infile=kskonly.example.db.in
|
|
|
ee1d55 |
zonefile=kskonly.example.db
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -x -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -x -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# A zone with the expired signatures
|
|
|
ee1d55 |
@@ -338,10 +340,10 @@ zone=expired.example.
|
|
|
ee1d55 |
infile=expired.example.db.in
|
|
|
ee1d55 |
zonefile=expired.example.db
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -P -r $RANDFILE -o $zone -s -1d -e +1h $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -r $RANDFILE -o $zone -s -1d -e +1h $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
rm -f $kskname.* $zskname.*
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
@@ -351,10 +353,10 @@ zone=update-nsec3.example.
|
|
|
ee1d55 |
infile=update-nsec3.example.db.in
|
|
|
ee1d55 |
zonefile=update-nsec3.example.db
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -3 -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -3 -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -P -3 - -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -3 - -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# A NSEC signed zone that will have auto-dnssec enabled and
|
|
|
ee1d55 |
@@ -364,12 +366,12 @@ zone=auto-nsec.example.
|
|
|
ee1d55 |
infile=auto-nsec.example.db.in
|
|
|
ee1d55 |
zonefile=auto-nsec.example.db
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -P -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# A NSEC3 signed zone that will have auto-dnssec enabled and
|
|
|
ee1d55 |
@@ -379,12 +381,12 @@ zone=auto-nsec3.example.
|
|
|
ee1d55 |
infile=auto-nsec3.example.db.in
|
|
|
ee1d55 |
zonefile=auto-nsec3.example.db
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -3 -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -3 -r $RANDFILE $zone)
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -3 -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -3 -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -P -3 - -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -3 - -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# Secure below cname test zone.
|
|
|
ee1d55 |
@@ -447,10 +449,10 @@ zone="expiring.example."
|
|
|
ee1d55 |
infile="expiring.example.db.in"
|
|
|
ee1d55 |
zonefile="expiring.example.db"
|
|
|
ee1d55 |
signedfile="expiring.example.db.signed"
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
cp $infile $zonefile
|
|
|
ee1d55 |
-$SIGNER -S -r $RANDFILE -e now+1mi -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -S -r $RANDFILE -e now+1mi -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
mv -f ${zskname}.private ${zskname}.private.moved
|
|
|
ee1d55 |
mv -f ${kskname}.private ${kskname}.private.moved
|
|
|
ee1d55 |
|
|
|
ee1d55 |
@@ -462,12 +464,12 @@ infile="upper.example.db.in"
|
|
|
ee1d55 |
zonefile="upper.example.db"
|
|
|
ee1d55 |
lower="upper.example.db.lower"
|
|
|
ee1d55 |
signedfile="upper.example.db.signed"
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
cp $infile $zonefile
|
|
|
ee1d55 |
-$SIGNER -P -S -r $RANDFILE -o $zone -f $lower $zonefile > /dev/null 2>/dev/null
|
|
|
ee1d55 |
-$CHECKZONE -D upper.example $lower 2>/dev/null | \
|
|
|
ee1d55 |
- sed '/RRSIG/s/ upper.example. / UPPER.EXAMPLE. /' > $signedfile
|
|
|
ee1d55 |
+$SIGNER -P -S -r $RANDFILE -o $zone -f $lower $zonefile >/dev/null 2>/dev/null
|
|
|
ee1d55 |
+$CHECKZONE -D upper.example $lower 2>/dev/null |
|
|
|
ee1d55 |
+ sed '/RRSIG/s/ upper.example. / UPPER.EXAMPLE. /' >$signedfile
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# Check that the signer's name is in lower case when zone name is in
|
|
|
ee1d55 |
@@ -477,10 +479,10 @@ zone="LOWER.EXAMPLE."
|
|
|
ee1d55 |
infile="lower.example.db.in"
|
|
|
ee1d55 |
zonefile="lower.example.db"
|
|
|
ee1d55 |
signedfile="lower.example.db.signed"
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
cp $infile $zonefile
|
|
|
ee1d55 |
-$SIGNER -P -S -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -S -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# Zone with signatures about to expire, and dynamic, but configured
|
|
|
ee1d55 |
@@ -490,21 +492,21 @@ zone="nosign.example."
|
|
|
ee1d55 |
infile="nosign.example.db.in"
|
|
|
ee1d55 |
zonefile="nosign.example.db"
|
|
|
ee1d55 |
signedfile="nosign.example.db.signed"
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
cp $infile $zonefile
|
|
|
ee1d55 |
-$SIGNER -S -r $RANDFILE -e now+1mi -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -S -r $RANDFILE -e now+1mi -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
# preserve a normalized copy of the NS RRSIG for comparison later
|
|
|
ee1d55 |
-$CHECKZONE -D nosign.example nosign.example.db.signed 2>/dev/null | \
|
|
|
ee1d55 |
- awk '$4 == "RRSIG" && $5 == "NS" {$2 = ""; print}' | \
|
|
|
ee1d55 |
- sed 's/[ ][ ]*/ /g'> ../nosign.before
|
|
|
ee1d55 |
+$CHECKZONE -D nosign.example nosign.example.db.signed 2>/dev/null |
|
|
|
ee1d55 |
+ awk '$4 == "RRSIG" && $5 == "NS" {$2 = ""; print}' |
|
|
|
ee1d55 |
+ sed 's/[ ][ ]*/ /g' >../nosign.before
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# An inline signing zone
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
zone=inline.example.
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -3 -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -3 -r $RANDFILE $zone)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# publish a new key while deactivating another key at the same time.
|
|
|
ee1d55 |
@@ -512,13 +514,13 @@ zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
|
|
|
ee1d55 |
zone=publish-inactive.example
|
|
|
ee1d55 |
infile=publish-inactive.example.db.in
|
|
|
ee1d55 |
zonefile=publish-inactive.example.db
|
|
|
ee1d55 |
-now=`date -u +%Y%m%d%H%M%S`
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
-kskname=`$KEYGEN -P $now+90s -A $now+3600s -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
-kskname=`$KEYGEN -I $now+90s -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
+now=$(date -u +%Y%m%d%H%M%S)
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
+kskname=$($KEYGEN -P $now+90s -A $now+3600s -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
+kskname=$($KEYGEN -I $now+90s -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
cp $infile $zonefile
|
|
|
ee1d55 |
-$SIGNER -S -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -S -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# A zone which will change its sig-validity-interval
|
|
|
ee1d55 |
@@ -526,8 +528,8 @@ $SIGNER -S -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
zone=siginterval.example
|
|
|
ee1d55 |
infile=siginterval.example.db.in
|
|
|
ee1d55 |
zonefile=siginterval.example.db
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -3 -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -3 -r $RANDFILE -fk $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -3 -r $RANDFILE $zone)
|
|
|
ee1d55 |
cp $infile $zonefile
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
@@ -551,10 +553,10 @@ sed -e 's/bogus/badds/g' < dsset-bogus.example$TP > dsset-badds.example$TP
|
|
|
ee1d55 |
zone=future.example
|
|
|
ee1d55 |
infile=future.example.db.in
|
|
|
ee1d55 |
zonefile=future.example.db
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -P -s +3600 -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -s +3600 -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
cp -f $kskname.key trusted-future.key
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
@@ -563,10 +565,10 @@ cp -f $kskname.key trusted-future.key
|
|
|
ee1d55 |
zone=managed-future.example
|
|
|
ee1d55 |
infile=managed-future.example.db.in
|
|
|
ee1d55 |
zonefile=managed-future.example.db
|
|
|
ee1d55 |
-kskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone`
|
|
|
ee1d55 |
-zskname=`$KEYGEN -q -r $RANDFILE $zone`
|
|
|
ee1d55 |
+kskname=$($KEYGEN -q -r $RANDFILE -f KSK $zone)
|
|
|
ee1d55 |
+zskname=$($KEYGEN -q -r $RANDFILE $zone)
|
|
|
ee1d55 |
cat $infile $kskname.key $zskname.key >$zonefile
|
|
|
ee1d55 |
-$SIGNER -P -s +3600 -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1
|
|
|
ee1d55 |
+$SIGNER -P -s +3600 -r $RANDFILE -o $zone $zonefile >/dev/null 2>&1
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#
|
|
|
ee1d55 |
# A zone with a revoked key
|
|
|
ee1d55 |
diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh
|
|
|
ee1d55 |
index 91a4822..e8d8f7e 100644
|
|
|
ee1d55 |
--- a/bin/tests/system/dnssec/tests.sh
|
|
|
ee1d55 |
+++ b/bin/tests/system/dnssec/tests.sh
|
|
|
ee1d55 |
@@ -699,6 +699,21 @@ n=`expr $n + 1`
|
|
|
ee1d55 |
if [ $ret != 0 ]; then echo_i "failed"; fi
|
|
|
ee1d55 |
status=`expr $status + $ret`
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+echo_i "checking mixed-case positive validation ($n)"
|
|
|
ee1d55 |
+ret=0
|
|
|
ee1d55 |
+for type in a txt aaaa loc; do
|
|
|
ee1d55 |
+ $DIG $DIGOPTS +noauth mixedcase.secure.example. \
|
|
|
ee1d55 |
+ @10.53.0.3 $type >dig.out.$type.ns3.test$n || ret=1
|
|
|
ee1d55 |
+ $DIG $DIGOPTS +noauth mixedcase.secure.example. \
|
|
|
ee1d55 |
+ @10.53.0.4 $type >dig.out.$type.ns4.test$n || ret=1
|
|
|
ee1d55 |
+ digcomp --lc dig.out.$type.ns3.test$n dig.out.$type.ns4.test$n || ret=1
|
|
|
ee1d55 |
+ grep "status: NOERROR" dig.out.$type.ns4.test$n >/dev/null || ret=1
|
|
|
ee1d55 |
+ grep "flags:.*ad.*QUERY" dig.out.$type.ns4.test$n >/dev/null || ret=1
|
|
|
ee1d55 |
+done
|
|
|
ee1d55 |
+n=$((n + 1))
|
|
|
ee1d55 |
+test "$ret" -eq 0 || echo_i "failed"
|
|
|
ee1d55 |
+status=$((status + ret))
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
echo_i "checking multi-stage positive validation NSEC/NSEC3 ($n)"
|
|
|
ee1d55 |
ret=0
|
|
|
ee1d55 |
$DIG $DIGOPTS +noauth a.nsec3.example. \
|
|
|
ee1d55 |
diff --git a/lib/dns/catz.c b/lib/dns/catz.c
|
|
|
ee1d55 |
index 767c710..98ddd01 100644
|
|
|
ee1d55 |
--- a/lib/dns/catz.c
|
|
|
ee1d55 |
+++ b/lib/dns/catz.c
|
|
|
ee1d55 |
@@ -395,33 +395,21 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
|
|
ee1d55 |
|
|
|
ee1d55 |
dns_name_format(&target->name, czname, DNS_NAME_FORMATSIZE);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_init(&toadd, target->catzs->mctx, 16);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ isc_ht_init(&toadd, target->catzs->mctx, 16, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_init(&tomod, target->catzs->mctx, 16);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ isc_ht_init(&tomod, target->catzs->mctx, 16, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_iter_create(newzone->entries, &iter1);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ isc_ht_iter_create(newzone->entries, &iter1);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_iter_create(target->entries, &iter2);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ isc_ht_iter_create(target->entries, &iter2);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* We can create those iterators now, even though toadd and tomod are
|
|
|
ee1d55 |
* empty
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- result = isc_ht_iter_create(toadd, &iteradd);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ isc_ht_iter_create(toadd, &iteradd);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_iter_create(tomod, &itermod);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ isc_ht_iter_create(tomod, &itermod);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* First - walk the new zone and find all nodes that are not in the
|
|
|
ee1d55 |
@@ -565,7 +553,6 @@ dns_catz_zones_merge(dns_catz_zone_t *target, dns_catz_zone_t *newzone) {
|
|
|
ee1d55 |
|
|
|
ee1d55 |
result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-cleanup:
|
|
|
ee1d55 |
if (iter1 != NULL)
|
|
|
ee1d55 |
isc_ht_iter_destroy(&iter1);
|
|
|
ee1d55 |
if (iter2 != NULL)
|
|
|
ee1d55 |
@@ -605,9 +592,7 @@ dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm,
|
|
|
ee1d55 |
if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
goto cleanup_mutex;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_init(&new_zones->zones, mctx, 4);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup_refcount;
|
|
|
ee1d55 |
+ isc_ht_init(&new_zones->zones, mctx, 4, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_mem_attach(mctx, &new_zones->mctx);
|
|
|
ee1d55 |
new_zones->zmm = zmm;
|
|
|
ee1d55 |
@@ -624,7 +609,6 @@ dns_catz_new_zones(dns_catz_zones_t **catzsp, dns_catz_zonemodmethods_t *zmm,
|
|
|
ee1d55 |
|
|
|
ee1d55 |
cleanup_ht:
|
|
|
ee1d55 |
isc_ht_destroy(&new_zones->zones);
|
|
|
ee1d55 |
- cleanup_refcount:
|
|
|
ee1d55 |
isc_refcount_destroy(&new_zones->refs);
|
|
|
ee1d55 |
cleanup_mutex:
|
|
|
ee1d55 |
isc_mutex_destroy(&new_zones->lock);
|
|
|
ee1d55 |
@@ -667,9 +651,7 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
|
|
|
ee1d55 |
if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
goto cleanup_newzone;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_init(&new_zone->entries, catzs->mctx, 4);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup_name;
|
|
|
ee1d55 |
+ isc_ht_init(&new_zone->entries, catzs->mctx, 4, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
new_zone->updatetimer = NULL;
|
|
|
ee1d55 |
result = isc_timer_create(catzs->timermgr, isc_timertype_inactive,
|
|
|
ee1d55 |
@@ -698,7 +680,6 @@ dns_catz_new_zone(dns_catz_zones_t *catzs, dns_catz_zone_t **zonep,
|
|
|
ee1d55 |
|
|
|
ee1d55 |
cleanup_ht:
|
|
|
ee1d55 |
isc_ht_destroy(&new_zone->entries);
|
|
|
ee1d55 |
- cleanup_name:
|
|
|
ee1d55 |
dns_name_free(&new_zone->name, catzs->mctx);
|
|
|
ee1d55 |
cleanup_newzone:
|
|
|
ee1d55 |
isc_mem_put(catzs->mctx, new_zone, sizeof(*new_zone));
|
|
|
ee1d55 |
@@ -800,8 +781,7 @@ dns_catz_zone_detach(dns_catz_zone_t **zonep) {
|
|
|
ee1d55 |
if (refs == 0) {
|
|
|
ee1d55 |
isc_mem_t *mctx = zone->catzs->mctx;
|
|
|
ee1d55 |
if (zone->entries != NULL) {
|
|
|
ee1d55 |
- result = isc_ht_iter_create(zone->entries, &iter);
|
|
|
ee1d55 |
- INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_iter_create(zone->entries, &iter);
|
|
|
ee1d55 |
for (result = isc_ht_iter_first(iter);
|
|
|
ee1d55 |
result == ISC_R_SUCCESS;
|
|
|
ee1d55 |
result = isc_ht_iter_delcurrent_next(iter))
|
|
|
ee1d55 |
@@ -860,8 +840,7 @@ dns_catz_catzs_detach(dns_catz_zones_t **catzsp) {
|
|
|
ee1d55 |
catzs->magic = 0;
|
|
|
ee1d55 |
DESTROYLOCK(&catzs->lock);
|
|
|
ee1d55 |
if (catzs->zones != NULL) {
|
|
|
ee1d55 |
- result = isc_ht_iter_create(catzs->zones, &iter);
|
|
|
ee1d55 |
- INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_iter_create(catzs->zones, &iter);
|
|
|
ee1d55 |
for (result = isc_ht_iter_first(iter);
|
|
|
ee1d55 |
result == ISC_R_SUCCESS;)
|
|
|
ee1d55 |
{
|
|
|
ee1d55 |
@@ -1970,8 +1949,7 @@ dns_catz_prereconfig(dns_catz_zones_t *catzs) {
|
|
|
ee1d55 |
|
|
|
ee1d55 |
REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_iter_create(catzs->zones, &iter);
|
|
|
ee1d55 |
- INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_iter_create(catzs->zones, &iter);
|
|
|
ee1d55 |
for (result = isc_ht_iter_first(iter);
|
|
|
ee1d55 |
result == ISC_R_SUCCESS;
|
|
|
ee1d55 |
result = isc_ht_iter_next(iter))
|
|
|
ee1d55 |
@@ -1993,8 +1971,7 @@ dns_catz_postreconfig(dns_catz_zones_t *catzs) {
|
|
|
ee1d55 |
REQUIRE(DNS_CATZ_ZONES_VALID(catzs));
|
|
|
ee1d55 |
|
|
|
ee1d55 |
LOCK(&catzs->lock);
|
|
|
ee1d55 |
- result = isc_ht_iter_create(catzs->zones, &iter);
|
|
|
ee1d55 |
- INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_iter_create(catzs->zones, &iter);
|
|
|
ee1d55 |
for (result = isc_ht_iter_first(iter);
|
|
|
ee1d55 |
result == ISC_R_SUCCESS;)
|
|
|
ee1d55 |
{
|
|
|
ee1d55 |
@@ -2036,5 +2013,6 @@ dns_catz_postreconfig(dns_catz_zones_t *catzs) {
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp) {
|
|
|
ee1d55 |
REQUIRE(DNS_CATZ_ZONE_VALID(catz));
|
|
|
ee1d55 |
- return (isc_ht_iter_create(catz->entries, itp));
|
|
|
ee1d55 |
+ isc_ht_iter_create(catz->entries, itp);
|
|
|
ee1d55 |
+ return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h
|
|
|
ee1d55 |
index 868a87d..6682450 100644
|
|
|
ee1d55 |
--- a/lib/dns/include/dns/message.h
|
|
|
ee1d55 |
+++ b/lib/dns/include/dns/message.h
|
|
|
ee1d55 |
@@ -739,45 +739,6 @@ dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
|
|
|
ee1d55 |
*\li #ISC_R_NOTFOUND -- the desired type does not exist.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
-dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
|
|
|
ee1d55 |
- dns_rdatatype_t type, dns_rdatatype_t covers,
|
|
|
ee1d55 |
- dns_rdataset_t **rdataset);
|
|
|
ee1d55 |
-/*%<
|
|
|
ee1d55 |
- * Search the name for the specified rdclass and type. If it is found,
|
|
|
ee1d55 |
- * *rdataset is filled in with a pointer to that rdataset.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- * Requires:
|
|
|
ee1d55 |
- *\li if '**rdataset' is non-NULL, *rdataset needs to be NULL.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- *\li 'type' be a valid type, and NOT dns_rdatatype_any.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- *\li If 'type' is dns_rdatatype_rrsig, 'covers' must be a valid type.
|
|
|
ee1d55 |
- * Otherwise it should be 0.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- * Returns:
|
|
|
ee1d55 |
- *\li #ISC_R_SUCCESS -- all is well.
|
|
|
ee1d55 |
- *\li #ISC_R_NOTFOUND -- the desired type does not exist.
|
|
|
ee1d55 |
- */
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
-void
|
|
|
ee1d55 |
-dns_message_movename(dns_message_t *msg, dns_name_t *name,
|
|
|
ee1d55 |
- dns_section_t fromsection,
|
|
|
ee1d55 |
- dns_section_t tosection);
|
|
|
ee1d55 |
-/*%<
|
|
|
ee1d55 |
- * Move a name from one section to another.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- * Requires:
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- *\li 'msg' be valid.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- *\li 'name' must be a name already in 'fromsection'.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- *\li 'fromsection' must be a valid section.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- *\li 'tosection' must be a valid section.
|
|
|
ee1d55 |
- */
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
dns_message_addname(dns_message_t *msg, dns_name_t *name,
|
|
|
ee1d55 |
dns_section_t section);
|
|
|
ee1d55 |
diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h
|
|
|
ee1d55 |
index 93ddacd..9f60081 100644
|
|
|
ee1d55 |
--- a/lib/dns/include/dns/name.h
|
|
|
ee1d55 |
+++ b/lib/dns/include/dns/name.h
|
|
|
ee1d55 |
@@ -67,6 +67,7 @@
|
|
|
ee1d55 |
#include <stdio.h>
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#include <isc/boolean.h>
|
|
|
ee1d55 |
+#include <isc/ht.h>
|
|
|
ee1d55 |
#include <isc/lang.h>
|
|
|
ee1d55 |
#include <isc/magic.h>
|
|
|
ee1d55 |
#include <isc/region.h> /* Required for storage size of dns_label_t. */
|
|
|
ee1d55 |
@@ -110,6 +111,7 @@ struct dns_name {
|
|
|
ee1d55 |
isc_buffer_t * buffer;
|
|
|
ee1d55 |
ISC_LINK(dns_name_t) link;
|
|
|
ee1d55 |
ISC_LIST(dns_rdataset_t) list;
|
|
|
ee1d55 |
+ isc_ht_t *ht;
|
|
|
ee1d55 |
};
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#define DNS_NAME_MAGIC ISC_MAGIC('D','N','S','n')
|
|
|
ee1d55 |
@@ -170,7 +172,7 @@ LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_wildcardname;
|
|
|
ee1d55 |
A, (sizeof(A) - 1), sizeof(B), \
|
|
|
ee1d55 |
DNS_NAMEATTR_READONLY, \
|
|
|
ee1d55 |
B, NULL, { (void *)-1, (void *)-1}, \
|
|
|
ee1d55 |
- {NULL, NULL} \
|
|
|
ee1d55 |
+ {NULL, NULL}, NULL \
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#define DNS_NAME_INITABSOLUTE(A,B) { \
|
|
|
ee1d55 |
@@ -178,12 +180,12 @@ LIBDNS_EXTERNAL_DATA extern dns_name_t *dns_wildcardname;
|
|
|
ee1d55 |
A, sizeof(A), sizeof(B), \
|
|
|
ee1d55 |
DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE, \
|
|
|
ee1d55 |
B, NULL, { (void *)-1, (void *)-1}, \
|
|
|
ee1d55 |
- {NULL, NULL} \
|
|
|
ee1d55 |
+ {NULL, NULL}, NULL \
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#define DNS_NAME_INITEMPTY { \
|
|
|
ee1d55 |
DNS_NAME_MAGIC, NULL, 0, 0, 0, NULL, NULL, \
|
|
|
ee1d55 |
- { (void *)-1, (void *)-1 }, { NULL, NULL } \
|
|
|
ee1d55 |
+ { (void *)-1, (void *)-1 }, { NULL, NULL }, NULL \
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
@@ -1373,6 +1375,7 @@ do { \
|
|
|
ee1d55 |
_n->buffer = NULL; \
|
|
|
ee1d55 |
ISC_LINK_INIT(_n, link); \
|
|
|
ee1d55 |
ISC_LIST_INIT(_n->list); \
|
|
|
ee1d55 |
+ _n->ht = NULL; \
|
|
|
ee1d55 |
} while (0)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#define DNS_NAME_RESET(n) \
|
|
|
ee1d55 |
diff --git a/lib/dns/message.c b/lib/dns/message.c
|
|
|
ee1d55 |
index 9210c26..c97b7bd 100644
|
|
|
ee1d55 |
--- a/lib/dns/message.c
|
|
|
ee1d55 |
+++ b/lib/dns/message.c
|
|
|
ee1d55 |
@@ -19,6 +19,8 @@
|
|
|
ee1d55 |
#include <ctype.h>
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#include <isc/buffer.h>
|
|
|
ee1d55 |
+#include <isc/hash.h>
|
|
|
ee1d55 |
+#include <isc/ht.h>
|
|
|
ee1d55 |
#include <isc/mem.h>
|
|
|
ee1d55 |
#include <isc/print.h>
|
|
|
ee1d55 |
#include <isc/string.h> /* Required for HP/UX (and others?) */
|
|
|
ee1d55 |
@@ -159,6 +161,9 @@ msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
|
|
|
ee1d55 |
#define msgblock_get(block, type) \
|
|
|
ee1d55 |
((type *)msgblock_internalget(block, sizeof(type)))
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+dns__message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **rdatasetp);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
static inline void *
|
|
|
ee1d55 |
msgblock_internalget(dns_msgblock_t *, unsigned int);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
@@ -470,7 +475,7 @@ msgresetopt(dns_message_t *msg)
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
INSIST(dns_rdataset_isassociated(msg->opt));
|
|
|
ee1d55 |
dns_rdataset_disassociate(msg->opt);
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, msg->opt);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &msg->opt);
|
|
|
ee1d55 |
msg->opt = NULL;
|
|
|
ee1d55 |
msg->cc_ok = 0;
|
|
|
ee1d55 |
msg->cc_bad = 0;
|
|
|
ee1d55 |
@@ -491,10 +496,11 @@ msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
|
|
|
ee1d55 |
msg->querytsig = msg->tsig;
|
|
|
ee1d55 |
} else {
|
|
|
ee1d55 |
dns_rdataset_disassociate(msg->tsig);
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, msg->tsig);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &msg->tsig);
|
|
|
ee1d55 |
if (msg->querytsig != NULL) {
|
|
|
ee1d55 |
dns_rdataset_disassociate(msg->querytsig);
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, msg->querytsig);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg,
|
|
|
ee1d55 |
+ &msg->querytsig);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
if (dns_name_dynamic(msg->tsigname))
|
|
|
ee1d55 |
@@ -504,13 +510,10 @@ msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
|
|
|
ee1d55 |
msg->tsigname = NULL;
|
|
|
ee1d55 |
} else if (msg->querytsig != NULL && !replying) {
|
|
|
ee1d55 |
dns_rdataset_disassociate(msg->querytsig);
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, msg->querytsig);
|
|
|
ee1d55 |
- msg->querytsig = NULL;
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &msg->querytsig);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
if (msg->sig0 != NULL) {
|
|
|
ee1d55 |
- INSIST(dns_rdataset_isassociated(msg->sig0));
|
|
|
ee1d55 |
- dns_rdataset_disassociate(msg->sig0);
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, msg->sig0);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &msg->sig0);
|
|
|
ee1d55 |
if (msg->sig0name != NULL) {
|
|
|
ee1d55 |
if (dns_name_dynamic(msg->sig0name))
|
|
|
ee1d55 |
dns_name_free(msg->sig0name, msg->mctx);
|
|
|
ee1d55 |
@@ -812,6 +815,18 @@ dns_message_destroy(dns_message_t **msgp) {
|
|
|
ee1d55 |
isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+static isc_result_t
|
|
|
ee1d55 |
+name_hash_add(isc_ht_t *ht, dns_name_t *name, dns_name_t **foundp) {
|
|
|
ee1d55 |
+ isc_result_t result = isc_ht_find(ht, name->ndata, name->length,
|
|
|
ee1d55 |
+ (void **)foundp);
|
|
|
ee1d55 |
+ if (result == ISC_R_SUCCESS) {
|
|
|
ee1d55 |
+ return (ISC_R_EXISTS);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, name->ndata, name->length, (void *)name);
|
|
|
ee1d55 |
+ INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
static isc_result_t
|
|
|
ee1d55 |
findname(dns_name_t **foundname, dns_name_t *target,
|
|
|
ee1d55 |
dns_namelist_t *section)
|
|
|
ee1d55 |
@@ -831,28 +846,36 @@ findname(dns_name_t **foundname, dns_name_t *target,
|
|
|
ee1d55 |
return (ISC_R_NOTFOUND);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
-dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
|
|
|
ee1d55 |
- dns_rdatatype_t type, dns_rdatatype_t covers,
|
|
|
ee1d55 |
- dns_rdataset_t **rdataset)
|
|
|
ee1d55 |
-{
|
|
|
ee1d55 |
- dns_rdataset_t *curr;
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- REQUIRE(name != NULL);
|
|
|
ee1d55 |
- REQUIRE(rdataset == NULL || *rdataset == NULL);
|
|
|
ee1d55 |
+#ifdef _WIN32
|
|
|
ee1d55 |
+__pragma(pack(push, 1))
|
|
|
ee1d55 |
+typedef struct rds_key {
|
|
|
ee1d55 |
+ dns_rdataclass_t rdclass;
|
|
|
ee1d55 |
+ dns_rdatatype_t type;
|
|
|
ee1d55 |
+ dns_rdatatype_t covers;
|
|
|
ee1d55 |
+} rds_key_t;
|
|
|
ee1d55 |
+__pragma(pack(pop))
|
|
|
ee1d55 |
+#else
|
|
|
ee1d55 |
+typedef struct __attribute__((__packed__)) rds_key {
|
|
|
ee1d55 |
+ dns_rdataclass_t rdclass;
|
|
|
ee1d55 |
+ dns_rdatatype_t type;
|
|
|
ee1d55 |
+ dns_rdatatype_t covers;
|
|
|
ee1d55 |
+} rds_key_t;
|
|
|
ee1d55 |
+#endif
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- for (curr = ISC_LIST_TAIL(name->list);
|
|
|
ee1d55 |
- curr != NULL;
|
|
|
ee1d55 |
- curr = ISC_LIST_PREV(curr, link)) {
|
|
|
ee1d55 |
- if (curr->rdclass == rdclass &&
|
|
|
ee1d55 |
- curr->type == type && curr->covers == covers) {
|
|
|
ee1d55 |
- if (rdataset != NULL)
|
|
|
ee1d55 |
- *rdataset = curr;
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
+static isc_result_t
|
|
|
ee1d55 |
+rds_hash_add(isc_ht_t *ht, dns_rdataset_t *rds, dns_rdataset_t **foundp) {
|
|
|
ee1d55 |
+ rds_key_t key = { .rdclass = rds->rdclass,
|
|
|
ee1d55 |
+ .type = rds->type,
|
|
|
ee1d55 |
+ .covers = rds->covers };
|
|
|
ee1d55 |
+ isc_result_t result = isc_ht_find(ht, (const unsigned char *)&key,
|
|
|
ee1d55 |
+ sizeof(key), (void **)foundp);
|
|
|
ee1d55 |
+ if (result == ISC_R_SUCCESS) {
|
|
|
ee1d55 |
+ return (ISC_R_EXISTS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- return (ISC_R_NOTFOUND);
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, (const unsigned char *)&key, sizeof(key),
|
|
|
ee1d55 |
+ (void *)rds);
|
|
|
ee1d55 |
+ INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
@@ -980,6 +1003,18 @@ getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
} \
|
|
|
ee1d55 |
} while (0)
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+cleanup_name_hashmaps(dns_namelist_t *section) {
|
|
|
ee1d55 |
+ dns_name_t *name = NULL;
|
|
|
ee1d55 |
+ for (name = ISC_LIST_HEAD(*section); name != NULL;
|
|
|
ee1d55 |
+ name = ISC_LIST_NEXT(name, link))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ if (name->ht != NULL) {
|
|
|
ee1d55 |
+ isc_ht_destroy(&name->ht);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
static isc_result_t
|
|
|
ee1d55 |
getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
unsigned int options)
|
|
|
ee1d55 |
@@ -991,13 +1026,15 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
dns_offsets_t *offsets;
|
|
|
ee1d55 |
dns_rdataset_t *rdataset;
|
|
|
ee1d55 |
dns_rdatalist_t *rdatalist;
|
|
|
ee1d55 |
- isc_result_t result;
|
|
|
ee1d55 |
+ isc_result_t result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
dns_rdatatype_t rdtype;
|
|
|
ee1d55 |
dns_rdataclass_t rdclass;
|
|
|
ee1d55 |
dns_namelist_t *section;
|
|
|
ee1d55 |
- isc_boolean_t free_name;
|
|
|
ee1d55 |
+ isc_boolean_t free_name = ISC_FALSE;
|
|
|
ee1d55 |
isc_boolean_t best_effort;
|
|
|
ee1d55 |
isc_boolean_t seen_problem;
|
|
|
ee1d55 |
+ isc_ht_t *name_map = NULL;
|
|
|
ee1d55 |
+ isc_boolean_t free_ht = ISC_FALSE;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
section = &msg->sections[DNS_SECTION_QUESTION];
|
|
|
ee1d55 |
|
|
|
ee1d55 |
@@ -1005,9 +1042,14 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
seen_problem = ISC_FALSE;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
name = NULL;
|
|
|
ee1d55 |
+ name2 = NULL;
|
|
|
ee1d55 |
rdataset = NULL;
|
|
|
ee1d55 |
rdatalist = NULL;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ if (msg->counts[DNS_SECTION_QUESTION] > 1) {
|
|
|
ee1d55 |
+ isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
|
|
|
ee1d55 |
name = isc_mempool_get(msg->namepool);
|
|
|
ee1d55 |
if (name == NULL)
|
|
|
ee1d55 |
@@ -1030,13 +1072,20 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ /* If there is only one QNAME, skip the duplicity checks */
|
|
|
ee1d55 |
+ if (name_map == NULL) {
|
|
|
ee1d55 |
+ result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
+ goto skip_name_check;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Run through the section, looking to see if this name
|
|
|
ee1d55 |
* is already there. If it is found, put back the allocated
|
|
|
ee1d55 |
* name since we no longer need it, and set our name pointer
|
|
|
ee1d55 |
* to point to the name we found.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- result = findname(&name2, name, section);
|
|
|
ee1d55 |
+ result = name_hash_add(name_map, name, &name2);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* If it is the first name in the section, accept it.
|
|
|
ee1d55 |
@@ -1048,18 +1097,28 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
* this should be legal or not. In either case we no longer
|
|
|
ee1d55 |
* need this name pointer.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS) {
|
|
|
ee1d55 |
- if (!ISC_LIST_EMPTY(*section))
|
|
|
ee1d55 |
+ skip_name_check:
|
|
|
ee1d55 |
+ switch (result) {
|
|
|
ee1d55 |
+ case ISC_R_SUCCESS:
|
|
|
ee1d55 |
+ if (!ISC_LIST_EMPTY(*section)) {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
ISC_LIST_APPEND(*section, name, link);
|
|
|
ee1d55 |
- free_name = ISC_FALSE;
|
|
|
ee1d55 |
- } else {
|
|
|
ee1d55 |
- isc_mempool_put(msg->namepool, name);
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ case ISC_R_EXISTS:
|
|
|
ee1d55 |
+ dns_message_puttempname(msg, &name);
|
|
|
ee1d55 |
name = name2;
|
|
|
ee1d55 |
name2 = NULL;
|
|
|
ee1d55 |
- free_name = ISC_FALSE;
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ default:
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Unreachable
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ free_name = ISC_FALSE;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Get type and class.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
@@ -1087,13 +1146,6 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
if (rdtype == dns_rdatatype_tkey)
|
|
|
ee1d55 |
msg->tkey = 1;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- /*
|
|
|
ee1d55 |
- * Can't ask the same question twice.
|
|
|
ee1d55 |
- */
|
|
|
ee1d55 |
- result = dns_message_find(name, rdclass, rdtype, 0, NULL);
|
|
|
ee1d55 |
- if (result == ISC_R_SUCCESS)
|
|
|
ee1d55 |
- DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Allocate a new rdatalist.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
@@ -1102,7 +1154,7 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
result = ISC_R_NOMEMORY;
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
- rdataset = isc_mempool_get(msg->rdspool);
|
|
|
ee1d55 |
+ dns_message_gettemprdataset(msg, &rdataset);
|
|
|
ee1d55 |
if (rdataset == NULL) {
|
|
|
ee1d55 |
result = ISC_R_NOMEMORY;
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
@@ -1115,32 +1167,74 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
rdatalist->type = rdtype;
|
|
|
ee1d55 |
rdatalist->rdclass = rdclass;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- dns_rdataset_init(rdataset);
|
|
|
ee1d55 |
result = dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Skip the duplicity check for first rdataset
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ if (ISC_LIST_EMPTY(name->list)) {
|
|
|
ee1d55 |
+ goto skip_rds_check;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Can't ask the same question twice.
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ if (name->ht == NULL) {
|
|
|
ee1d55 |
+ isc_ht_init(&name->ht, msg->mctx, 1,
|
|
|
ee1d55 |
+ ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
+ free_ht = ISC_TRUE;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ dns_rdataset_t *old_rdataset = NULL;
|
|
|
ee1d55 |
+ for (old_rdataset = ISC_LIST_HEAD(name->list);
|
|
|
ee1d55 |
+ old_rdataset != NULL;
|
|
|
ee1d55 |
+ old_rdataset = ISC_LIST_NEXT(old_rdataset, link))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ result = rds_hash_add(name->ht, old_rdataset,
|
|
|
ee1d55 |
+ NULL);
|
|
|
ee1d55 |
+ INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ result = rds_hash_add(name->ht, rdataset, NULL);
|
|
|
ee1d55 |
+ if (result == ISC_R_EXISTS) {
|
|
|
ee1d55 |
+ DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ skip_rds_check:
|
|
|
ee1d55 |
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
rdataset = NULL;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if (seen_problem)
|
|
|
ee1d55 |
- return (DNS_R_RECOVERABLE);
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (seen_problem) {
|
|
|
ee1d55 |
+ result = DNS_R_RECOVERABLE;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
cleanup:
|
|
|
ee1d55 |
if (rdataset != NULL) {
|
|
|
ee1d55 |
- INSIST(!dns_rdataset_isassociated(rdataset));
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, rdataset);
|
|
|
ee1d55 |
+ if (dns_rdataset_isassociated(rdataset)) {
|
|
|
ee1d55 |
+ dns_rdataset_disassociate(rdataset);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ dns_message_puttemprdataset(msg, &rdataset);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
#if 0
|
|
|
ee1d55 |
if (rdatalist != NULL)
|
|
|
ee1d55 |
isc_mempool_put(msg->rdlpool, rdatalist);
|
|
|
ee1d55 |
#endif
|
|
|
ee1d55 |
- if (free_name)
|
|
|
ee1d55 |
- isc_mempool_put(msg->namepool, name);
|
|
|
ee1d55 |
+ if (free_name) {
|
|
|
ee1d55 |
+ dns_message_puttempname(msg, &name);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (free_ht) {
|
|
|
ee1d55 |
+ cleanup_name_hashmaps(section);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (name_map != NULL) {
|
|
|
ee1d55 |
+ isc_ht_destroy(&name_map);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
return (result);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
@@ -1220,24 +1314,26 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
unsigned int count, rdatalen;
|
|
|
ee1d55 |
dns_name_t *name = NULL;
|
|
|
ee1d55 |
dns_name_t *name2 = NULL;
|
|
|
ee1d55 |
- dns_offsets_t *offsets;
|
|
|
ee1d55 |
- dns_rdataset_t *rdataset;
|
|
|
ee1d55 |
- dns_rdatalist_t *rdatalist;
|
|
|
ee1d55 |
- isc_result_t result;
|
|
|
ee1d55 |
+ dns_offsets_t *offsets = NULL;
|
|
|
ee1d55 |
+ dns_rdataset_t *rdataset = NULL;
|
|
|
ee1d55 |
+ dns_rdataset_t *found_rdataset = NULL;
|
|
|
ee1d55 |
+ dns_rdatalist_t *rdatalist = NULL;
|
|
|
ee1d55 |
+ isc_result_t result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
dns_rdatatype_t rdtype, covers;
|
|
|
ee1d55 |
dns_rdataclass_t rdclass;
|
|
|
ee1d55 |
- dns_rdata_t *rdata;
|
|
|
ee1d55 |
+ dns_rdata_t *rdata = NULL;
|
|
|
ee1d55 |
dns_ttl_t ttl;
|
|
|
ee1d55 |
- dns_namelist_t *section;
|
|
|
ee1d55 |
- isc_boolean_t free_name = ISC_FALSE, free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
- isc_boolean_t preserve_order, best_effort, seen_problem;
|
|
|
ee1d55 |
- isc_boolean_t issigzero;
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
|
|
|
ee1d55 |
- best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
|
|
|
ee1d55 |
- seen_problem = ISC_FALSE;
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- section = &msg->sections[sectionid];
|
|
|
ee1d55 |
+ dns_namelist_t *section = &msg->sections[sectionid];
|
|
|
ee1d55 |
+ isc_boolean_t free_name = ISC_FALSE, seen_problem = ISC_FALSE;
|
|
|
ee1d55 |
+ isc_boolean_t free_ht = ISC_FALSE;
|
|
|
ee1d55 |
+ isc_boolean_t preserve_order = ((options & DNS_MESSAGEPARSE_PRESERVEORDER) != 0);
|
|
|
ee1d55 |
+ isc_boolean_t best_effort = ((options & DNS_MESSAGEPARSE_BESTEFFORT) != 0);
|
|
|
ee1d55 |
+ isc_boolean_t isedns, issigzero, istsig;
|
|
|
ee1d55 |
+ isc_ht_t *name_map = NULL;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (msg->counts[sectionid] > 1) {
|
|
|
ee1d55 |
+ isc_ht_init(&name_map, msg->mctx, 1, ISC_HT_CASE_INSENSITIVE);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
for (count = 0; count < msg->counts[sectionid]; count++) {
|
|
|
ee1d55 |
int recstart = source->current;
|
|
|
ee1d55 |
@@ -1245,11 +1341,15 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
|
|
|
ee1d55 |
skip_name_search = ISC_FALSE;
|
|
|
ee1d55 |
skip_type_search = ISC_FALSE;
|
|
|
ee1d55 |
- free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
+ isedns = ISC_FALSE;
|
|
|
ee1d55 |
+ issigzero = ISC_FALSE;
|
|
|
ee1d55 |
+ istsig = ISC_FALSE;
|
|
|
ee1d55 |
+ found_rdataset = NULL;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
name = isc_mempool_get(msg->namepool);
|
|
|
ee1d55 |
- if (name == NULL)
|
|
|
ee1d55 |
+ if (name == NULL) {
|
|
|
ee1d55 |
return (ISC_R_NOMEMORY);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
free_name = ISC_TRUE;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
offsets = newoffsets(msg);
|
|
|
ee1d55 |
@@ -1265,8 +1365,9 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
isc_buffer_remainingregion(source, &r);
|
|
|
ee1d55 |
isc_buffer_setactive(source, r.length);
|
|
|
ee1d55 |
result = getname(name, source, msg, dctx);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
+ if (result != ISC_R_SUCCESS) {
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Get type, class, ttl, and rdatalen. Verify that at least
|
|
|
ee1d55 |
@@ -1286,9 +1387,10 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
* established a class. Do so now.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
if (msg->rdclass_set == 0 &&
|
|
|
ee1d55 |
- rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
|
|
|
ee1d55 |
- rdtype != dns_rdatatype_tsig && /* class is ANY */
|
|
|
ee1d55 |
- rdtype != dns_rdatatype_tkey) { /* class is undefined */
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_tsig && /* class is ANY */
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_tkey) /* class is undefined */
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
msg->rdclass = rdclass;
|
|
|
ee1d55 |
msg->rdclass_set = 1;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
@@ -1297,15 +1399,17 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
* If this class is different than the one in the question
|
|
|
ee1d55 |
* section, bail.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- if (msg->opcode != dns_opcode_update
|
|
|
ee1d55 |
- && rdtype != dns_rdatatype_tsig
|
|
|
ee1d55 |
- && rdtype != dns_rdatatype_opt
|
|
|
ee1d55 |
- && rdtype != dns_rdatatype_key /* in a TKEY query */
|
|
|
ee1d55 |
- && rdtype != dns_rdatatype_sig /* SIG(0) */
|
|
|
ee1d55 |
- && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
|
|
|
ee1d55 |
- && msg->rdclass != dns_rdataclass_any
|
|
|
ee1d55 |
- && msg->rdclass != rdclass)
|
|
|
ee1d55 |
+ if (msg->opcode != dns_opcode_update &&
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_tsig &&
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_opt &&
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_key && /* in a TKEY query */
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_sig && /* SIG(0) */
|
|
|
ee1d55 |
+ rdtype != dns_rdatatype_tkey && /* Win2000 TKEY */
|
|
|
ee1d55 |
+ msg->rdclass != dns_rdataclass_any &&
|
|
|
ee1d55 |
+ msg->rdclass != rdclass)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* If this is not a TKEY query/response then the KEY
|
|
|
ee1d55 |
@@ -1315,7 +1419,9 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
rdtype == dns_rdatatype_key &&
|
|
|
ee1d55 |
msg->rdclass != dns_rdataclass_any &&
|
|
|
ee1d55 |
msg->rdclass != rdclass)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Special type handling for TSIG, OPT, and TKEY.
|
|
|
ee1d55 |
@@ -1328,10 +1434,13 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
if (sectionid != DNS_SECTION_ADDITIONAL ||
|
|
|
ee1d55 |
rdclass != dns_rdataclass_any ||
|
|
|
ee1d55 |
count != msg->counts[sectionid] - 1)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_BADTSIG);
|
|
|
ee1d55 |
- msg->sigstart = recstart;
|
|
|
ee1d55 |
- skip_name_search = ISC_TRUE;
|
|
|
ee1d55 |
- skip_type_search = ISC_TRUE;
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
+ skip_name_search = ISC_TRUE;
|
|
|
ee1d55 |
+ skip_type_search = ISC_TRUE;
|
|
|
ee1d55 |
+ istsig = ISC_TRUE;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
} else if (rdtype == dns_rdatatype_opt) {
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* The name of an OPT record must be ".", it
|
|
|
ee1d55 |
@@ -1341,9 +1450,13 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
if (!dns_name_equal(dns_rootname, name) ||
|
|
|
ee1d55 |
sectionid != DNS_SECTION_ADDITIONAL ||
|
|
|
ee1d55 |
msg->opt != NULL)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
- skip_name_search = ISC_TRUE;
|
|
|
ee1d55 |
- skip_type_search = ISC_TRUE;
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
+ skip_name_search = ISC_TRUE;
|
|
|
ee1d55 |
+ skip_type_search = ISC_TRUE;
|
|
|
ee1d55 |
+ isedns = ISC_TRUE;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
} else if (rdtype == dns_rdatatype_tkey) {
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* A TKEY must be in the additional section if this
|
|
|
ee1d55 |
@@ -1354,13 +1467,16 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
dns_section_t tkeysection;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
|
|
|
ee1d55 |
+ if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0) {
|
|
|
ee1d55 |
tkeysection = DNS_SECTION_ADDITIONAL;
|
|
|
ee1d55 |
- else
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
tkeysection = DNS_SECTION_ANSWER;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
if (sectionid != tkeysection &&
|
|
|
ee1d55 |
sectionid != DNS_SECTION_ANSWER)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
@@ -1386,7 +1502,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
if (msg->opcode == dns_opcode_update &&
|
|
|
ee1d55 |
- update(sectionid, rdclass)) {
|
|
|
ee1d55 |
+ update(sectionid, rdclass))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
if (rdatalen != 0) {
|
|
|
ee1d55 |
result = DNS_R_FORMERR;
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
@@ -1406,46 +1523,54 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
} else if (rdclass == dns_rdataclass_none &&
|
|
|
ee1d55 |
msg->opcode == dns_opcode_update &&
|
|
|
ee1d55 |
- sectionid == DNS_SECTION_UPDATE) {
|
|
|
ee1d55 |
+ sectionid == DNS_SECTION_UPDATE)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
result = getrdata(source, msg, dctx, msg->rdclass,
|
|
|
ee1d55 |
rdtype, rdatalen, rdata);
|
|
|
ee1d55 |
- } else
|
|
|
ee1d55 |
- result = getrdata(source, msg, dctx, rdclass,
|
|
|
ee1d55 |
- rdtype, rdatalen, rdata);
|
|
|
ee1d55 |
- if (result != ISC_R_SUCCESS)
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
+ result = getrdata(source, msg, dctx, rdclass, rdtype,
|
|
|
ee1d55 |
+ rdatalen, rdata);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ if (result != ISC_R_SUCCESS) {
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
rdata->rdclass = rdclass;
|
|
|
ee1d55 |
- issigzero = ISC_FALSE;
|
|
|
ee1d55 |
- if (rdtype == dns_rdatatype_rrsig &&
|
|
|
ee1d55 |
- rdata->flags == 0) {
|
|
|
ee1d55 |
+ if (rdtype == dns_rdatatype_rrsig && rdata->flags == 0) {
|
|
|
ee1d55 |
covers = dns_rdata_covers(rdata);
|
|
|
ee1d55 |
- if (covers == 0)
|
|
|
ee1d55 |
+ if (covers == 0) {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
|
|
|
ee1d55 |
- rdata->flags == 0) {
|
|
|
ee1d55 |
+ rdata->flags == 0)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
covers = dns_rdata_covers(rdata);
|
|
|
ee1d55 |
if (covers == 0) {
|
|
|
ee1d55 |
if (sectionid != DNS_SECTION_ADDITIONAL ||
|
|
|
ee1d55 |
count != msg->counts[sectionid] - 1)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_BADSIG0);
|
|
|
ee1d55 |
- msg->sigstart = recstart;
|
|
|
ee1d55 |
- skip_name_search = ISC_TRUE;
|
|
|
ee1d55 |
- skip_type_search = ISC_TRUE;
|
|
|
ee1d55 |
- issigzero = ISC_TRUE;
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
+ skip_name_search = ISC_TRUE;
|
|
|
ee1d55 |
+ skip_type_search = ISC_TRUE;
|
|
|
ee1d55 |
+ issigzero = ISC_TRUE;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
} else {
|
|
|
ee1d55 |
if (msg->rdclass != dns_rdataclass_any &&
|
|
|
ee1d55 |
msg->rdclass != rdclass)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
- } else
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
covers = 0;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Check the ownername of NSEC3 records
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
if (rdtype == dns_rdatatype_nsec3 &&
|
|
|
ee1d55 |
- !dns_rdata_checkowner(name, msg->rdclass, rdtype,
|
|
|
ee1d55 |
- ISC_FALSE)) {
|
|
|
ee1d55 |
+ !dns_rdata_checkowner(name, msg->rdclass, rdtype, ISC_FALSE))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
result = DNS_R_BADOWNERNAME;
|
|
|
ee1d55 |
goto cleanup;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
@@ -1456,109 +1581,156 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
* to the end of the message.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
if (preserve_order || msg->opcode == dns_opcode_update ||
|
|
|
ee1d55 |
- skip_name_search) {
|
|
|
ee1d55 |
- if (rdtype != dns_rdatatype_opt &&
|
|
|
ee1d55 |
- rdtype != dns_rdatatype_tsig &&
|
|
|
ee1d55 |
- !issigzero)
|
|
|
ee1d55 |
- {
|
|
|
ee1d55 |
+ skip_name_search)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ if (!isedns && !istsig && !issigzero) {
|
|
|
ee1d55 |
ISC_LIST_APPEND(*section, name, link);
|
|
|
ee1d55 |
free_name = ISC_FALSE;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
} else {
|
|
|
ee1d55 |
+ if (name_map == NULL) {
|
|
|
ee1d55 |
+ result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
+ goto skip_name_check;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Run through the section, looking to see if this name
|
|
|
ee1d55 |
* is already there. If it is found, put back the
|
|
|
ee1d55 |
* allocated name since we no longer need it, and set
|
|
|
ee1d55 |
* our name pointer to point to the name we found.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- result = findname(&name2, name, section);
|
|
|
ee1d55 |
+ result = name_hash_add(name_map, name, &name2);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* If it is a new name, append to the section.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- if (result == ISC_R_SUCCESS) {
|
|
|
ee1d55 |
- isc_mempool_put(msg->namepool, name);
|
|
|
ee1d55 |
- name = name2;
|
|
|
ee1d55 |
- } else {
|
|
|
ee1d55 |
+ skip_name_check:
|
|
|
ee1d55 |
+ switch (result) {
|
|
|
ee1d55 |
+ case ISC_R_SUCCESS:
|
|
|
ee1d55 |
ISC_LIST_APPEND(*section, name, link);
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ case ISC_R_EXISTS:
|
|
|
ee1d55 |
+ dns_message_puttempname(msg, &name);
|
|
|
ee1d55 |
+ name = name2;
|
|
|
ee1d55 |
+ name2 = NULL;
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ default:
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Unreachable
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
free_name = ISC_FALSE;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ dns_message_gettemprdataset(msg, &rdataset);
|
|
|
ee1d55 |
+ if (rdataset == NULL) {
|
|
|
ee1d55 |
+ result = ISC_R_NOMEMORY;
|
|
|
ee1d55 |
+ goto cleanup;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ rdatalist = newrdatalist(msg);
|
|
|
ee1d55 |
+ if (rdatalist == NULL) {
|
|
|
ee1d55 |
+ result = ISC_R_NOMEMORY;
|
|
|
ee1d55 |
+ goto cleanup;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ rdatalist->type = rdtype;
|
|
|
ee1d55 |
+ rdatalist->covers = covers;
|
|
|
ee1d55 |
+ rdatalist->rdclass = rdclass;
|
|
|
ee1d55 |
+ rdatalist->ttl = ttl;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
|
|
|
ee1d55 |
+ ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ dns_rdataset_setownercase(rdataset, name);
|
|
|
ee1d55 |
+ rdatalist = NULL;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Search name for the particular type and class.
|
|
|
ee1d55 |
* Skip this stage if in update mode or this is a meta-type.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- if (preserve_order || msg->opcode == dns_opcode_update ||
|
|
|
ee1d55 |
- skip_type_search)
|
|
|
ee1d55 |
- result = ISC_R_NOTFOUND;
|
|
|
ee1d55 |
- else {
|
|
|
ee1d55 |
+ if (isedns || istsig || issigzero) {
|
|
|
ee1d55 |
+ /* Skip adding the rdataset to the tables */
|
|
|
ee1d55 |
+ } else if (preserve_order || msg->opcode == dns_opcode_update ||
|
|
|
ee1d55 |
+ skip_type_search)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* If this is a type that can only occur in
|
|
|
ee1d55 |
* the question section, fail.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- if (dns_rdatatype_questiononly(rdtype))
|
|
|
ee1d55 |
+ if (dns_rdatatype_questiononly(rdtype)) {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ if (ISC_LIST_EMPTY(name->list)) {
|
|
|
ee1d55 |
+ result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
+ goto skip_rds_check;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ if (name->ht == NULL) {
|
|
|
ee1d55 |
+ isc_ht_init(&name->ht, msg->mctx, 1,
|
|
|
ee1d55 |
+ ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
+ free_ht = ISC_TRUE;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- rdataset = NULL;
|
|
|
ee1d55 |
- result = dns_message_find(name, rdclass, rdtype,
|
|
|
ee1d55 |
- covers, &rdataset);
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
+ INSIST(ISC_LIST_HEAD(name->list) ==
|
|
|
ee1d55 |
+ ISC_LIST_TAIL(name->list));
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- /*
|
|
|
ee1d55 |
- * If we found an rdataset that matches, we need to
|
|
|
ee1d55 |
- * append this rdata to that set. If we did not, we need
|
|
|
ee1d55 |
- * to create a new rdatalist, store the important bits there,
|
|
|
ee1d55 |
- * convert it to an rdataset, and link the latter to the name.
|
|
|
ee1d55 |
- * Yuck. When appending, make certain that the type isn't
|
|
|
ee1d55 |
- * a singleton type, such as SOA or CNAME.
|
|
|
ee1d55 |
- *
|
|
|
ee1d55 |
- * Note that this check will be bypassed when preserving order,
|
|
|
ee1d55 |
- * the opcode is an update, or the type search is skipped.
|
|
|
ee1d55 |
- */
|
|
|
ee1d55 |
- if (result == ISC_R_SUCCESS) {
|
|
|
ee1d55 |
- if (dns_rdatatype_issingleton(rdtype)) {
|
|
|
ee1d55 |
- dns_rdata_t *first;
|
|
|
ee1d55 |
- dns_rdatalist_fromrdataset(rdataset,
|
|
|
ee1d55 |
- &rdatalist);
|
|
|
ee1d55 |
- first = ISC_LIST_HEAD(rdatalist->rdata);
|
|
|
ee1d55 |
- INSIST(first != NULL);
|
|
|
ee1d55 |
- if (dns_rdata_compare(rdata, first) != 0)
|
|
|
ee1d55 |
- DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
+ dns_rdataset_t *old_rdataset =
|
|
|
ee1d55 |
+ ISC_LIST_HEAD(name->list);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if (result == ISC_R_NOTFOUND) {
|
|
|
ee1d55 |
- rdataset = isc_mempool_get(msg->rdspool);
|
|
|
ee1d55 |
- if (rdataset == NULL) {
|
|
|
ee1d55 |
- result = ISC_R_NOMEMORY;
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
- free_rdataset = ISC_TRUE;
|
|
|
ee1d55 |
+ result = rds_hash_add(name->ht, old_rdataset,
|
|
|
ee1d55 |
+ NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- rdatalist = newrdatalist(msg);
|
|
|
ee1d55 |
- if (rdatalist == NULL) {
|
|
|
ee1d55 |
- result = ISC_R_NOMEMORY;
|
|
|
ee1d55 |
- goto cleanup;
|
|
|
ee1d55 |
+ INSIST(result == ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
+ result = rds_hash_add(name->ht, rdataset,
|
|
|
ee1d55 |
+ &found_rdataset);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- rdatalist->type = rdtype;
|
|
|
ee1d55 |
- rdatalist->covers = covers;
|
|
|
ee1d55 |
- rdatalist->rdclass = rdclass;
|
|
|
ee1d55 |
- rdatalist->ttl = ttl;
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- dns_rdataset_init(rdataset);
|
|
|
ee1d55 |
- RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
|
|
|
ee1d55 |
- rdataset)
|
|
|
ee1d55 |
- == ISC_R_SUCCESS);
|
|
|
ee1d55 |
- dns_rdataset_setownercase(rdataset, name);
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * If we found an rdataset that matches, we need to
|
|
|
ee1d55 |
+ * append this rdata to that set. If we did not, we
|
|
|
ee1d55 |
+ * need to create a new rdatalist, store the important
|
|
|
ee1d55 |
+ * bits there, convert it to an rdataset, and link the
|
|
|
ee1d55 |
+ * latter to the name. Yuck. When appending, make
|
|
|
ee1d55 |
+ * certain that the type isn't a singleton type, such as
|
|
|
ee1d55 |
+ * SOA or CNAME.
|
|
|
ee1d55 |
+ *
|
|
|
ee1d55 |
+ * Note that this check will be bypassed when preserving
|
|
|
ee1d55 |
+ * order, the opcode is an update, or the type search is
|
|
|
ee1d55 |
+ * skipped.
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ skip_rds_check:
|
|
|
ee1d55 |
+ switch (result) {
|
|
|
ee1d55 |
+ case ISC_R_EXISTS:
|
|
|
ee1d55 |
+ /* Free the rdataset we used as the key */
|
|
|
ee1d55 |
+ dns_rdataset_disassociate(rdataset);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &rdataset);
|
|
|
ee1d55 |
+ result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
+ rdataset = found_rdataset;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (!dns_rdatatype_issingleton(rdtype)) {
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if (rdtype != dns_rdatatype_opt &&
|
|
|
ee1d55 |
- rdtype != dns_rdatatype_tsig &&
|
|
|
ee1d55 |
- !issigzero)
|
|
|
ee1d55 |
- {
|
|
|
ee1d55 |
+ dns_rdatalist_fromrdataset(rdataset,
|
|
|
ee1d55 |
+ &rdatalist);
|
|
|
ee1d55 |
+ dns_rdata_t *first =
|
|
|
ee1d55 |
+ ISC_LIST_HEAD(rdatalist->rdata);
|
|
|
ee1d55 |
+ INSIST(first != NULL);
|
|
|
ee1d55 |
+ if (dns_rdata_compare(rdata, first) != 0) {
|
|
|
ee1d55 |
+ DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ case ISC_R_SUCCESS:
|
|
|
ee1d55 |
ISC_LIST_APPEND(name->list, rdataset, link);
|
|
|
ee1d55 |
- free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
+ default:
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Unreachable
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ break;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
@@ -1572,8 +1744,9 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
if (ttl != rdataset->ttl) {
|
|
|
ee1d55 |
rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
|
|
|
ee1d55 |
- if (ttl < rdataset->ttl)
|
|
|
ee1d55 |
+ if (ttl < rdataset->ttl) {
|
|
|
ee1d55 |
rdataset->ttl = ttl;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/* Append this rdata to the rdataset. */
|
|
|
ee1d55 |
@@ -1588,43 +1761,40 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
* already set if best-effort parsing is enabled otherwise
|
|
|
ee1d55 |
* there will only be at most one of each.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
- if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
|
|
|
ee1d55 |
+ if (isedns) {
|
|
|
ee1d55 |
dns_rcode_t ercode;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
msg->opt = rdataset;
|
|
|
ee1d55 |
- rdataset = NULL;
|
|
|
ee1d55 |
- free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
ercode = (dns_rcode_t)
|
|
|
ee1d55 |
((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
|
|
|
ee1d55 |
>> 20);
|
|
|
ee1d55 |
msg->rcode |= ercode;
|
|
|
ee1d55 |
- isc_mempool_put(msg->namepool, name);
|
|
|
ee1d55 |
+ dns_message_puttempname(msg, &name);
|
|
|
ee1d55 |
free_name = ISC_FALSE;
|
|
|
ee1d55 |
- } else if (issigzero && msg->sig0 == NULL) {
|
|
|
ee1d55 |
+ } else if (issigzero) {
|
|
|
ee1d55 |
msg->sig0 = rdataset;
|
|
|
ee1d55 |
msg->sig0name = name;
|
|
|
ee1d55 |
- rdataset = NULL;
|
|
|
ee1d55 |
- free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
+ msg->sigstart = recstart;
|
|
|
ee1d55 |
free_name = ISC_FALSE;
|
|
|
ee1d55 |
- } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
|
|
|
ee1d55 |
+ } else if (istsig) {
|
|
|
ee1d55 |
msg->tsig = rdataset;
|
|
|
ee1d55 |
msg->tsigname = name;
|
|
|
ee1d55 |
- /* Windows doesn't like TSIG names to be compressed. */
|
|
|
ee1d55 |
+ msg->sigstart = recstart;
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Windows doesn't like TSIG names to be compressed.
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
|
|
|
ee1d55 |
- rdataset = NULL;
|
|
|
ee1d55 |
- free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
free_name = ISC_FALSE;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
+ rdataset = NULL;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
if (seen_problem) {
|
|
|
ee1d55 |
- if (free_name)
|
|
|
ee1d55 |
- isc_mempool_put(msg->namepool, name);
|
|
|
ee1d55 |
- if (free_rdataset)
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, rdataset);
|
|
|
ee1d55 |
- free_name = free_rdataset = ISC_FALSE;
|
|
|
ee1d55 |
+ if (free_name) {
|
|
|
ee1d55 |
+ dns_message_puttempname(msg, &name);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ free_name = ISC_FALSE;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
INSIST(free_name == ISC_FALSE);
|
|
|
ee1d55 |
- INSIST(free_rdataset == ISC_FALSE);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
@@ -1635,20 +1805,32 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
|
|
|
ee1d55 |
if (sectionid == DNS_SECTION_AUTHORITY &&
|
|
|
ee1d55 |
msg->opcode == dns_opcode_query &&
|
|
|
ee1d55 |
((msg->flags & DNS_MESSAGEFLAG_QR) != 0) &&
|
|
|
ee1d55 |
- ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) &&
|
|
|
ee1d55 |
- !preserve_order &&
|
|
|
ee1d55 |
+ ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) && !preserve_order &&
|
|
|
ee1d55 |
!auth_signed(section))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
DO_ERROR(DNS_R_FORMERR);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if (seen_problem)
|
|
|
ee1d55 |
- return (DNS_R_RECOVERABLE);
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ if (seen_problem) {
|
|
|
ee1d55 |
+ result = DNS_R_RECOVERABLE;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- cleanup:
|
|
|
ee1d55 |
- if (free_name)
|
|
|
ee1d55 |
- isc_mempool_put(msg->namepool, name);
|
|
|
ee1d55 |
- if (free_rdataset)
|
|
|
ee1d55 |
+cleanup:
|
|
|
ee1d55 |
+ if (rdataset != NULL && rdataset != found_rdataset) {
|
|
|
ee1d55 |
+ dns_rdataset_disassociate(rdataset);
|
|
|
ee1d55 |
isc_mempool_put(msg->rdspool, rdataset);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ if (free_name) {
|
|
|
ee1d55 |
+ dns_message_puttempname(msg, &name);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (free_ht) {
|
|
|
ee1d55 |
+ cleanup_name_hashmaps(section);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (name_map != NULL) {
|
|
|
ee1d55 |
+ isc_ht_destroy(&name_map);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
return (result);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
@@ -2380,11 +2562,11 @@ dns_message_renderreset(dns_message_t *msg) {
|
|
|
ee1d55 |
dns_message_puttempname(msg, &msg->tsigname);
|
|
|
ee1d55 |
if (msg->tsig != NULL) {
|
|
|
ee1d55 |
dns_rdataset_disassociate(msg->tsig);
|
|
|
ee1d55 |
- dns_message_puttemprdataset(msg, &msg->tsig);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &msg->tsig);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
if (msg->sig0 != NULL) {
|
|
|
ee1d55 |
dns_rdataset_disassociate(msg->sig0);
|
|
|
ee1d55 |
- dns_message_puttemprdataset(msg, &msg->sig0);
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &msg->sig0);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
@@ -2477,24 +2659,6 @@ dns_message_findname(dns_message_t *msg, dns_section_t section,
|
|
|
ee1d55 |
return (result);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-void
|
|
|
ee1d55 |
-dns_message_movename(dns_message_t *msg, dns_name_t *name,
|
|
|
ee1d55 |
- dns_section_t fromsection,
|
|
|
ee1d55 |
- dns_section_t tosection)
|
|
|
ee1d55 |
-{
|
|
|
ee1d55 |
- REQUIRE(msg != NULL);
|
|
|
ee1d55 |
- REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
|
|
|
ee1d55 |
- REQUIRE(name != NULL);
|
|
|
ee1d55 |
- REQUIRE(VALID_NAMED_SECTION(fromsection));
|
|
|
ee1d55 |
- REQUIRE(VALID_NAMED_SECTION(tosection));
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- /*
|
|
|
ee1d55 |
- * Unlink the name from the old section
|
|
|
ee1d55 |
- */
|
|
|
ee1d55 |
- ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
|
|
|
ee1d55 |
- ISC_LIST_APPEND(msg->sections[tosection], name, link);
|
|
|
ee1d55 |
-}
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
dns_message_addname(dns_message_t *msg, dns_name_t *name,
|
|
|
ee1d55 |
dns_section_t section)
|
|
|
ee1d55 |
@@ -2587,6 +2751,9 @@ dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
|
|
|
ee1d55 |
REQUIRE(DNS_MESSAGE_VALID(msg));
|
|
|
ee1d55 |
REQUIRE(item != NULL && *item != NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ if ((*item)->ht != NULL) {
|
|
|
ee1d55 |
+ isc_ht_destroy(&(*item)->ht);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
if (dns_name_dynamic(*item))
|
|
|
ee1d55 |
dns_name_free(*item, msg->mctx);
|
|
|
ee1d55 |
isc_mempool_put(msg->namepool, *item);
|
|
|
ee1d55 |
@@ -2602,14 +2769,19 @@ dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
|
|
|
ee1d55 |
*item = NULL;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+dns__message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
|
|
|
ee1d55 |
+ isc_mempool_put(msg->rdspool, *item);
|
|
|
ee1d55 |
+ *item = NULL;
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
|
|
|
ee1d55 |
REQUIRE(DNS_MESSAGE_VALID(msg));
|
|
|
ee1d55 |
REQUIRE(item != NULL && *item != NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
REQUIRE(!dns_rdataset_isassociated(*item));
|
|
|
ee1d55 |
- isc_mempool_put(msg->rdspool, *item);
|
|
|
ee1d55 |
- *item = NULL;
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, item);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
@@ -2774,7 +2946,7 @@ dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
|
|
|
ee1d55 |
|
|
|
ee1d55 |
cleanup:
|
|
|
ee1d55 |
dns_rdataset_disassociate(opt);
|
|
|
ee1d55 |
- dns_message_puttemprdataset(msg, &opt;;
|
|
|
ee1d55 |
+ dns__message_puttemprdataset(msg, &opt;;
|
|
|
ee1d55 |
return (result);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
diff --git a/lib/dns/name.c b/lib/dns/name.c
|
|
|
ee1d55 |
index e597c63..b3b127b 100644
|
|
|
ee1d55 |
--- a/lib/dns/name.c
|
|
|
ee1d55 |
+++ b/lib/dns/name.c
|
|
|
ee1d55 |
@@ -213,6 +213,7 @@ dns_name_invalidate(dns_name_t *name) {
|
|
|
ee1d55 |
name->offsets = NULL;
|
|
|
ee1d55 |
name->buffer = NULL;
|
|
|
ee1d55 |
ISC_LINK_INIT(name, link);
|
|
|
ee1d55 |
+ INSIST(name->ht == NULL);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_boolean_t
|
|
|
ee1d55 |
diff --git a/lib/isc/ht.c b/lib/isc/ht.c
|
|
|
ee1d55 |
index a86e3ec..0cd3a2c 100644
|
|
|
ee1d55 |
--- a/lib/isc/ht.c
|
|
|
ee1d55 |
+++ b/lib/isc/ht.c
|
|
|
ee1d55 |
@@ -1,6 +1,8 @@
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
+ * SPDX-License-Identifier: MPL-2.0
|
|
|
ee1d55 |
+ *
|
|
|
ee1d55 |
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
ee1d55 |
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
ee1d55 |
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
ee1d55 |
@@ -19,71 +21,290 @@
|
|
|
ee1d55 |
#include <isc/magic.h>
|
|
|
ee1d55 |
#include <isc/mem.h>
|
|
|
ee1d55 |
#include <isc/result.h>
|
|
|
ee1d55 |
+#include <isc/types.h>
|
|
|
ee1d55 |
#include <isc/util.h>
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
typedef struct isc_ht_node isc_ht_node_t;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-#define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b')
|
|
|
ee1d55 |
-#define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC)
|
|
|
ee1d55 |
+#define ISC_HT_MAGIC ISC_MAGIC('H', 'T', 'a', 'b')
|
|
|
ee1d55 |
+#define ISC_HT_VALID(ht) ISC_MAGIC_VALID(ht, ISC_HT_MAGIC)
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+#define HT_NO_BITS 0
|
|
|
ee1d55 |
+#define HT_MIN_BITS 1
|
|
|
ee1d55 |
+#define HT_MAX_BITS 32
|
|
|
ee1d55 |
+#define HT_OVERCOMMIT 3
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+#define HT_NEXTTABLE(idx) ((idx == 0) ? 1 : 0)
|
|
|
ee1d55 |
+#define TRY_NEXTTABLE(idx, ht) (idx == ht->hindex && rehashing_in_progress(ht))
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+#define GOLDEN_RATIO_32 0x61C88647
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+#define HASHSIZE(bits) ((isc_uint64_t)(1) << (bits))
|
|
|
ee1d55 |
|
|
|
ee1d55 |
struct isc_ht_node {
|
|
|
ee1d55 |
void *value;
|
|
|
ee1d55 |
isc_ht_node_t *next;
|
|
|
ee1d55 |
+ isc_uint32_t hashval;
|
|
|
ee1d55 |
size_t keysize;
|
|
|
ee1d55 |
- unsigned char key[FLEXIBLE_ARRAY_MEMBER];
|
|
|
ee1d55 |
+ unsigned char key[];
|
|
|
ee1d55 |
};
|
|
|
ee1d55 |
|
|
|
ee1d55 |
struct isc_ht {
|
|
|
ee1d55 |
unsigned int magic;
|
|
|
ee1d55 |
isc_mem_t *mctx;
|
|
|
ee1d55 |
- size_t size;
|
|
|
ee1d55 |
- size_t mask;
|
|
|
ee1d55 |
- unsigned int count;
|
|
|
ee1d55 |
- isc_ht_node_t **table;
|
|
|
ee1d55 |
+ size_t count;
|
|
|
ee1d55 |
+ isc_boolean_t case_sensitive;
|
|
|
ee1d55 |
+ size_t size[2];
|
|
|
ee1d55 |
+ isc_uint8_t hashbits[2];
|
|
|
ee1d55 |
+ isc_ht_node_t **table[2];
|
|
|
ee1d55 |
+ isc_uint8_t hindex;
|
|
|
ee1d55 |
+ isc_uint32_t hiter; /* rehashing iterator */
|
|
|
ee1d55 |
};
|
|
|
ee1d55 |
|
|
|
ee1d55 |
struct isc_ht_iter {
|
|
|
ee1d55 |
isc_ht_t *ht;
|
|
|
ee1d55 |
size_t i;
|
|
|
ee1d55 |
+ isc_uint8_t hindex;
|
|
|
ee1d55 |
isc_ht_node_t *cur;
|
|
|
ee1d55 |
};
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
-isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, isc_uint8_t bits) {
|
|
|
ee1d55 |
- isc_ht_t *ht = NULL;
|
|
|
ee1d55 |
+static isc_ht_node_t *
|
|
|
ee1d55 |
+isc__ht_find(const isc_ht_t *ht, const unsigned char *key,
|
|
|
ee1d55 |
+ const isc_uint32_t keysize, const isc_uint32_t hashval, const isc_uint8_t idx);
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+isc__ht_add(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize,
|
|
|
ee1d55 |
+ const isc_uint32_t hashval, const isc_uint8_t idx, void *value);
|
|
|
ee1d55 |
+static isc_result_t
|
|
|
ee1d55 |
+isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize,
|
|
|
ee1d55 |
+ const isc_uint32_t hashval, const isc_uint8_t idx);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_uint32_t
|
|
|
ee1d55 |
+rehash_bits(isc_ht_t *ht, size_t newcount);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_new(isc_ht_t *ht, const isc_uint8_t idx, const isc_uint8_t bits);
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_free(isc_ht_t *ht, const isc_uint8_t idx);
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_rehash(isc_ht_t *ht, isc_uint32_t newbits);
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_rehash_one(isc_ht_t *ht);
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+maybe_rehash(isc_ht_t *ht, size_t newcount);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_result_t
|
|
|
ee1d55 |
+isc__ht_iter_next(isc_ht_iter_t *it);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_uint8_t maptolower[] = {
|
|
|
ee1d55 |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
|
|
ee1d55 |
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
|
ee1d55 |
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
|
|
ee1d55 |
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
|
|
ee1d55 |
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
|
|
ee1d55 |
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
|
|
ee1d55 |
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
|
|
|
ee1d55 |
+ 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
|
|
ee1d55 |
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
|
|
|
ee1d55 |
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
|
|
ee1d55 |
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
|
|
|
ee1d55 |
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
|
|
ee1d55 |
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
|
|
|
ee1d55 |
+ 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
|
|
ee1d55 |
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
|
|
ee1d55 |
+ 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
|
|
ee1d55 |
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
|
|
|
ee1d55 |
+ 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
|
|
ee1d55 |
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
|
|
|
ee1d55 |
+ 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
|
|
ee1d55 |
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
|
|
|
ee1d55 |
+ 0xfc, 0xfd, 0xfe, 0xff
|
|
|
ee1d55 |
+};
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static int
|
|
|
ee1d55 |
+memcasecmp(const void *vs1, const void *vs2, size_t len) {
|
|
|
ee1d55 |
+ isc_uint8_t const *s1 = vs1;
|
|
|
ee1d55 |
+ isc_uint8_t const *s2 = vs2;
|
|
|
ee1d55 |
size_t i;
|
|
|
ee1d55 |
+ for (i = 0; i < len; i++) {
|
|
|
ee1d55 |
+ isc_uint8_t u1 = s1[i];
|
|
|
ee1d55 |
+ isc_uint8_t u2 = s2[i];
|
|
|
ee1d55 |
+ int U1 = maptolower[u1];
|
|
|
ee1d55 |
+ int U2 = maptolower[u2];
|
|
|
ee1d55 |
+ int diff = U1 - U2;
|
|
|
ee1d55 |
+ if (diff) {
|
|
|
ee1d55 |
+ return diff;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ return 0;
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- REQUIRE(htp != NULL && *htp == NULL);
|
|
|
ee1d55 |
- REQUIRE(mctx != NULL);
|
|
|
ee1d55 |
- REQUIRE(bits >= 1 && bits <= (sizeof(size_t)*8 - 1));
|
|
|
ee1d55 |
+static isc_boolean_t
|
|
|
ee1d55 |
+isc__ht_node_match(isc_ht_node_t *node, const isc_uint32_t hashval,
|
|
|
ee1d55 |
+ const isc_uint8_t *key, isc_uint32_t keysize, isc_boolean_t case_sensitive) {
|
|
|
ee1d55 |
+ return (node->hashval == hashval && node->keysize == keysize &&
|
|
|
ee1d55 |
+ (case_sensitive ? (memcmp(node->key, key, keysize) == 0)
|
|
|
ee1d55 |
+ : (memcasecmp(node->key, key, keysize) == 0)));
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_uint32_t
|
|
|
ee1d55 |
+hash_32(isc_uint32_t val, unsigned int bits) {
|
|
|
ee1d55 |
+ REQUIRE(bits <= HT_MAX_BITS);
|
|
|
ee1d55 |
+ /* High bits are more random. */
|
|
|
ee1d55 |
+ return (val * GOLDEN_RATIO_32 >> (32 - bits));
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_boolean_t
|
|
|
ee1d55 |
+rehashing_in_progress(const isc_ht_t *ht) {
|
|
|
ee1d55 |
+ return (ht->table[HT_NEXTTABLE(ht->hindex)] != NULL);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- ht = isc_mem_get(mctx, sizeof(struct isc_ht));
|
|
|
ee1d55 |
- if (ht == NULL) {
|
|
|
ee1d55 |
- return (ISC_R_NOMEMORY);
|
|
|
ee1d55 |
+static isc_boolean_t
|
|
|
ee1d55 |
+hashtable_is_overcommited(isc_ht_t *ht) {
|
|
|
ee1d55 |
+ return (ht->count >= (ht->size[ht->hindex] * HT_OVERCOMMIT));
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_uint32_t
|
|
|
ee1d55 |
+rehash_bits(isc_ht_t *ht, size_t newcount) {
|
|
|
ee1d55 |
+ isc_uint32_t newbits = ht->hashbits[ht->hindex];
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ while (newcount >= HASHSIZE(newbits) && newbits <= HT_MAX_BITS) {
|
|
|
ee1d55 |
+ newbits += 1;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- ht->mctx = NULL;
|
|
|
ee1d55 |
- isc_mem_attach(mctx, &ht->mctx);
|
|
|
ee1d55 |
+ return (newbits);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+/*
|
|
|
ee1d55 |
+ * Rebuild the hashtable to reduce the load factor
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_rehash(isc_ht_t *ht, isc_uint32_t newbits) {
|
|
|
ee1d55 |
+ isc_uint8_t oldindex = ht->hindex;
|
|
|
ee1d55 |
+ isc_uint32_t oldbits = ht->hashbits[oldindex];
|
|
|
ee1d55 |
+ isc_uint8_t newindex = HT_NEXTTABLE(oldindex);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ REQUIRE(ht->hashbits[oldindex] >= HT_MIN_BITS);
|
|
|
ee1d55 |
+ REQUIRE(ht->hashbits[oldindex] <= HT_MAX_BITS);
|
|
|
ee1d55 |
+ REQUIRE(ht->table[oldindex] != NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ REQUIRE(newbits <= HT_MAX_BITS);
|
|
|
ee1d55 |
+ REQUIRE(ht->hashbits[newindex] == HT_NO_BITS);
|
|
|
ee1d55 |
+ REQUIRE(ht->table[newindex] == NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ REQUIRE(newbits > oldbits);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- ht->size = ((size_t)1<
|
|
|
ee1d55 |
- ht->mask = ((size_t)1<
|
|
|
ee1d55 |
- ht->count = 0;
|
|
|
ee1d55 |
+ hashtable_new(ht, newindex, newbits);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- ht->table = isc_mem_get(ht->mctx, ht->size * sizeof(isc_ht_node_t*));
|
|
|
ee1d55 |
- if (ht->table == NULL) {
|
|
|
ee1d55 |
- isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht));
|
|
|
ee1d55 |
- return (ISC_R_NOMEMORY);
|
|
|
ee1d55 |
+ ht->hindex = newindex;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ hashtable_rehash_one(ht);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_rehash_one(isc_ht_t *ht) {
|
|
|
ee1d55 |
+ isc_ht_node_t **newtable = ht->table[ht->hindex];
|
|
|
ee1d55 |
+ isc_uint32_t oldsize = ht->size[HT_NEXTTABLE(ht->hindex)];
|
|
|
ee1d55 |
+ isc_ht_node_t **oldtable = ht->table[HT_NEXTTABLE(ht->hindex)];
|
|
|
ee1d55 |
+ isc_ht_node_t *node = NULL;
|
|
|
ee1d55 |
+ isc_ht_node_t *nextnode;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ /* Find first non-empty node */
|
|
|
ee1d55 |
+ while (ht->hiter < oldsize && oldtable[ht->hiter] == NULL) {
|
|
|
ee1d55 |
+ ht->hiter++;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- for (i = 0; i < ht->size; i++) {
|
|
|
ee1d55 |
- ht->table[i] = NULL;
|
|
|
ee1d55 |
+ /* Rehashing complete */
|
|
|
ee1d55 |
+ if (ht->hiter == oldsize) {
|
|
|
ee1d55 |
+ hashtable_free(ht, HT_NEXTTABLE(ht->hindex));
|
|
|
ee1d55 |
+ ht->hiter = 0;
|
|
|
ee1d55 |
+ return;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ /* Move the first non-empty node from old hashtable to new hashtable */
|
|
|
ee1d55 |
+ for (node = oldtable[ht->hiter]; node != NULL; node = nextnode) {
|
|
|
ee1d55 |
+ isc_uint32_t hash = hash_32(node->hashval,
|
|
|
ee1d55 |
+ ht->hashbits[ht->hindex]);
|
|
|
ee1d55 |
+ nextnode = node->next;
|
|
|
ee1d55 |
+ node->next = newtable[hash];
|
|
|
ee1d55 |
+ newtable[hash] = node;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ oldtable[ht->hiter] = NULL;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ ht->hiter++;
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+maybe_rehash(isc_ht_t *ht, size_t newcount) {
|
|
|
ee1d55 |
+ isc_uint32_t newbits = rehash_bits(ht, newcount);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (ht->hashbits[ht->hindex] < newbits && newbits <= HT_MAX_BITS) {
|
|
|
ee1d55 |
+ hashtable_rehash(ht, newbits);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_new(isc_ht_t *ht, const isc_uint8_t idx, const isc_uint8_t bits) {
|
|
|
ee1d55 |
+ size_t size;
|
|
|
ee1d55 |
+ REQUIRE(ht->hashbits[idx] == HT_NO_BITS);
|
|
|
ee1d55 |
+ REQUIRE(ht->table[idx] == NULL);
|
|
|
ee1d55 |
+ REQUIRE(bits >= HT_MIN_BITS);
|
|
|
ee1d55 |
+ REQUIRE(bits <= HT_MAX_BITS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ ht->hashbits[idx] = bits;
|
|
|
ee1d55 |
+ ht->size[idx] = HASHSIZE(ht->hashbits[idx]);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ size = ht->size[idx] * sizeof(isc_ht_node_t *);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ ht->table[idx] = isc_mem_get(ht->mctx, size);
|
|
|
ee1d55 |
+ INSIST(ht->table[idx] != NULL);
|
|
|
ee1d55 |
+ memset(ht->table[idx], 0, size);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+hashtable_free(isc_ht_t *ht, const isc_uint8_t idx) {
|
|
|
ee1d55 |
+ size_t size = ht->size[idx] * sizeof(isc_ht_node_t *);
|
|
|
ee1d55 |
+ size_t i;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ for (i = 0; i < ht->size[idx]; i++) {
|
|
|
ee1d55 |
+ isc_ht_node_t *node = ht->table[idx][i];
|
|
|
ee1d55 |
+ while (node != NULL) {
|
|
|
ee1d55 |
+ isc_ht_node_t *next = node->next;
|
|
|
ee1d55 |
+ ht->count--;
|
|
|
ee1d55 |
+ isc_mem_put(ht->mctx, node,
|
|
|
ee1d55 |
+ sizeof(*node) + node->keysize);
|
|
|
ee1d55 |
+ node = next;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_mem_put(ht->mctx, ht->table[idx], size);
|
|
|
ee1d55 |
+ ht->hashbits[idx] = HT_NO_BITS;
|
|
|
ee1d55 |
+ ht->table[idx] = NULL;
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+void
|
|
|
ee1d55 |
+isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, isc_uint8_t bits,
|
|
|
ee1d55 |
+ unsigned int options) {
|
|
|
ee1d55 |
+ isc_ht_t *ht = NULL;
|
|
|
ee1d55 |
+ isc_boolean_t case_sensitive = ((options & ISC_HT_CASE_INSENSITIVE) == 0);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ REQUIRE(htp != NULL && *htp == NULL);
|
|
|
ee1d55 |
+ REQUIRE(mctx != NULL);
|
|
|
ee1d55 |
+ REQUIRE(bits >= 1 && bits <= HT_MAX_BITS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ ht = isc_mem_get(mctx, sizeof(*ht));
|
|
|
ee1d55 |
+ INSIST(ht != NULL);
|
|
|
ee1d55 |
+ *ht = (isc_ht_t){
|
|
|
ee1d55 |
+ .case_sensitive = case_sensitive,
|
|
|
ee1d55 |
+ };
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_mem_attach(mctx, &ht->mctx);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ hashtable_new(ht, 0, bits);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
ht->magic = ISC_HT_MAGIC;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
*htp = ht;
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
@@ -91,125 +312,190 @@ isc_ht_destroy(isc_ht_t **htp) {
|
|
|
ee1d55 |
isc_ht_t *ht;
|
|
|
ee1d55 |
size_t i;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
REQUIRE(htp != NULL);
|
|
|
ee1d55 |
+ REQUIRE(ISC_HT_VALID(*htp));
|
|
|
ee1d55 |
|
|
|
ee1d55 |
ht = *htp;
|
|
|
ee1d55 |
- REQUIRE(ISC_HT_VALID(ht));
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
+ *htp = NULL;
|
|
|
ee1d55 |
ht->magic = 0;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- for (i = 0; i < ht->size; i++) {
|
|
|
ee1d55 |
- isc_ht_node_t *node = ht->table[i];
|
|
|
ee1d55 |
- while (node != NULL) {
|
|
|
ee1d55 |
- isc_ht_node_t *next = node->next;
|
|
|
ee1d55 |
- ht->count--;
|
|
|
ee1d55 |
- isc_mem_put(ht->mctx, node,
|
|
|
ee1d55 |
- offsetof(isc_ht_node_t, key) +
|
|
|
ee1d55 |
- node->keysize);
|
|
|
ee1d55 |
- node = next;
|
|
|
ee1d55 |
+ for (i = 0; i <= 1; i++) {
|
|
|
ee1d55 |
+ if (ht->table[i] != NULL) {
|
|
|
ee1d55 |
+ hashtable_free(ht, i);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
INSIST(ht->count == 0);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- isc_mem_put(ht->mctx, ht->table, ht->size * sizeof(isc_ht_node_t*));
|
|
|
ee1d55 |
- isc_mem_putanddetach(&ht->mctx, ht, sizeof(struct isc_ht));
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- *htp = NULL;
|
|
|
ee1d55 |
+ isc_mem_putanddetach(&ht->mctx, ht, sizeof(*ht));
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
-isc_ht_add(isc_ht_t *ht, const unsigned char *key,
|
|
|
ee1d55 |
- isc_uint32_t keysize, void *value)
|
|
|
ee1d55 |
-{
|
|
|
ee1d55 |
+static void
|
|
|
ee1d55 |
+isc__ht_add(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize,
|
|
|
ee1d55 |
+ const isc_uint32_t hashval, const isc_uint8_t idx, void *value) {
|
|
|
ee1d55 |
isc_ht_node_t *node;
|
|
|
ee1d55 |
isc_uint32_t hash;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ hash = hash_32(hashval, ht->hashbits[idx]);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ node = isc_mem_get(ht->mctx, sizeof(*node) + keysize);
|
|
|
ee1d55 |
+ INSIST(node != NULL);
|
|
|
ee1d55 |
+ *node = (isc_ht_node_t){
|
|
|
ee1d55 |
+ .keysize = keysize,
|
|
|
ee1d55 |
+ .hashval = hashval,
|
|
|
ee1d55 |
+ .next = ht->table[idx][hash],
|
|
|
ee1d55 |
+ .value = value,
|
|
|
ee1d55 |
+ };
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ memmove(node->key, key, keysize);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ ht->count++;
|
|
|
ee1d55 |
+ ht->table[idx][hash] = node;
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+isc_result_t
|
|
|
ee1d55 |
+isc_ht_add(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize,
|
|
|
ee1d55 |
+ void *value) {
|
|
|
ee1d55 |
+ isc_uint32_t hashval;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
REQUIRE(ISC_HT_VALID(ht));
|
|
|
ee1d55 |
REQUIRE(key != NULL && keysize > 0);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- hash = isc_hash_function(key, keysize, ISC_TRUE, NULL);
|
|
|
ee1d55 |
- node = ht->table[hash & ht->mask];
|
|
|
ee1d55 |
- while (node != NULL) {
|
|
|
ee1d55 |
- if (keysize == node->keysize &&
|
|
|
ee1d55 |
- memcmp(key, node->key, keysize) == 0) {
|
|
|
ee1d55 |
- return (ISC_R_EXISTS);
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
- node = node->next;
|
|
|
ee1d55 |
+ if (rehashing_in_progress(ht)) {
|
|
|
ee1d55 |
+ /* Rehash in progress */
|
|
|
ee1d55 |
+ hashtable_rehash_one(ht);
|
|
|
ee1d55 |
+ } else if (hashtable_is_overcommited(ht)) {
|
|
|
ee1d55 |
+ /* Rehash requested */
|
|
|
ee1d55 |
+ maybe_rehash(ht, ht->count);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- node = isc_mem_get(ht->mctx, offsetof(isc_ht_node_t, key) + keysize);
|
|
|
ee1d55 |
- if (node == NULL)
|
|
|
ee1d55 |
- return (ISC_R_NOMEMORY);
|
|
|
ee1d55 |
+ hashval = isc_hash_function(key, keysize, ht->case_sensitive, NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- memmove(node->key, key, keysize);
|
|
|
ee1d55 |
- node->keysize = keysize;
|
|
|
ee1d55 |
- node->next = ht->table[hash & ht->mask];
|
|
|
ee1d55 |
- node->value = value;
|
|
|
ee1d55 |
+ if (isc__ht_find(ht, key, keysize, hashval, ht->hindex) != NULL) {
|
|
|
ee1d55 |
+ return (ISC_R_EXISTS);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc__ht_add(ht, key, keysize, hashval, ht->hindex, value);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- ht->count++;
|
|
|
ee1d55 |
- ht->table[hash & ht->mask] = node;
|
|
|
ee1d55 |
return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+static isc_ht_node_t *
|
|
|
ee1d55 |
+isc__ht_find(const isc_ht_t *ht, const unsigned char *key,
|
|
|
ee1d55 |
+ const isc_uint32_t keysize, const isc_uint32_t hashval,
|
|
|
ee1d55 |
+ const isc_uint8_t idx) {
|
|
|
ee1d55 |
+ isc_uint32_t hash;
|
|
|
ee1d55 |
+ isc_uint8_t findex = idx;
|
|
|
ee1d55 |
+ isc_ht_node_t *node;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+nexttable:
|
|
|
ee1d55 |
+ hash = hash_32(hashval, ht->hashbits[findex]);
|
|
|
ee1d55 |
+ for (node = ht->table[findex][hash]; node != NULL;
|
|
|
ee1d55 |
+ node = node->next)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ if (isc__ht_node_match(node, hashval, key, keysize,
|
|
|
ee1d55 |
+ ht->case_sensitive))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ return (node);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ if (TRY_NEXTTABLE(findex, ht)) {
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Rehashing in progress, check the other table
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ findex = HT_NEXTTABLE(findex);
|
|
|
ee1d55 |
+ goto nexttable;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ return (NULL);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
|
|
|
ee1d55 |
- isc_uint32_t keysize, void **valuep)
|
|
|
ee1d55 |
-{
|
|
|
ee1d55 |
+ const isc_uint32_t keysize, void **valuep) {
|
|
|
ee1d55 |
+ isc_uint32_t hashval;
|
|
|
ee1d55 |
isc_ht_node_t *node;
|
|
|
ee1d55 |
- isc_uint32_t hash;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
REQUIRE(ISC_HT_VALID(ht));
|
|
|
ee1d55 |
REQUIRE(key != NULL && keysize > 0);
|
|
|
ee1d55 |
REQUIRE(valuep == NULL || *valuep == NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- hash = isc_hash_function(key, keysize, ISC_TRUE, NULL);
|
|
|
ee1d55 |
- node = ht->table[hash & ht->mask];
|
|
|
ee1d55 |
- while (node != NULL) {
|
|
|
ee1d55 |
- if (keysize == node->keysize &&
|
|
|
ee1d55 |
- memcmp(key, node->key, keysize) == 0) {
|
|
|
ee1d55 |
- *valuep = node->value;
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
- node = node->next;
|
|
|
ee1d55 |
+ hashval = isc_hash_function(key, keysize, ht->case_sensitive, NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ node = isc__ht_find(ht, key, keysize, hashval, ht->hindex);
|
|
|
ee1d55 |
+ if (node == NULL) {
|
|
|
ee1d55 |
+ return (ISC_R_NOTFOUND);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- return (ISC_R_NOTFOUND);
|
|
|
ee1d55 |
+ if (valuep != NULL) {
|
|
|
ee1d55 |
+ *valuep = node->value;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+ return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
-isc_ht_delete(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize) {
|
|
|
ee1d55 |
- isc_ht_node_t *node, *prev;
|
|
|
ee1d55 |
+static isc_result_t
|
|
|
ee1d55 |
+isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize,
|
|
|
ee1d55 |
+ const isc_uint32_t hashval, const isc_uint8_t idx) {
|
|
|
ee1d55 |
+ isc_ht_node_t *prev = NULL;
|
|
|
ee1d55 |
isc_uint32_t hash;
|
|
|
ee1d55 |
+ isc_ht_node_t *node;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- REQUIRE(ISC_HT_VALID(ht));
|
|
|
ee1d55 |
- REQUIRE(key != NULL && keysize > 0);
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- prev = NULL;
|
|
|
ee1d55 |
- hash = isc_hash_function(key, keysize, ISC_TRUE, NULL);
|
|
|
ee1d55 |
- node = ht->table[hash & ht->mask];
|
|
|
ee1d55 |
- while (node != NULL) {
|
|
|
ee1d55 |
- if (keysize == node->keysize &&
|
|
|
ee1d55 |
- memcmp(key, node->key, keysize) == 0) {
|
|
|
ee1d55 |
- if (prev == NULL)
|
|
|
ee1d55 |
- ht->table[hash & ht->mask] = node->next;
|
|
|
ee1d55 |
- else
|
|
|
ee1d55 |
+ hash = hash_32(hashval, ht->hashbits[idx]);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ for (node = ht->table[idx][hash]; node != NULL;
|
|
|
ee1d55 |
+ prev = node, node = node->next)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ if (isc__ht_node_match(node, hashval, key, keysize,
|
|
|
ee1d55 |
+ ht->case_sensitive))
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
+ if (prev == NULL) {
|
|
|
ee1d55 |
+ ht->table[idx][hash] = node->next;
|
|
|
ee1d55 |
+ } else {
|
|
|
ee1d55 |
prev->next = node->next;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
isc_mem_put(ht->mctx, node,
|
|
|
ee1d55 |
- offsetof(isc_ht_node_t, key) +
|
|
|
ee1d55 |
- node->keysize);
|
|
|
ee1d55 |
+ sizeof(*node) + node->keysize);
|
|
|
ee1d55 |
ht->count--;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- prev = node;
|
|
|
ee1d55 |
- node = node->next;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
return (ISC_R_NOTFOUND);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
+isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize) {
|
|
|
ee1d55 |
+ isc_uint32_t hashval;
|
|
|
ee1d55 |
+ isc_uint8_t hindex;
|
|
|
ee1d55 |
+ isc_result_t result;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ REQUIRE(ISC_HT_VALID(ht));
|
|
|
ee1d55 |
+ REQUIRE(key != NULL && keysize > 0);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (rehashing_in_progress(ht)) {
|
|
|
ee1d55 |
+ /* Rehash in progress */
|
|
|
ee1d55 |
+ hashtable_rehash_one(ht);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ hindex = ht->hindex;
|
|
|
ee1d55 |
+ hashval = isc_hash_function(key, keysize, ht->case_sensitive, NULL);
|
|
|
ee1d55 |
+nexttable:
|
|
|
ee1d55 |
+ result = isc__ht_delete(ht, key, keysize, hashval, hindex);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (result == ISC_R_NOTFOUND && TRY_NEXTTABLE(hindex, ht)) {
|
|
|
ee1d55 |
+ /*
|
|
|
ee1d55 |
+ * Rehashing in progress, check the other table
|
|
|
ee1d55 |
+ */
|
|
|
ee1d55 |
+ hindex = HT_NEXTTABLE(hindex);
|
|
|
ee1d55 |
+ goto nexttable;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ return (result);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+void
|
|
|
ee1d55 |
isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) {
|
|
|
ee1d55 |
isc_ht_iter_t *it;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
@@ -217,16 +503,13 @@ isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp) {
|
|
|
ee1d55 |
REQUIRE(itp != NULL && *itp == NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
it = isc_mem_get(ht->mctx, sizeof(isc_ht_iter_t));
|
|
|
ee1d55 |
- if (it == NULL)
|
|
|
ee1d55 |
- return (ISC_R_NOMEMORY);
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- it->ht = ht;
|
|
|
ee1d55 |
- it->i = 0;
|
|
|
ee1d55 |
- it->cur = NULL;
|
|
|
ee1d55 |
+ INSIST(it != NULL);
|
|
|
ee1d55 |
+ *it = (isc_ht_iter_t){
|
|
|
ee1d55 |
+ .ht = ht,
|
|
|
ee1d55 |
+ .hindex = ht->hindex,
|
|
|
ee1d55 |
+ };
|
|
|
ee1d55 |
|
|
|
ee1d55 |
*itp = it;
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
@@ -237,26 +520,48 @@ isc_ht_iter_destroy(isc_ht_iter_t **itp) {
|
|
|
ee1d55 |
REQUIRE(itp != NULL && *itp != NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
it = *itp;
|
|
|
ee1d55 |
- ht = it->ht;
|
|
|
ee1d55 |
- isc_mem_put(ht->mctx, it, sizeof(isc_ht_iter_t));
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
*itp = NULL;
|
|
|
ee1d55 |
+ ht = it->ht;
|
|
|
ee1d55 |
+ isc_mem_put(ht->mctx, it, sizeof(*it));
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
isc_ht_iter_first(isc_ht_iter_t *it) {
|
|
|
ee1d55 |
+ isc_ht_t *ht;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
REQUIRE(it != NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ ht = it->ht;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ it->hindex = ht->hindex;
|
|
|
ee1d55 |
it->i = 0;
|
|
|
ee1d55 |
- while (it->i < it->ht->size && it->ht->table[it->i] == NULL)
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ return (isc__ht_iter_next(it));
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+static isc_result_t
|
|
|
ee1d55 |
+isc__ht_iter_next(isc_ht_iter_t *it) {
|
|
|
ee1d55 |
+ isc_ht_t *ht = it->ht;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ while (it->i < ht->size[it->hindex] &&
|
|
|
ee1d55 |
+ ht->table[it->hindex][it->i] == NULL)
|
|
|
ee1d55 |
+ {
|
|
|
ee1d55 |
it->i++;
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if (it->i == it->ht->size)
|
|
|
ee1d55 |
- return (ISC_R_NOMORE);
|
|
|
ee1d55 |
+ if (it->i < ht->size[it->hindex]) {
|
|
|
ee1d55 |
+ it->cur = ht->table[it->hindex][it->i];
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- it->cur = it->ht->table[it->i];
|
|
|
ee1d55 |
+ return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ if (TRY_NEXTTABLE(it->hindex, ht)) {
|
|
|
ee1d55 |
+ it->hindex = HT_NEXTTABLE(it->hindex);
|
|
|
ee1d55 |
+ it->i = 0;
|
|
|
ee1d55 |
+ return (isc__ht_iter_next(it));
|
|
|
ee1d55 |
+ }
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ return (ISC_R_NOMORE);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
@@ -265,58 +570,35 @@ isc_ht_iter_next(isc_ht_iter_t *it) {
|
|
|
ee1d55 |
REQUIRE(it->cur != NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
it->cur = it->cur->next;
|
|
|
ee1d55 |
- if (it->cur == NULL) {
|
|
|
ee1d55 |
- do {
|
|
|
ee1d55 |
- it->i++;
|
|
|
ee1d55 |
- } while (it->i < it->ht->size && it->ht->table[it->i] == NULL);
|
|
|
ee1d55 |
- if (it->i >= it->ht->size)
|
|
|
ee1d55 |
- return (ISC_R_NOMORE);
|
|
|
ee1d55 |
- it->cur = it->ht->table[it->i];
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ if (it->cur != NULL) {
|
|
|
ee1d55 |
+ return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- return (ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ it->i++;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ return (isc__ht_iter_next(it));
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
isc_ht_iter_delcurrent_next(isc_ht_iter_t *it) {
|
|
|
ee1d55 |
isc_result_t result = ISC_R_SUCCESS;
|
|
|
ee1d55 |
- isc_ht_node_t *to_delete = NULL;
|
|
|
ee1d55 |
- isc_ht_node_t *prev = NULL;
|
|
|
ee1d55 |
- isc_ht_node_t *node = NULL;
|
|
|
ee1d55 |
- isc_uint32_t hash;
|
|
|
ee1d55 |
+ isc_ht_node_t *dnode = NULL;
|
|
|
ee1d55 |
+ isc_uint8_t dindex;
|
|
|
ee1d55 |
isc_ht_t *ht;
|
|
|
ee1d55 |
+ isc_result_t dresult;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
REQUIRE(it != NULL);
|
|
|
ee1d55 |
REQUIRE(it->cur != NULL);
|
|
|
ee1d55 |
- to_delete = it->cur;
|
|
|
ee1d55 |
ht = it->ht;
|
|
|
ee1d55 |
+ dnode = it->cur;
|
|
|
ee1d55 |
+ dindex = it->hindex;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- it->cur = it->cur->next;
|
|
|
ee1d55 |
- if (it->cur == NULL) {
|
|
|
ee1d55 |
- do {
|
|
|
ee1d55 |
- it->i++;
|
|
|
ee1d55 |
- } while (it->i < ht->size && ht->table[it->i] == NULL);
|
|
|
ee1d55 |
- if (it->i >= ht->size)
|
|
|
ee1d55 |
- result = ISC_R_NOMORE;
|
|
|
ee1d55 |
- else
|
|
|
ee1d55 |
- it->cur = ht->table[it->i];
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
-
|
|
|
ee1d55 |
- hash = isc_hash_function(to_delete->key, to_delete->keysize, ISC_TRUE,
|
|
|
ee1d55 |
- NULL);
|
|
|
ee1d55 |
- node = ht->table[hash & ht->mask];
|
|
|
ee1d55 |
- while (node != to_delete) {
|
|
|
ee1d55 |
- prev = node;
|
|
|
ee1d55 |
- node = node->next;
|
|
|
ee1d55 |
- INSIST(node != NULL);
|
|
|
ee1d55 |
- }
|
|
|
ee1d55 |
+ result = isc_ht_iter_next(it);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- if (prev == NULL)
|
|
|
ee1d55 |
- ht->table[hash & ht->mask] = node->next;
|
|
|
ee1d55 |
- else
|
|
|
ee1d55 |
- prev->next = node->next;
|
|
|
ee1d55 |
- isc_mem_put(ht->mctx, node,
|
|
|
ee1d55 |
- offsetof(isc_ht_node_t, key) + node->keysize);
|
|
|
ee1d55 |
- ht->count--;
|
|
|
ee1d55 |
+ dresult = isc__ht_delete(ht, dnode->key, dnode->keysize, dnode->hashval,
|
|
|
ee1d55 |
+ dindex);
|
|
|
ee1d55 |
+ INSIST(dresult == ISC_R_SUCCESS);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
return (result);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
@@ -331,8 +613,8 @@ isc_ht_iter_current(isc_ht_iter_t *it, void **valuep) {
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
void
|
|
|
ee1d55 |
-isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize)
|
|
|
ee1d55 |
-{
|
|
|
ee1d55 |
+isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key,
|
|
|
ee1d55 |
+ size_t *keysize) {
|
|
|
ee1d55 |
REQUIRE(it != NULL);
|
|
|
ee1d55 |
REQUIRE(it->cur != NULL);
|
|
|
ee1d55 |
REQUIRE(key != NULL && *key == NULL);
|
|
|
ee1d55 |
@@ -341,9 +623,9 @@ isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize)
|
|
|
ee1d55 |
*keysize = it->cur->keysize;
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-unsigned int
|
|
|
ee1d55 |
-isc_ht_count(isc_ht_t *ht) {
|
|
|
ee1d55 |
+size_t
|
|
|
ee1d55 |
+isc_ht_count(const isc_ht_t *ht) {
|
|
|
ee1d55 |
REQUIRE(ISC_HT_VALID(ht));
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- return(ht->count);
|
|
|
ee1d55 |
+ return (ht->count);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
diff --git a/lib/isc/include/isc/ht.h b/lib/isc/include/isc/ht.h
|
|
|
ee1d55 |
index ea9eab7..843e671 100644
|
|
|
ee1d55 |
--- a/lib/isc/include/isc/ht.h
|
|
|
ee1d55 |
+++ b/lib/isc/include/isc/ht.h
|
|
|
ee1d55 |
@@ -1,6 +1,8 @@
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
+ * SPDX-License-Identifier: MPL-2.0
|
|
|
ee1d55 |
+ *
|
|
|
ee1d55 |
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
ee1d55 |
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
ee1d55 |
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
ee1d55 |
@@ -11,30 +13,33 @@
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/* ! \file */
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-#ifndef ISC_HT_H
|
|
|
ee1d55 |
-#define ISC_HT_H 1
|
|
|
ee1d55 |
+#pragma once
|
|
|
ee1d55 |
|
|
|
ee1d55 |
#include <string.h>
|
|
|
ee1d55 |
-#include <isc/types.h>
|
|
|
ee1d55 |
#include <isc/result.h>
|
|
|
ee1d55 |
+#include <isc/types.h>
|
|
|
ee1d55 |
|
|
|
ee1d55 |
-typedef struct isc_ht isc_ht_t;
|
|
|
ee1d55 |
+typedef struct isc_ht isc_ht_t;
|
|
|
ee1d55 |
typedef struct isc_ht_iter isc_ht_iter_t;
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+enum { ISC_HT_CASE_SENSITIVE = 0x00, ISC_HT_CASE_INSENSITIVE = 0x01 };
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
* Initialize hashtable at *htp, using memory context and size of (1<
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
+ * If 'options' contains ISC_HT_CASE_INSENSITIVE, then upper- and lower-case
|
|
|
ee1d55 |
+ * letters in key values will generate the same hash values; this can be used
|
|
|
ee1d55 |
+ * when the key for a hash table is a DNS name.
|
|
|
ee1d55 |
+ *
|
|
|
ee1d55 |
* Requires:
|
|
|
ee1d55 |
*\li 'htp' is not NULL and '*htp' is NULL.
|
|
|
ee1d55 |
*\li 'mctx' is a valid memory context.
|
|
|
ee1d55 |
*\li 'bits' >=1 and 'bits' <=32
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
- * Returns:
|
|
|
ee1d55 |
- *\li #ISC_R_NOMEMORY -- not enough memory to create pool
|
|
|
ee1d55 |
- *\li #ISC_R_SUCCESS -- all is well.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
-isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, isc_uint8_t bits);
|
|
|
ee1d55 |
+void
|
|
|
ee1d55 |
+isc_ht_init(isc_ht_t **htp, isc_mem_t *mctx, isc_uint8_t bits,
|
|
|
ee1d55 |
+ unsigned int options);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
* Destroy hashtable, freeing everything
|
|
|
ee1d55 |
@@ -51,6 +56,7 @@ isc_ht_destroy(isc_ht_t **htp);
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
* Requires:
|
|
|
ee1d55 |
*\li 'ht' is a valid hashtable
|
|
|
ee1d55 |
+ *\li write-lock
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
* Returns:
|
|
|
ee1d55 |
*\li #ISC_R_NOMEMORY -- not enough memory to create pool
|
|
|
ee1d55 |
@@ -58,15 +64,18 @@ isc_ht_destroy(isc_ht_t **htp);
|
|
|
ee1d55 |
*\li #ISC_R_SUCCESS -- all is well.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
-isc_ht_add(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize,
|
|
|
ee1d55 |
- void *value);
|
|
|
ee1d55 |
+isc_ht_add(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize,
|
|
|
ee1d55 |
+ void *value);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
* Find a node matching 'key'/'keysize' in hashtable 'ht';
|
|
|
ee1d55 |
- * if found, set 'value' to its value
|
|
|
ee1d55 |
+ * if found, set '*valuep' to its value. (If 'valuep' is NULL,
|
|
|
ee1d55 |
+ * then simply return SUCCESS or NOTFOUND to indicate whether the
|
|
|
ee1d55 |
+ * key exists in the hashtable.)
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
* Requires:
|
|
|
ee1d55 |
* \li 'ht' is a valid hashtable
|
|
|
ee1d55 |
+ * \li read-lock
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
* Returns:
|
|
|
ee1d55 |
* \li #ISC_R_SUCCESS -- success
|
|
|
ee1d55 |
@@ -74,20 +83,21 @@ isc_ht_add(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize,
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
isc_ht_find(const isc_ht_t *ht, const unsigned char *key,
|
|
|
ee1d55 |
- isc_uint32_t keysize, void **valuep);
|
|
|
ee1d55 |
+ const isc_uint32_t keysize, void **valuep);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
* Delete node from hashtable
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
* Requires:
|
|
|
ee1d55 |
*\li ht is a valid hashtable
|
|
|
ee1d55 |
+ *\li write-lock
|
|
|
ee1d55 |
*
|
|
|
ee1d55 |
* Returns:
|
|
|
ee1d55 |
*\li #ISC_R_NOTFOUND -- key not found
|
|
|
ee1d55 |
*\li #ISC_R_SUCCESS -- all is well
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
isc_result_t
|
|
|
ee1d55 |
-isc_ht_delete(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize);
|
|
|
ee1d55 |
+isc_ht_delete(isc_ht_t *ht, const unsigned char *key, const isc_uint32_t keysize);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
* Create an iterator for the hashtable; point '*itp' to it.
|
|
|
ee1d55 |
@@ -96,7 +106,7 @@ isc_ht_delete(isc_ht_t *ht, const unsigned char *key, isc_uint32_t keysize);
|
|
|
ee1d55 |
*\li 'ht' is a valid hashtable
|
|
|
ee1d55 |
*\li 'itp' is non NULL and '*itp' is NULL.
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
-isc_result_t
|
|
|
ee1d55 |
+void
|
|
|
ee1d55 |
isc_ht_iter_create(isc_ht_t *ht, isc_ht_iter_t **itp);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
/*%
|
|
|
ee1d55 |
@@ -176,6 +186,5 @@ isc_ht_iter_currentkey(isc_ht_iter_t *it, unsigned char **key, size_t *keysize);
|
|
|
ee1d55 |
* Requires:
|
|
|
ee1d55 |
*\li 'ht' is a valid hashtable
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
-unsigned int
|
|
|
ee1d55 |
-isc_ht_count(isc_ht_t *ht);
|
|
|
ee1d55 |
-#endif
|
|
|
ee1d55 |
+size_t
|
|
|
ee1d55 |
+isc_ht_count(const isc_ht_t *ht);
|
|
|
ee1d55 |
diff --git a/lib/isc/tests/ht_test.c b/lib/isc/tests/ht_test.c
|
|
|
ee1d55 |
index 11ffb79..f1b2782 100644
|
|
|
ee1d55 |
--- a/lib/isc/tests/ht_test.c
|
|
|
ee1d55 |
+++ b/lib/isc/tests/ht_test.c
|
|
|
ee1d55 |
@@ -52,8 +52,7 @@ static void test_ht_full(int bits, uintptr_t count) {
|
|
|
ee1d55 |
NULL, &mctx, 0);
|
|
|
ee1d55 |
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_init(&ht, mctx, bits);
|
|
|
ee1d55 |
- ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_init(&ht, mctx, bits, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
ATF_REQUIRE(ht != NULL);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
for (i = 1; i < count; i++) {
|
|
|
ee1d55 |
@@ -203,8 +202,7 @@ static void test_ht_iterator() {
|
|
|
ee1d55 |
NULL, &mctx, 0);
|
|
|
ee1d55 |
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
- result = isc_ht_init(&ht, mctx, 16);
|
|
|
ee1d55 |
- ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_init(&ht, mctx, 16, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
ATF_REQUIRE(ht != NULL);
|
|
|
ee1d55 |
for (i = 1; i <= count; i++) {
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
@@ -218,8 +216,7 @@ static void test_ht_iterator() {
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
walked = 0;
|
|
|
ee1d55 |
- result = isc_ht_iter_create(ht, &iter);
|
|
|
ee1d55 |
- ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ isc_ht_iter_create(ht, &iter);
|
|
|
ee1d55 |
|
|
|
ee1d55 |
for (result = isc_ht_iter_first(iter);
|
|
|
ee1d55 |
result == ISC_R_SUCCESS;
|
|
|
ee1d55 |
@@ -303,6 +300,61 @@ static void test_ht_iterator() {
|
|
|
ee1d55 |
ATF_REQUIRE_EQ(ht, NULL);
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+static void test_ht_case() {
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_ht_t *ht = NULL;
|
|
|
ee1d55 |
+ void *f = NULL;
|
|
|
ee1d55 |
+ isc_result_t result = ISC_R_UNSET;
|
|
|
ee1d55 |
+ isc_mem_t *mctx = NULL;
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
|
|
|
ee1d55 |
+ NULL, &mctx, 0);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ unsigned char lower[16] = { "test case" };
|
|
|
ee1d55 |
+ unsigned char same[16] = { "test case" };
|
|
|
ee1d55 |
+ unsigned char upper[16] = { "TEST CASE" };
|
|
|
ee1d55 |
+ unsigned char mixed[16] = { "tEsT CaSe" };
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_ht_init(&ht, mctx, 8, ISC_HT_CASE_SENSITIVE);
|
|
|
ee1d55 |
+ ATF_REQUIRE(ht != NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, lower, 16, (void *)lower);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, same, 16, (void *)same);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_EXISTS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, upper, 16, (void *)upper);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_find(ht, mixed, 16, &f);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(f, NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_ht_destroy(&ht;;
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(ht, NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_ht_init(&ht, mctx, 8, ISC_HT_CASE_INSENSITIVE);
|
|
|
ee1d55 |
+ ATF_REQUIRE(ht != NULL);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, lower, 16, (void *)lower);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, same, 16, (void *)same);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_EXISTS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_add(ht, upper, 16, (void *)upper);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_EXISTS);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ result = isc_ht_find(ht, mixed, 16, &f);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(f, &lower);
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ isc_ht_destroy(&ht;;
|
|
|
ee1d55 |
+ ATF_REQUIRE_EQ(ht, NULL);
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
ATF_TC(isc_ht_20);
|
|
|
ee1d55 |
ATF_TC_HEAD(isc_ht_20, tc) {
|
|
|
ee1d55 |
atf_tc_set_md_var(tc, "descr", "20 bit, 200K elements test");
|
|
|
ee1d55 |
@@ -357,6 +409,16 @@ ATF_TC_BODY(isc_ht_iterator, tc) {
|
|
|
ee1d55 |
test_ht_iterator();
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
|
|
|
ee1d55 |
+ATF_TC(isc_ht_case);
|
|
|
ee1d55 |
+ATF_TC_HEAD(isc_ht_case, tc) {
|
|
|
ee1d55 |
+ atf_tc_set_md_var(tc, "descr", "case sensitivity test");
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
+ATF_TC_BODY(isc_ht_case, tc) {
|
|
|
ee1d55 |
+ UNUSED(tc);
|
|
|
ee1d55 |
+ test_ht_case();
|
|
|
ee1d55 |
+}
|
|
|
ee1d55 |
+
|
|
|
ee1d55 |
/*
|
|
|
ee1d55 |
* Main
|
|
|
ee1d55 |
*/
|
|
|
ee1d55 |
@@ -366,5 +428,6 @@ ATF_TP_ADD_TCS(tp) {
|
|
|
ee1d55 |
ATF_TP_ADD_TC(tp, isc_ht_1);
|
|
|
ee1d55 |
/* ATF_TP_ADD_TC(tp, isc_ht_32); */
|
|
|
ee1d55 |
ATF_TP_ADD_TC(tp, isc_ht_iterator);
|
|
|
ee1d55 |
+ ATF_TP_ADD_TC(tp, isc_ht_case);
|
|
|
ee1d55 |
return (atf_no_error());
|
|
|
ee1d55 |
}
|
|
|
ee1d55 |
--
|
|
|
ee1d55 |
2.45.0
|
|
|
ee1d55 |
|