Skip to content

fix bug in zone class wrt SOA/RRSig #335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/org/xbill/DNS/Zone.java
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ public <T extends Record> void addRecord(T r) {

Name name = r.getName();
int rtype = r.getRRsetType();
int actualType = r.getType();

if (rtype == Type.SOA && !name.equals(origin)) {
throw new IllegalArgumentException(
Expand All @@ -254,7 +255,7 @@ public <T extends Record> void addRecord(T r) {
} else {
// Adding a SOA must replace any existing record. We validated before that the zone name
// didn't change
if (rtype == Type.SOA) {
if (actualType == Type.SOA) {
rrset.deleteRR(SOA);
SOA = (SOARecord) r;
}
Expand Down
206 changes: 206 additions & 0 deletions src/test/java/org/xbill/DNS/ZoneWithSoaSigTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// SPDX-License-Identifier: BSD-3-Clause
package org.xbill.DNS;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.junit.jupiter.api.Test;

public class ZoneWithSoaSigTest {
@Test
void canParseZoneWithSigs() throws IOException {
Name an = Name.fromString("10.in-addr.arpa.");
Name host = Name.fromString("z.example.com.");
Name secondary = Name.fromString("y.example.com.");
Name admin = Name.fromString("dns-ops.example.com.");

long ttl = 86400;
long serial = 2147483749L;
long refresh = 1800;
long retry = 900;
long expire = 691200;
long minimum = 10800;

// dummy set of records for a dummy zone
Record[] records =
new Record[] {
new SOARecord(an, DClass.IN, ttl, host, admin, serial, refresh, retry, expire, minimum),
new NSRecord(an, DClass.IN, ttl, host),
new NSRecord(an, DClass.IN, ttl, secondary),
new DNSKEYRecord(
an, DClass.IN, ttl, 256, 3, 5, "dummypublickey".getBytes(StandardCharsets.UTF_8)),
new RRSIGRecord(
an,
DClass.IN,
ttl,
Type.NS,
5,
ttl,
Instant.now(),
Instant.now(),
5,
an,
"dummysig1".getBytes(StandardCharsets.UTF_8)),
new RRSIGRecord(
an,
DClass.IN,
ttl,
Type.SOA,
5,
ttl,
Instant.now(),
Instant.now(),
5,
an,
"dummysig2".getBytes(StandardCharsets.UTF_8))
};

Zone z = new Zone(an, records);
List<RRset> rrSets = StreamSupport.stream(z.spliterator(), false).collect(Collectors.toList());

// there should be 3 RRsets (soa, ns, dskey)
assertThat(rrSets).hasSize(3);

// assert that there is 1 SOA and it is signed
List<RRset> allSoaSets =
rrSets.stream().filter(r -> r.getType() == Type.SOA).collect(Collectors.toList());
assertThat(allSoaSets).hasSize(1);
RRset onlySoaSet = allSoaSets.get(0);
assertThat(onlySoaSet.rrs()).hasSize(1);
assertThat(onlySoaSet.sigs()).hasSize(1);

// assert that there are 2 nameservers and they are signed
List<RRset> allNsSets =
rrSets.stream().filter(r -> r.getType() == Type.NS).collect(Collectors.toList());
RRset onlyNsSet = allNsSets.get(0);
assertThat(onlyNsSet.rrs()).hasSize(2);
assertThat(onlyNsSet.sigs()).hasSize(1);

// assert that there is 1 dskey and it is not signed
List<RRset> allKeySets =
rrSets.stream().filter(r -> r.getType() == Type.DNSKEY).collect(Collectors.toList());
RRset onlyKeySet = allKeySets.get(0);
assertThat(onlyKeySet.rrs()).hasSize(1);
assertThat(onlyKeySet.sigs()).hasSize(0);
}

@Test
void canReplaceSoa() throws IOException {
Name an = Name.fromString("10.in-addr.arpa.");
Name host = Name.fromString("z.example.com.");
Name secondary = Name.fromString("y.example.com.");
Name admin = Name.fromString("dns-ops.example.com.");
Name admin2 = Name.fromString("dns-ops2.example.com.");

long ttl = 86400;
long serial = 2147483749L;
long refresh = 1800;
long retry = 900;
long expire = 691200;
long minimum = 10800;

Record soa =
new SOARecord(an, DClass.IN, ttl, host, admin, serial, refresh, retry, expire, minimum);
Record soaRrsig =
new RRSIGRecord(
an,
DClass.IN,
ttl,
Type.SOA,
5,
ttl,
Instant.now(),
Instant.now(),
5,
an,
"soa1Sig".getBytes(StandardCharsets.UTF_8));

// for otherSoa, admin is different than the original
Record otherSoa =
new SOARecord(an, DClass.IN, ttl, host, admin2, serial, refresh, retry, expire, minimum);
// for oatherSoaRrsig sig is different from the original
Record oatherSoaRrsig =
new RRSIGRecord(
an,
DClass.IN,
ttl,
Type.SOA,
5,
ttl,
Instant.now(),
Instant.now(),
5,
an,
"soa2sig".getBytes(StandardCharsets.UTF_8));

Record nsSig =
new RRSIGRecord(
an,
DClass.IN,
ttl,
Type.NS,
5,
ttl,
Instant.now(),
Instant.now(),
5,
an,
"nsSig".getBytes(StandardCharsets.UTF_8));

// dummy set of records for a dummy zone
Record[] records =
new Record[] {
soa,
new NSRecord(an, DClass.IN, ttl, host),
new NSRecord(an, DClass.IN, ttl, secondary),
new DNSKEYRecord(
an, DClass.IN, ttl, 256, 3, 5, "dummypublickey".getBytes(StandardCharsets.UTF_8)),
nsSig,
soaRrsig
};

Zone z = new Zone(an, records);
// replace Soa
z.addRecord(otherSoa);
// replace RRSig covering Soa
z.removeRecord(soaRrsig);
z.addRecord(oatherSoaRrsig);

List<RRset> rrSets = StreamSupport.stream(z.spliterator(), false).collect(Collectors.toList());

// there should be 3 RRsets (soa, ns, dskey)
assertThat(rrSets).hasSize(3);

// assert that there is 1 SOA and it is signed
List<RRset> allSoaSets =
rrSets.stream().filter(r -> r.getType() == Type.SOA).collect(Collectors.toList());
assertThat(allSoaSets).hasSize(1);
RRset onlySoaSet = allSoaSets.get(0);
assertThat(onlySoaSet.rrs()).hasSize(1);
assertThat(onlySoaSet.sigs()).hasSize(1);
// confirm that the SOA was replaced correctly
assertThat(((SOARecord) onlySoaSet.rrs().get(0)).getAdmin()).isEqualTo(admin2);
// confirm that the RRSig on the SOA was replaced correctly
assertThat((onlySoaSet.sigs().get(0)).getSignature())
.isEqualTo("soa2sig".getBytes(StandardCharsets.UTF_8));

// assert that there are 2 nameservers and they are signed
List<RRset> allNsSets =
rrSets.stream().filter(r -> r.getType() == Type.NS).collect(Collectors.toList());
RRset onlyNsSet = allNsSets.get(0);
assertThat(onlyNsSet.rrs()).hasSize(2);
assertThat(onlyNsSet.sigs()).hasSize(1);

// assert that there is 1 dskey and it is not signed
List<RRset> allKeySets =
rrSets.stream().filter(r -> r.getType() == Type.DNSKEY).collect(Collectors.toList());
RRset onlyKeySet = allKeySets.get(0);
assertThat(onlyKeySet.rrs()).hasSize(1);
assertThat(onlyKeySet.sigs()).hasSize(0);
}
}
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy