Skip to content

Commit 3aca907

Browse files
authored
Fix bug with SOA records not updating correctly (#266)
Note that the SOA record is stored twice: once in the zones table (the `authority` section of the `#zone{}` record), and another one as a standalone RRSet in the typed records table. And then the resolution algorithm would use the RRSet in the typed records table as the answer for an explicit query to SOA records but the cached ones on the zone record for any other query that required including SOA records. This would be an issue for DNSSEC, because for example an NSEC answer would include the RRSIG record of the _new_ SOA record, but with the _old_ SOA record, hence triggering a validation failure. Note that this code was available in v7, and it was lost just very unfortunately. The PR comes with a regression test.
1 parent 227f81c commit 3aca907

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

src/zones/erldns_zone_cache.erl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,11 @@ delete_zone_rrset(ZoneName, Digest, RRFqdn, Type, Counter) ->
505505
update_zone_records_and_digest(ZLabels, RecordsCount, Digest) ->
506506
case find_zone_in_cache(ZLabels) of
507507
#zone{} = Zone ->
508-
UpdatedZone = Zone#zone{version = Digest, record_count = RecordsCount},
508+
UpdatedZone = Zone#zone{
509+
version = Digest,
510+
authority = get_records_by_name_and_type(Zone, ZLabels, ?DNS_TYPE_SOA),
511+
record_count = RecordsCount
512+
},
509513
true = insert_zone(UpdatedZone),
510514
ok;
511515
zone_not_found ->

test/zones_SUITE.erl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ groups() ->
6666
is_record_name_in_zone_strict,
6767
put_zone,
6868
put_zone_rrset,
69+
put_zone_rrset_fetch_soa_match,
6970
put_zone_rrset_records_count_with_existing_rrset,
7071
put_zone_rrset_records_count_with_new_rrset,
7172
put_zone_rrset_records_count_matches_cache,
@@ -738,6 +739,43 @@ put_zone_rrset(_) ->
738739
% There should be no change in record count
739740
?assertEqual(ZoneBase#zone.record_count, ZoneModified#zone.record_count).
740741

742+
put_zone_rrset_fetch_soa_match(_) ->
743+
ZoneName = dns:dname_to_lower(~"put_zone_rrset_fetch_soa_match.com"),
744+
SoaData = #dns_rrdata_soa{
745+
mname = ~"ns1.put_zone_rrset_fetch_soa_match.com",
746+
rname = ~"admin.put_zone_rrset_fetch_soa_match.com",
747+
serial = 12345,
748+
refresh = 555,
749+
retry = 666,
750+
expire = 777,
751+
minimum = 888
752+
},
753+
SOA = #dns_rr{
754+
name = ZoneName,
755+
type = ?DNS_TYPE_SOA,
756+
data = SoaData,
757+
ttl = 3600
758+
},
759+
Z = erldns_zone_codec:build_zone(ZoneName, ~"Digest-01", [SOA], []),
760+
?assertMatch(ok, erldns_zone_cache:put_zone(Z)),
761+
ZoneBase = erldns_zone_cache:get_authoritative_zone(ZoneName),
762+
SoaRecordsInCache = erldns_zone_cache:get_records_by_name_and_type(ZoneName, ?DNS_TYPE_SOA),
763+
?assertMatch(SoaRecordsInCache, ZoneBase#zone.authority),
764+
NewSoa = SOA#dns_rr{data = SoaData#dns_rrdata_soa{serial = 12346}},
765+
?assertMatch(
766+
ok,
767+
erldns_zone_cache:put_zone_rrset(
768+
{ZoneName, ~"Digest-02", [NewSoa], []},
769+
~"put_zone_rrset_fetch_soa_match.com",
770+
?DNS_TYPE_SOA,
771+
1
772+
)
773+
),
774+
ZoneModified = erldns_zone_cache:get_authoritative_zone(ZoneName),
775+
NewSoaRecordsInCache = erldns_zone_cache:get_records_by_name_and_type(ZoneName, ?DNS_TYPE_SOA),
776+
Comment = #{soa_in_zone => ZoneModified#zone.authority, soa_in_cache => NewSoaRecordsInCache},
777+
?assertMatch(NewSoaRecordsInCache, ZoneModified#zone.authority, Comment).
778+
741779
put_zone_rrset_records_count_with_existing_rrset(_) ->
742780
ZoneName = dns:dname_to_lower(~"example.com"),
743781
ZoneLabels = dns:dname_to_labels(ZoneName),

0 commit comments

Comments
 (0)