This is an automated email from the ASF dual-hosted git repository.
rawlin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new a663e7a TR should support aggressive NSEC queries (#6648)
a663e7a is described below
commit a663e7a36814e45e2ee8ffbf7b0c7aa6111a0494
Author: Srijeet Chatterjee <[email protected]>
AuthorDate: Fri Apr 1 13:01:09 2022 -0600
TR should support aggressive NSEC queries (#6648)
* wip
* TR should support aggressive NSEC queries
* code review fix
---
CHANGELOG.md | 1 +
.../traffic_router/core/dns/ZoneManager.java | 36 ++++++-
.../core/dns/ZoneManagerUnitTest.java | 110 ++++++++++++++++++++-
3 files changed, 138 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b65e77b..ecd2dbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- [#6590](https://github.com/apache/trafficcontrol/pull/6590) Python client:
Corrected parameter name in decorator for get\_parameters\_by\_profile\_id
- [#6368](https://github.com/apache/trafficcontrol/pull/6368) Fixed validation
response message from `/acme_accounts`
- [#6603](https://github.com/apache/trafficcontrol/issues/6603) Fixed users
with "admin" "Priv Level" not having Permission to view or delete DNSSEC keys.
+- Fixed Traffic Router to handle aggressive NSEC correctly.
- [#6626](https://github.com/apache/trafficcontrol/pull/6626) Fixed t3c
Capabilities request failure issue which could result in malformed config.
- [#6370](https://github.com/apache/trafficcontrol/pull/6370) Fixed docs for
`POST` and response code for `PUT` to `/acme_accounts` endpoint
- Only `operations` and `admin` roles should have the
`DELIVERY-SERVICE:UPDATE` permission.
diff --git
a/traffic_router/core/src/main/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManager.java
b/traffic_router/core/src/main/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManager.java
index 149c7fd..d1a2c9a 100644
---
a/traffic_router/core/src/main/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManager.java
+++
b/traffic_router/core/src/main/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManager.java
@@ -940,7 +940,7 @@ public class ZoneManager extends Resolver {
final DNSRouteResult result =
trafficRouter.route(request, track);
if (result != null) {
- final Zone dynamicZone =
fillDynamicZone(dynamicZoneCache, staticZone, request, result);
+ final Zone dynamicZone =
fillDynamicZone(getDynamicZoneCache(), staticZone, request, result);
track.setResultCode(dynamicZone,
request.getName(), request.getQueryType());
if (result.getDeliveryService() == null) {
builder.deliveryServiceXmlIds(null);
@@ -972,16 +972,23 @@ public class ZoneManager extends Resolver {
try {
boolean nsSeen = false;
final List<Record> records = new ArrayList<>();
-
+ String dsRoutingName = null;
+ boolean routingNameNSECSeen = false;
for (final InetRecord address : result.getAddresses()) {
final DeliveryService ds =
result.getDeliveryService();
Name name = request.getName();
+ if (ds != null && ds.getRoutingName() != null) {
+ dsRoutingName = ds.getRoutingName();
+ }
if (address.getType() == Type.NS) {
name = staticZone.getOrigin();
} else if (ds != null && (address.getType() ==
Type.A || address.getType() == Type.AAAA)) {
final String routingName =
ds.getRoutingName();
name = new Name(routingName,
staticZone.getOrigin()); // routingname.ds.cdn.tld
+ } else if (ds != null && address.getType() ==
Type.NSEC && dsRoutingName != null &&
+ address.getTarget().equals(new
Name(dsRoutingName, staticZone.getOrigin()).toString())) {
+ routingNameNSECSeen = true;
}
final Record record = createRecord(name,
address);
@@ -989,7 +996,6 @@ public class ZoneManager extends Resolver {
if (record != null) {
records.add(record);
}
-
if (record instanceof NSRecord) {
nsSeen = true;
}
@@ -1009,7 +1015,20 @@ public class ZoneManager extends Resolver {
continue;
}
- records.add(r);
+ if (r.getType() == Type.NSEC &&
r.getName().toString().equals(staticZone.getOrigin().toString()) &&
dsRoutingName != null) {
+ final Name dsFQDN = new
Name(dsRoutingName, staticZone.getOrigin());
+ if (r instanceof NSECRecord) {
+ final NSECRecord
removeRec = new NSECRecord(dsFQDN, r.getDClass(), r.getTTL(), ((NSECRecord)
r).getNext(), ((NSECRecord) r).getTypes());
+ if
(dsFQDN.compareTo(removeRec.getNext()) < 0 && !routingNameNSECSeen) {
+
records.add(removeRec);
+
routingNameNSECSeen = true;
+ } else {
+ records.add(r);
+ }
+ }
+ } else {
+ records.add(r);
+ }
}
}
@@ -1020,7 +1039,7 @@ public class ZoneManager extends Resolver {
}
try {
- final ZoneKey zoneKey =
signatureManager.generateDynamicZoneKey(staticZone.getOrigin(), records,
request.isDnssec());
+ final ZoneKey zoneKey =
getSignatureManager().generateDynamicZoneKey(staticZone.getOrigin(), records,
request.isDnssec());
final Zone zone = dzc.get(zoneKey);
return zone;
} catch (ExecutionException e) {
@@ -1199,4 +1218,11 @@ public class ZoneManager extends Resolver {
public CacheStats getDynamicCacheStats() {
return dynamicZoneCache.stats();
}
+
+ public static SignatureManager getSignatureManager() {
+ return signatureManager;
+ }
+ public static LoadingCache<ZoneKey, Zone> getDynamicZoneCache() {
+ return dynamicZoneCache;
+ }
}
diff --git
a/traffic_router/core/src/test/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManagerUnitTest.java
b/traffic_router/core/src/test/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManagerUnitTest.java
index 69cca2f..5445622 100644
---
a/traffic_router/core/src/test/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManagerUnitTest.java
+++
b/traffic_router/core/src/test/java/org/apache/traffic_control/traffic_router/core/dns/ZoneManagerUnitTest.java
@@ -15,7 +15,17 @@
package org.apache.traffic_control.traffic_router.core.dns;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import org.apache.traffic_control.traffic_router.core.ds.DeliveryService;
import org.apache.traffic_control.traffic_router.core.edge.CacheRegister;
+import org.apache.traffic_control.traffic_router.core.edge.InetRecord;
+import org.apache.traffic_control.traffic_router.core.request.DNSRequest;
+import org.apache.traffic_control.traffic_router.core.router.DNSRouteResult;
import org.apache.traffic_control.traffic_router.core.router.StatTracker;
import
org.apache.traffic_control.traffic_router.core.router.StatTracker.Track.ResultType;
import
org.apache.traffic_control.traffic_router.core.router.TrafficRouterManager;
@@ -24,6 +34,7 @@ import
org.apache.traffic_control.traffic_router.core.router.TrafficRouter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
@@ -38,8 +49,11 @@ import org.xbill.DNS.SOARecord;
import org.xbill.DNS.SetResponse;
import org.xbill.DNS.Type;
import org.xbill.DNS.Zone;
+import org.xbill.DNS.NSRecord;
+import org.xbill.DNS.CNAMERecord;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -57,18 +71,20 @@ import static
org.powermock.api.mockito.PowerMockito.whenNew;
@PowerMockIgnore("javax.management.*")
public class ZoneManagerUnitTest {
ZoneManager zoneManager;
-
+ TrafficRouter trafficRouter;
+ SignatureManager signatureManager;
+ CacheRegister cacheRegister;
@Before
public void before() throws Exception {
- TrafficRouter trafficRouter = mock(TrafficRouter.class);
- CacheRegister cacheRegister = mock(CacheRegister.class);
+ trafficRouter = mock(TrafficRouter.class);
+ cacheRegister = mock(CacheRegister.class);
when(trafficRouter.getCacheRegister()).thenReturn(cacheRegister);
PowerMockito.spy(ZoneManager.class);
PowerMockito.stub(PowerMockito.method(ZoneManager.class,
"initTopLevelDomain")).toReturn(null);
PowerMockito.stub(PowerMockito.method(ZoneManager.class,
"initZoneCache")).toReturn(null);
- SignatureManager signatureManager =
PowerMockito.mock(SignatureManager.class);
+ signatureManager = PowerMockito.mock(SignatureManager.class);
whenNew(SignatureManager.class).withArguments(any(ZoneManager.class),
any(CacheRegister.class), any(TrafficOpsUtils.class),
any(TrafficRouterManager.class)).thenReturn(signatureManager);
zoneManager = spy(new ZoneManager(trafficRouter, new StatTracker(),
null, mock(TrafficRouterManager.class)));
@@ -99,6 +115,92 @@ public class ZoneManagerUnitTest {
}
@Test
+ public void itGetsCorrectNSECRecordFromStaticAndDynamicZones() throws
Exception {
+
+ final Name qname = Name.fromString("dns1.example.com.");
+ final InetAddress client = InetAddress.getByName("192.168.56.78");
+
+ DNSAccessRecord.Builder builder = new DNSAccessRecord.Builder(1L,
client);
+ builder = spy(builder);
+
+ Name m_an, m_host, m_admin;
+ m_an = Name.fromString("dns1.example.com.");
+ m_host = Name.fromString("dns1.example.com.");
+ m_admin = Name.fromString("admin.example.com.");
+ Record ar;
+ NSRecord ns;
+ NSECRecord nsec;
+ ar = new SOARecord(m_an, DClass.IN, 0x13A8,
+ m_host, m_admin, 0xABCDEF12L, 0xCDEF1234L,
+ 0xEF123456L, 0x12345678L, 0x3456789AL);
+
+ ns = new NSRecord(m_an, DClass.IN, 12345L, m_an);
+ nsec = new NSECRecord(m_an, DClass.IN, 12345L, new
Name("foobar.dns1.example.com."), new int[]{1});
+ Record[] records = new Record[] {ar, ns, nsec};
+ m_an = Name.fromString("dns1.example.com.");
+ Zone zone = new Zone(m_an, records);
+ // static zone
+ doReturn(zone).when(zoneManager).getZone(qname, Type.NSEC);
+
+ DNSRouteResult dnsRouteResult = new DNSRouteResult();
+ ObjectNode node = JsonNodeFactory.instance.objectNode();
+ ArrayNode domainNode = node.putArray("domains");
+ domainNode.add("example.com");
+ node.put("routingName","edge");
+ node.put("coverageZoneOnly", false);
+ DeliveryService ds1 = new DeliveryService("ds1", node);
+
+
+ dnsRouteResult.setDeliveryService(ds1);
+ InetRecord address = new InetRecord("cdn-tr.dns1.example.com.",
12345L);
+ List<InetRecord> list = new ArrayList<>();
+ list.add(address);
+ dnsRouteResult.setAddresses(list);
+
+ Record cnameRecord = new CNAMERecord(new Name("dns1.example.com."),
DClass.IN, 12345L, new Name("cdn-tr.dns1.example.com."));
+ Record nsecRecord = new NSECRecord(new Name("edge.dns1.example.com."),
DClass.IN, 12345L, new Name("foobar.dns1.example.com."), new int[]{1});
+
+ // Add records for dynamic zones
+ Record[] recordArray = new Record[]{cnameRecord, ar, nsecRecord, ns};
+ List<Record> recordList = Arrays.asList(recordArray);
+ Zone dynamicZone = new Zone(new Name("dns1.example.com."),
recordArray);
+
+ CacheLoader<ZoneKey, Zone> loader;
+ loader = new CacheLoader<>() {
+ @Override
+ public Zone load(ZoneKey zoneKey) {
+ return dynamicZone;
+ }
+
+ };
+ loader.load(new ZoneKey(Name.fromString("dns1.example.com."),
Arrays.asList(records)));
+ LoadingCache<ZoneKey, Zone> dynamicZoneCache =
CacheBuilder.newBuilder().build(loader);
+
+ // stub calls for signatureManager, dynamicZoneCache and
generateDynamicZoneKey
+ when(ZoneManager.getDynamicZoneCache()).thenReturn(dynamicZoneCache);
+ ZoneKey zk = new ZoneKey(Name.fromString("dns1.example.com."),
recordList);
+ dynamicZoneCache.put(zk, dynamicZone);
+
+ when(ZoneManager.getSignatureManager()).thenReturn(signatureManager);
+ Answer<ZoneKey> currentTimeAnswer = invocation -> zk;
+
+ when(ZoneManager.getSignatureManager().generateDynamicZoneKey(
+ eq(Name.fromString("dns1.example.com.")),
+ anyList(),
+ eq(true))).
+ then(currentTimeAnswer);
+ when(trafficRouter.isEdgeDNSRouting()).thenReturn(true);
+ when(trafficRouter.route(any(DNSRequest.class),
any(StatTracker.Track.class))).thenReturn(dnsRouteResult);
+ Zone resultZone = zoneManager.getZone(qname, Type.NSEC, client, true,
builder);
+ // make sure the function gets called with the correct records as
expected
+ verify(ZoneManager.getSignatureManager()).generateDynamicZoneKey(
eq(Name.fromString("dns1.example.com.")),
+ argThat(t -> t.containsAll(Arrays.asList(nsecRecord, ns, ar))),
+ eq(true));
+ SetResponse setResponse = resultZone.findRecords(new
Name(ds1.getRoutingName() + "." + "dns1.example.com."), Type.NSEC);
+ assertThat(setResponse.isNXDOMAIN(), equalTo(false));
+ }
+
+ @Test
public void testZonesAreEqual() throws java.net.UnknownHostException,
org.xbill.DNS.TextParseException {
class TestCase {
String reason;