1ead1e536SRenato Botelho do Couto#!/usr/bin/env python3
24bf88880SDave Barach
34bf88880SDave Barachimport unittest
44bf88880SDave Barach
54bf88880SDave Barachfrom framework import VppTestCase, VppTestRunner
64bf88880SDave Barachfrom vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath
74bf88880SDave Barachfrom ipaddress import *
84bf88880SDave Barach
94bf88880SDave Barachimport scapy.compat
104bf88880SDave Barachfrom scapy.contrib.mpls import MPLS
114bf88880SDave Barachfrom scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
124bf88880SDave Barachfrom scapy.layers.l2 import Ether
134bf88880SDave Barachfrom scapy.packet import Raw
144bf88880SDave Barachfrom scapy.layers.dns import DNSRR, DNS, DNSQR
154bf88880SDave Barach
164bf88880SDave Barach
174bf88880SDave Barachclass TestDns(VppTestCase):
184bf88880SDave Barach    """ Dns Test Cases """
194bf88880SDave Barach
204bf88880SDave Barach    @classmethod
214bf88880SDave Barach    def setUpClass(cls):
224bf88880SDave Barach        super(TestDns, cls).setUpClass()
234bf88880SDave Barach
244bf88880SDave Barach    @classmethod
254bf88880SDave Barach    def tearDownClass(cls):
264bf88880SDave Barach        super(TestDns, cls).tearDownClass()
274bf88880SDave Barach
284bf88880SDave Barach    def setUp(self):
294bf88880SDave Barach        super(TestDns, self).setUp()
304bf88880SDave Barach
314bf88880SDave Barach        self.create_pg_interfaces(range(1))
324bf88880SDave Barach
334bf88880SDave Barach        for i in self.pg_interfaces:
344bf88880SDave Barach            i.admin_up()
354bf88880SDave Barach            i.config_ip4()
364bf88880SDave Barach            i.resolve_arp()
374bf88880SDave Barach
384bf88880SDave Barach    def tearDown(self):
394bf88880SDave Barach        super(TestDns, self).tearDown()
404bf88880SDave Barach
414bf88880SDave Barach    def create_stream(self, src_if):
424bf88880SDave Barach        """Create input packet stream for defined interface.
434bf88880SDave Barach
444bf88880SDave Barach        :param VppInterface src_if: Interface to create packet stream for.
454bf88880SDave Barach        """
464bf88880SDave Barach        good_request = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
474bf88880SDave Barach                        IP(src=src_if.remote_ip4) /
484bf88880SDave Barach                        UDP(sport=1234, dport=53) /
494bf88880SDave Barach                        DNS(rd=1, qd=DNSQR(qname="bozo.clown.org")))
504bf88880SDave Barach
514bf88880SDave Barach        bad_request = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
524bf88880SDave Barach                       IP(src=src_if.remote_ip4) /
534bf88880SDave Barach                       UDP(sport=1234, dport=53) /
544bf88880SDave Barach                       DNS(rd=1, qd=DNSQR(qname="no.clown.org")))
554bf88880SDave Barach        pkts = [good_request, bad_request]
564bf88880SDave Barach        return pkts
574bf88880SDave Barach
584bf88880SDave Barach    def verify_capture(self, dst_if, capture):
594bf88880SDave Barach        """Verify captured input packet stream for defined interface.
604bf88880SDave Barach
614bf88880SDave Barach        :param VppInterface dst_if: Interface to verify captured packet stream
624bf88880SDave Barach            for.
634bf88880SDave Barach        :param list capture: Captured packet stream.
644bf88880SDave Barach        """
654bf88880SDave Barach        self.logger.info("Verifying capture on interface %s" % dst_if.name)
664bf88880SDave Barach        for packet in capture:
674bf88880SDave Barach            dns = packet[DNS]
684bf88880SDave Barach            self.assertEqual(dns.an[0].rdata, '1.2.3.4')
694bf88880SDave Barach
704bf88880SDave Barach    def test_dns_unittest(self):
714bf88880SDave Barach        """ DNS Name Resolver Basic Functional Test """
724bf88880SDave Barach
734bf88880SDave Barach        # Set up an upstream name resolver. We won't actually go there
744bf88880SDave Barach        self.vapi.dns_name_server_add_del(
754bf88880SDave Barach            is_ip6=0, is_add=1, server_address=IPv4Address(u'8.8.8.8').packed)
764bf88880SDave Barach
774bf88880SDave Barach        # Enable name resolution
784bf88880SDave Barach        self.vapi.dns_enable_disable(enable=1)
794bf88880SDave Barach
804bf88880SDave Barach        # Manually add a static dns cache entry
814bf88880SDave Barach        self.logger.info(self.vapi.cli("dns cache add bozo.clown.org 1.2.3.4"))
824bf88880SDave Barach
834bf88880SDave Barach        # Test the binary API
8426ea1465Ssnaramre        rv = self.vapi.dns_resolve_name(name=b'bozo.clown.org')
854bf88880SDave Barach        self.assertEqual(rv.ip4_address, IPv4Address(u'1.2.3.4').packed)
864bf88880SDave Barach
874bf88880SDave Barach        # Configure 127.0.0.1/8 on the pg interface
884bf88880SDave Barach        self.vapi.sw_interface_add_del_address(
894bf88880SDave Barach            sw_if_index=self.pg0.sw_if_index,
90efd7bc2bSNeale Ranns            prefix="127.0.0.1/8")
914bf88880SDave Barach
924bf88880SDave Barach        # Send a couple of DNS request packets, one for bozo.clown.org
934bf88880SDave Barach        # and one for no.clown.org which won't resolve
944bf88880SDave Barach
954bf88880SDave Barach        pkts = self.create_stream(self.pg0)
964bf88880SDave Barach        self.pg0.add_stream(pkts)
974bf88880SDave Barach        self.pg_enable_capture(self.pg_interfaces)
984bf88880SDave Barach
994bf88880SDave Barach        self.pg_start()
1004bf88880SDave Barach        pkts = self.pg0.get_capture(1)
1014bf88880SDave Barach        self.verify_capture(self.pg0, pkts)
1024bf88880SDave Barach
1034bf88880SDave Barach        # Make sure that the cache contents are correct
1044bf88880SDave Barach        str = self.vapi.cli("show dns cache verbose")
1054bf88880SDave Barach        self.assertIn('1.2.3.4', str)
1064bf88880SDave Barach        self.assertIn('[P] no.clown.org:', str)
1074bf88880SDave Barach
1084bf88880SDave Barachif __name__ == '__main__':
1094bf88880SDave Barach    unittest.main(testRunner=VppTestRunner)
110