This is an automated email from the ASF dual-hosted git repository.

elsloo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-trafficcontrol.git

commit d47ce5918a9bff617cdb094ed5345b4682b29b87
Author: kapsharm <kapsh...@cisco.com>
AuthorDate: Wed Jun 21 09:20:33 2017 -0400

    Experimental support for Client Subnet in DNS Queries RFC7871
    
    (cherry picked from commit 34e122e932d409c24a26101149a8a50a3a1a1a28)
---
 .../traffic_router/core/dns/NameServer.java        |  52 ++++++-
 .../traffic_router/core/dns/NameServerTest.java    | 171 +++++++++++++++++++++
 2 files changed, 217 insertions(+), 6 deletions(-)

diff --git 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServer.java
 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServer.java
index 1bf3c2e..e8a0ab7 100644
--- 
a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServer.java
+++ 
b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServer.java
@@ -22,6 +22,7 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.log4j.Logger;
+import org.json.JSONObject;
 import org.xbill.DNS.DClass;
 import org.xbill.DNS.ExtendedFlags;
 import org.xbill.DNS.Flags;
@@ -36,7 +37,10 @@ import org.xbill.DNS.Section;
 import org.xbill.DNS.SetResponse;
 import org.xbill.DNS.Type;
 import org.xbill.DNS.Zone;
+import org.xbill.DNS.EDNSOption;
+import org.xbill.DNS.ClientSubnetOption;
 
+import com.comcast.cdn.traffic_control.traffic_router.core.cache.CacheRegister;
 import 
