Skip to content
This repository has been archived by the owner on Feb 6, 2022. It is now read-only.

Commit

Permalink
Merge pull request #16 from ibauersachs/update-unbound-files
Browse files Browse the repository at this point in the history
  • Loading branch information
ibauersachs authored May 14, 2019
2 parents c3843fa + 72b617f commit 05cb5d3
Show file tree
Hide file tree
Showing 139 changed files with 1,151 additions and 679 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,8 @@ public enum ResponseClassification {
CNAME_NODATA,

/** A response with CNAMES that points into the void. */
CNAME_NAMEERROR;
CNAME_NAMEERROR,

/** A referral, from cache with a nonRD query. */
REFERRAL;
}
43 changes: 42 additions & 1 deletion src/main/java/org/jitsi/dnssec/validator/ValUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,58 @@ public void init(Properties config) {
/**
* Given a response, classify ANSWER responses into a subtype.
*
* @param request The original query message.
* @param m The response to classify.
*
* @return A subtype ranging from UNKNOWN to NAMEERROR.
*/
public static ResponseClassification classifyResponse(SMessage m) {
public static ResponseClassification classifyResponse(Message request, SMessage m) {
// Normal Name Error's are easy to detect -- but don't mistake a CNAME
// chain ending in NXDOMAIN.
if (m.getRcode() == Rcode.NXDOMAIN && m.getCount(Section.ANSWER) == 0) {
return ResponseClassification.NAMEERROR;
}

// check for referral: nonRD query and it looks like a nodata
if (m.getCount(Section.ANSWER) == 0 && m.getRcode() != Rcode.NOERROR) {
// SOA record in auth indicates it is NODATA instead.
// All validation requiring NODATA messages have SOA in
// authority section.
// uses fact that answer section is empty
boolean sawNs = false;
for (RRset set : m.getSectionRRsets(Section.AUTHORITY)) {
if (set.getType() == Type.SOA) {
return ResponseClassification.NODATA;
}

if (set.getType() == Type.DS) {
return ResponseClassification.REFERRAL;
}

if (set.getType() == Type.NS) {
sawNs = true;
}
}

return sawNs
? ResponseClassification.REFERRAL
: ResponseClassification.NODATA;
}

// root referral where NS set is in the answer section
if (m.getSectionRRsets(Section.AUTHORITY).size() == 0
&& m.getSectionRRsets(Section.ANSWER).size() == 1
&& m.getRcode() == Rcode.NOERROR
&& m.getSectionRRsets(Section.ANSWER).get(0).getType() == Type.NS
&& !m.getSectionRRsets(Section.ANSWER).get(0).getName().equals(request.getQuestion().getName())) {
return ResponseClassification.REFERRAL;
}

// dump bad messages
if (m.getRcode() != Rcode.NOERROR && m.getRcode() != Rcode.NXDOMAIN) {
return ResponseClassification.UNKNOWN;
}

// Next is NODATA
if (m.getCount(Section.ANSWER) == 0) {
return ResponseClassification.NODATA;
Expand Down
44 changes: 42 additions & 2 deletions src/main/java/org/jitsi/dnssec/validator/ValidatingResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
Expand Down Expand Up @@ -227,6 +228,41 @@ public TrustAnchorStore getTrustAnchors() {
return this.trustAnchors;
}

/**
* For messages that are not referrals, if the chase reply contains an
* unsigned NS record in the authority section it could have been inserted
* by a (BIND) forwarder that thinks the zone is insecure, and that has an
* NS record without signatures in cache. Remove the NS record since the
* reply does not hinge on that record (in the authority section), but do
* not remove it if it removes the last record from the answer+authority
* sections.
*
* @param response: the chased reply, we have a key for this contents, so we
* should have signatures for these rrsets and not having
* signatures means it will be bogus.
*/
private void removeSpuriousAuthority(SMessage response) {
// if no answer and only 1 auth RRset, do not remove that one
if (response.getSectionRRsets(Section.ANSWER).size() == 0 && response.getSectionRRsets(Section.AUTHORITY).size() == 1) {
return;
}

// search authority section for unsigned NS records
Iterator<SRRset> authRrsetIterator = response.getSectionRRsets(Section.AUTHORITY).iterator();
while (authRrsetIterator.hasNext()) {
SRRset rrset = authRrsetIterator.next();
if (rrset.getType() == Type.NS) {
if (!rrset.sigs().hasNext()) {
logger.trace("Removing spurious unsigned NS record (likely inserted by forwarder) {}/{}/{}",
rrset.getName(),
Type.string(rrset.getType()),
DClass.string(rrset.getDClass()));
authRrsetIterator.remove();
}
}
}
}

/**
* Given a "postive" response -- a response that contains an answer to the
* question, and no CNAME chain, validate this response. This generally
Expand Down Expand Up @@ -797,7 +833,7 @@ private KeyEntry dsResponseToKE(SMessage response, Message request, SRRset keyRr
int qclass = request.getQuestion().getDClass();

SecurityStatus status;
ResponseClassification subtype = ValUtils.classifyResponse(response);
ResponseClassification subtype = ValUtils.classifyResponse(request, response);

KeyEntry bogusKE = KeyEntry.newBadKeyEntry(qname, qclass, DEFAULT_TA_BAD_KEY_TTL);
switch (subtype) {
Expand Down Expand Up @@ -1044,7 +1080,11 @@ private boolean processKeyValidate(SMessage response, Name signerName, KeyEntry
}

private SMessage processValidate(Message request, SMessage response) {
ResponseClassification subtype = ValUtils.classifyResponse(response);
ResponseClassification subtype = ValUtils.classifyResponse(request, response);
if (subtype != ResponseClassification.REFERRAL) {
this.removeSpuriousAuthority(response);
}

switch (subtype) {
case POSITIVE:
case CNAME:
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/jitsi/dnssec/unbound/rpl/RplParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ else if (state == ParseState.STEP_QUERY) {

private Record parseRecord(String line) throws IOException {
try {
Master ma = new Master(new ByteArrayInputStream(line.getBytes()), null, 3600);
Master ma = new Master(new ByteArrayInputStream(line.getBytes()), Name.root, 3600);
Record r = ma.nextRecord();
if (r.getType() == Type.RRSIG) {
RRSIGRecord rr = (RRSIGRecord)r;
Expand Down
55 changes: 7 additions & 48 deletions src/test/java/org/jitsi/dnssec/unbound/rpl/UnboundTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,25 +65,7 @@ public void runUnboundTest() throws ParseException, IOException {
config.put(ValUtils.DIGEST_HARDEN_DOWNGRADE, Boolean.toString(rpl.hardenAlgoDowngrade));

for (Message m : rpl.replays) {
add(stripAdditional(m));
for (RRset set : m.getSectionRRsets(Section.AUTHORITY)) {
if (set.getType() == Type.DS && set.sigs().hasNext() && Name.fromString("sub.example.com.").equals(set.getName())) {
Message additional = new Message();
additional.addRecord(Record.newRecord(set.getName(), set.getType(), set.getDClass()), Section.QUESTION);
Iterator<?> it = set.rrs();
while (it.hasNext()) {
additional.addRecord((Record)it.next(), Section.ANSWER);
}

it = set.sigs();
while (it.hasNext()) {
additional.addRecord((Record)it.next(), Section.ANSWER);
}

add(stripAdditional(additional));
break;
}
}
add(m);
}

// merge xNAME queries into one
Expand Down Expand Up @@ -151,7 +133,7 @@ else if (s.getType() == Type.DNAME) {

clear();
for (Message m : rpl.replays) {
add(stripAdditional(m));
add(m);
}

if (rpl.date != null) {
Expand Down Expand Up @@ -180,34 +162,6 @@ else if (s.getType() == Type.DNAME) {
}
}

private Message stripAdditional(Message m) {
if (m.getQuestion().getType() == Type.RRSIG) {
return m;
}

Message copy = new Message();
copy.setHeader(m.getHeader());
for (int i = 0; i < Section.ADDITIONAL; i++) {
for (RRset set : m.getSectionRRsets(i)) {
if (set.getType() == Type.NS && m.getQuestion().getType() != Type.NS) {
continue;
}

Iterator<?> rrs = set.rrs();
while (rrs.hasNext()) {
copy.addRecord((Record)rrs.next(), i);
}

Iterator<?> sigs = set.sigs();
while (sigs.hasNext()) {
copy.addRecord((Record)sigs.next(), i);
}
}
}

return copy;
}

private Name add(Message target, Message source) {
Name next = null;
target.getHeader().setRcode(source.getRcode());
Expand Down Expand Up @@ -849,6 +803,11 @@ public void val_secds_nosig() throws ParseException, IOException {
runUnboundTest();
}

@Test
public void val_spurious_ns() throws ParseException, IOException {
runUnboundTest();
}

@Test
public void val_stub_noroot() throws ParseException, IOException {
runUnboundTest();
Expand Down
8 changes: 4 additions & 4 deletions src/test/resources/unbound/val_adbit.rpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
fake-sha1: yes
trust-anchor-signaling: no
minimal-responses: no

stub-zone:
name: "."
Expand Down Expand Up @@ -138,10 +142,8 @@ SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
Expand All @@ -162,10 +164,8 @@ SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
SECTION AUTHORITY
example.com. IN NS ns.example.com.
example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
SECTION ADDITIONAL
ns.example.com. IN A 1.2.3.4
ENTRY_END
Expand Down
3 changes: 3 additions & 0 deletions src/test/resources/unbound/val_adcopy.rpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ server:
#trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
fake-sha1: yes
minimal-responses: no

stub-zone:
name: "."
Expand Down
5 changes: 4 additions & 1 deletion src/test/resources/unbound/val_anchor_nx.rpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ server:
trust-anchor: "sub.example.com. 3600 IN DS 30899 RSASHA1 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
fake-sha1: yes
trust-anchor-signaling: no

stub-zone:
name: "."
Expand Down Expand Up @@ -200,7 +203,7 @@ ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AD NXDOMAIN
REPLY QR RD RA AD DO NXDOMAIN
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
Expand Down
8 changes: 5 additions & 3 deletions src/test/resources/unbound/val_anchor_nx_nosig.rpl
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
; config options
; The island of trust is at example.com
server:
trust-anchor: "sub.example.com. 3600 IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3"
trust-anchor: "sub.example.com. 3600 IN DS 30899 RSASHA1 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
fake-sha1: yes

stub-zone:
name: "."
Expand Down Expand Up @@ -155,7 +157,7 @@ RANGE_BEGIN 0 100
ADDRESS 1.2.3.6

; response to DNSKEY priming query
; sub.example.com. 3600 IN DS 30899 5 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3
; sub.example.com. 3600 IN DS 30899 RSASHA1 1 f7ed618f24d5e5202927e1d27bc2e84a141cb4b3
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
Expand Down Expand Up @@ -199,7 +201,7 @@ ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
REPLY QR RD RA DO NXDOMAIN
SECTION QUESTION
www.sub.example.com. IN A
SECTION ANSWER
Expand Down
19 changes: 4 additions & 15 deletions src/test/resources/unbound/val_ans_dsent.rpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ server:
trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
val-override-date: "20070916134226"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: "no"
fake-sha1: yes
trust-anchor-signaling: no

stub-zone:
name: "."
Expand Down Expand Up @@ -138,20 +141,6 @@ example.com. 3600 IN RRSIG SOA 3 2 3600 20070926135752 200708291357
ENTRY_END

; response for delegation to sub zone.
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
0.0.194.example.com. IN DS
SECTION ANSWER
0.0.194.example.com. 3600 IN DS 30899 RSASHA1 1 aa46f0717075d9750ac3596c659a2e326b33c28c
0.0.194.example.com. 3600 IN RRSIG DS 3 5 3600 20070926135752 20070829135752 2854 example.com. MCwCFC9GIqtp/103hktw6bPpD83gr+0iAhQ8yev2yUaR9l64rYBUYTJqOoTKdw== ;{id = 2854}
SECTION AUTHORITY
SECTION ADDITIONAL
ns.sub.example.com. IN A 1.2.3.6
ENTRY_END

ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
Expand Down Expand Up @@ -245,7 +234,7 @@ ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AD NOERROR
REPLY QR RD RA AD DO NOERROR
SECTION QUESTION
328.0.0.194.example.com. IN A
SECTION ANSWER
Expand Down
Loading

0 comments on commit 05cb5d3

Please sign in to comment.