com.comcast.cdn.traffic_control.traffic_router.core.router.TrafficRouterManager;
 
 public class NameServer {
@@ -74,7 +78,7 @@ public class NameServer {
                return response;
        }
 
-       @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
+       @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity", 
"PMD.AvoidDeeplyNestedIfStmts"})
        private void addAnswers(final Message request, final Message response, 
final InetAddress clientAddress, final DNSAccessRecord.Builder builder) {
                final Record question = request.getQuestion();
 
@@ -82,9 +86,12 @@ public class NameServer {
                        final int qclass = question.getDClass();
                        final Name qname = question.getName();
                        final OPTRecord qopt = request.getOPT();
+                       List<EDNSOption> list = Collections.EMPTY_LIST;
                        boolean dnssecRequest = false;
                        int qtype = question.getType();
-
+                       final CacheRegister data = 
trafficRouterManager.getTrafficRouter().getCacheRegister();
+                       final JSONObject config = data.getConfig();
+                       final boolean ecsEnable = 
config.optBoolean("ecsEnable", false);
                        int flags = 0;
 
                        if ((qopt != null) && (qopt.getVersion() > 
MAX_SUPPORTED_EDNS_VERS)) {
@@ -108,13 +115,46 @@ public class NameServer {
                                qtype = Type.ANY;
                                flags |= FLAG_SIGONLY;
                        }
-
-                       lookup(qname, qtype, clientAddress, response, flags, 
dnssecRequest, builder);
-
+                       // Get list of options matching client subnet option 
code (8)
+                       if (qopt != null ){
+                               list = 
qopt.getOptions(EDNSOption.Code.CLIENT_SUBNET);
+                       }
+                       InetAddress ipaddr = null;
+                       int nmask = 0;
+                       if (ecsEnable) {
+                               for (final EDNSOption option : list) {
+                                       assert (option instanceof 
ClientSubnetOption);
+                                       // If there are multiple 
ClientSubnetOptions in the Option RR, then
+                                       // choose the one with longest source 
prefix. RFC 7871
+                                       if 
(((ClientSubnetOption)option).getSourceNetmask() > nmask) {
+                                               nmask = 
((ClientSubnetOption)option).getSourceNetmask();
+                                               ipaddr = 
((ClientSubnetOption)option).getAddress();
+                                       }
+                               }
+                       }
+                       if ((ipaddr!= null) && (ecsEnable)) {
+                               LOGGER.debug("DNS: Using Client IP Address from 
ECS Option" + ipaddr.getHostAddress() + "/" 
+                                               + nmask);
+                               lookup(qname, qtype, ipaddr, response, flags, 
dnssecRequest, builder);
+                       } else {
+                               lookup(qname, qtype, clientAddress, response, 
flags, dnssecRequest, builder);
+                       }
+                       
                        if (response.getHeader().getRcode() == Rcode.REFUSED) {
                                return;
                        }
-
+                       
+                       // Check if we had incoming ClientSubnetOption in 
Option RR, then we need
+                       // to return with the response, setting the scope 
subnet as well
+                       if ((nmask != 0) && (ecsEnable)) {      
+                               final ClientSubnetOption cso = new 
ClientSubnetOption(nmask, nmask, ipaddr);
+                               final List<ClientSubnetOption> csoList = new 
ArrayList<ClientSubnetOption>(1);
+                               csoList.add(cso);       
+                               // OptRecord Arguments: payloadSize = 1280, 
xrcode = 0, version=0, flags=0, option List
+                               final OPTRecord opt = new OPTRecord(1280, 0, 0, 
0, csoList);
+                               response.addRecord(opt, Section.ADDITIONAL);
+                       }
+               
                        if (qopt != null && flags == FLAG_DNSSECOK) {
                                final int optflags = ExtendedFlags.DO;
                                final OPTRecord opt = new OPTRecord(1280, 
(byte) 0, (byte) 0, optflags);
diff --git 
a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServerTest.java
 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServerTest.java
new file mode 100644
index 0000000..9ce13ac
--- /dev/null
+++ 
b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/dns/NameServerTest.java
@@ -0,0 +1,171 @@
+package com.comcast.cdn.traffic_control.traffic_router.core.dns;
+
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.TrafficRouter;
+import 
com.comcast.cdn.traffic_control.traffic_router.core.router.TrafficRouterManager;
+import com.comcast.cdn.traffic_control.traffic_router.core.cache.CacheRegister;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.DNSAccessRecord;
+import com.comcast.cdn.traffic_control.traffic_router.core.dns.NameServer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.xbill.DNS.*;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.powermock.api.mockito.PowerMockito.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.json.JSONObject;
+
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Header.class, NameServer.class, TrafficRouterManager.class, 
TrafficRouter.class, CacheRegister.class})
+public class NameServerTest {
+    private NameServer nameServer;
+    private InetAddress client;
+    private TrafficRouterManager trafficRouterManager;
+    private TrafficRouter trafficRouter;
+    private Record ar;
+    private NSRecord ns;
+    
+    @Before
+    public void before() throws Exception {
+
+        client = Inet4Address.getByAddress(new byte[]{(byte) 192, (byte) 168, 
23, 45});
+        nameServer = new NameServer(); 
+        trafficRouterManager = mock(TrafficRouterManager.class);
+        trafficRouter = mock(TrafficRouter.class);
+        CacheRegister cacheRegister = mock(CacheRegister.class);
+        doReturn(cacheRegister).when(trafficRouter).getCacheRegister();
+        JSONObject js = new JSONObject().put("ecsEnable", true);
+        when(cacheRegister.getConfig()).thenReturn(js);
+        
+        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.");
+           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);
+    }
+
+    @Test
+    public void TestARecordQueryWithClientSubnetOption() throws Exception {
+        
+        Name name = Name.fromString("host1.example.com.");
+        Record question = Record.newRecord(name, Type.A, DClass.IN, 12345L);
+        Message query = Message.newQuery(question);
+       
+        //Add opt record, with client subnet option.
+        int nmask = 28;
+        InetAddress ipaddr = Inet4Address.getByName("192.168.33.0");
+        ClientSubnetOption cso = new ClientSubnetOption(nmask, ipaddr);
+        List<ClientSubnetOption> cso_list = new 
ArrayList<ClientSubnetOption>(1);
+        cso_list.add(cso);     
+        OPTRecord opt = new OPTRecord(1280, 0, 0, 0, cso_list);
+        query.addRecord(opt, Section.ADDITIONAL);
+        
+       
+           // Add ARecord Entry in the zone
+        InetAddress resolvedAddress = Inet4Address.getByName("192.168.8.9");
+        Record answer = new ARecord(name, DClass.IN, 12345L, resolvedAddress);
+        Record[] records = new Record[] {ar, ns, answer};
+        
+        Name m_an = Name.fromString("dns1.example.com.");
+        Zone zone = new Zone(m_an, records);
+       
+        DNSAccessRecord.Builder builder = new DNSAccessRecord.Builder(1L, 
client);
+
+        nameServer.setTrafficRouterManager(trafficRouterManager);
+       
+        // Following is needed to mock this call: zone = 
trafficRouterManager.getTrafficRouter().getZone(qname, qtype, clientAddress, 
dnssecRequest, builder);
+        
when(trafficRouterManager.getTrafficRouter()).thenReturn(trafficRouter);
+        when(trafficRouter.getZone(any(Name.class), any(int.class), 
eq(ipaddr), any(boolean.class), 
any(DNSAccessRecord.Builder.class))).thenReturn(zone);
+
+        // The function call under test:
+        Message res = nameServer.query(query, client, builder);
+
+        
+        //Verification of response
+        OPTRecord qopt = res.getOPT();
+        List<EDNSOption> list = Collections.EMPTY_LIST;
+        list = qopt.getOptions(EDNSOption.Code.CLIENT_SUBNET);
+        assert (list != Collections.EMPTY_LIST);
+        ClientSubnetOption option = (ClientSubnetOption)list.get(0);
+        assertThat(nmask, equalTo(option.getSourceNetmask()));
+        assertThat(nmask, equalTo(option.getScopeNetmask()));
+        assertThat(ipaddr, equalTo(option.getAddress()));
+    }
+    
+    @Test
+    public void TestARecordQueryWithMultipleClientSubnetOption() throws 
Exception {
+        
+        Name name = Name.fromString("host1.example.com.");
+        Record question = Record.newRecord(name, Type.A, DClass.IN, 12345L);
+        Message query = Message.newQuery(question);
+       
+        //Add opt record, with multiple client subnet option.
+        int nmask1 = 16;
+        int nmask2 = 24;
+        InetAddress ipaddr1 = Inet4Address.getByName("192.168.0.0");
+        InetAddress ipaddr2 = Inet4Address.getByName("192.168.33.0");
+        ClientSubnetOption cso1 = new ClientSubnetOption(nmask1, ipaddr1);
+        ClientSubnetOption cso2 = new ClientSubnetOption(nmask2, ipaddr2);
+        List<ClientSubnetOption> cso_list = new 
ArrayList<ClientSubnetOption>(1);
+        cso_list.add(cso1);
+        cso_list.add(cso2);
+        final OPTRecord opt = new OPTRecord(1280, 0, 0, 0, cso_list);
+        query.addRecord(opt, Section.ADDITIONAL);
+        
+       
+           // Add ARecord Entry in the zone
+        InetAddress resolvedAddress = Inet4Address.getByName("192.168.8.9");
+        Record answer = new ARecord(name, DClass.IN, 12345L, resolvedAddress);
+        Record[] records = new Record[] {ar, ns, answer};
+        
+        Name m_an = Name.fromString("dns1.example.com.");
+        Zone zone = new Zone(m_an, records);
+       
+        DNSAccessRecord.Builder builder = new DNSAccessRecord.Builder(1L, 
client);
+
+        nameServer.setTrafficRouterManager(trafficRouterManager);
+       
+        // Following is needed to mock this call: zone = 
trafficRouterManager.getTrafficRouter().getZone(qname, qtype, clientAddress, 
dnssecRequest, builder);
+        
when(trafficRouterManager.getTrafficRouter()).thenReturn(trafficRouter);
+        when(trafficRouter.getZone(any(Name.class), any(int.class), 
eq(ipaddr2), any(boolean.class), 
any(DNSAccessRecord.Builder.class))).thenReturn(zone);
+
+        // The function call under test:
+        Message res = nameServer.query(query, client, builder);
+
+        
+        //Verification of response
+        OPTRecord qopt = res.getOPT();
+        List<EDNSOption> list = Collections.EMPTY_LIST;
+        list = qopt.getOptions(EDNSOption.Code.CLIENT_SUBNET);
+        assert (list != Collections.EMPTY_LIST);
+        ClientSubnetOption option = (ClientSubnetOption)list.get(0);
+        assertThat(1, equalTo(list.size()));
+        assertThat(nmask2, equalTo(option.getSourceNetmask()));
+        assertThat(nmask2, equalTo(option.getScopeNetmask()));
+        assertThat(ipaddr2, equalTo(option.getAddress()));
+    }
+   
+}

-- 
To stop receiving notification emails like this one, please contact
els...@apache.org.

Reply via email to