1#!/usr/bin/env python3 2# 3# Copyright (c) 2023, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29import unittest 30 31import config 32import thread_cert 33 34import ipaddress 35import shlex 36 37# Test description: 38# This test verifies forwarding DNS queries sent by 'Router' by using 39# a record resolved by BIND9 server. 40# 41# Topology: 42# ----------------(eth)-------------------- 43# | | 44# BR (Leader) DNS SERVER 45# | 46# ROUTER 47# 48 49BR = 1 50ROUTER = 2 51DNS_SERVER = 3 52 53TEST_DOMAIN = 'test.domain' 54TEST_DOMAIN_IP6_ADDRESSES = {'2001:db8::1'} 55 56TEST_DOMAIN_BIND_CONF = f''' 57zone "{TEST_DOMAIN}" {{ type master; file "/etc/bind/db.test.domain"; }}; 58''' 59 60TEST_DOMAIN_BIND_ZONE = f''' 61$TTL 24h 62@ IN SOA {TEST_DOMAIN} test.{TEST_DOMAIN}. ( 20230330 86400 300 604800 3600 ) 63@ IN NS {TEST_DOMAIN}. 64''' + '\n'.join(f'@ IN AAAA {addr}' for addr in TEST_DOMAIN_IP6_ADDRESSES) 65 66 67class UpstreamDns(thread_cert.TestCase): 68 USE_MESSAGE_FACTORY = False 69 70 TOPOLOGY = { 71 BR: { 72 'name': 'BR', 73 'is_otbr': True, 74 'version': '1.4', 75 }, 76 ROUTER: { 77 'name': 'Router', 78 'version': '1.4', 79 }, 80 DNS_SERVER: { 81 'name': 'DNS Server', 82 'is_host': True 83 }, 84 } 85 86 def test(self): 87 br = self.nodes[BR] 88 router = self.nodes[ROUTER] 89 dns_server = self.nodes[DNS_SERVER] 90 91 self._start_dns_server(dns_server) 92 dns_server_addr = dns_server.get_ether_addrs(ipv4=True, ipv6=False)[0] 93 94 # Disable the bind9 service on the BR otherwise bind9 may respond to Thread devices' DNS queries 95 br.bash('service bind9 stop') 96 97 # Update BR's /etc/resolv.conf and force BR to reload it 98 br.bash(shlex.join(['echo', 'nameserver ' + dns_server_addr]) + ' > /etc/resolv.conf') 99 br.stop_otbr_service() 100 br.start_otbr_service() 101 102 br.start() 103 self.simulator.go(config.LEADER_STARTUP_DELAY) 104 self.assertEqual('leader', br.get_state()) 105 106 # When feature flag is enabled, NAT64 might be disabled by default. So 107 # ensure NAT64 is enabled here. 108 br.nat64_set_enabled(True) 109 br.srp_server_set_enabled(True) 110 111 router.start() 112 self.simulator.go(config.ROUTER_STARTUP_DELAY) 113 self.assertEqual('router', router.get_state()) 114 115 self.simulator.go(10) 116 router.srp_client_enable_auto_start_mode() 117 118 # verify the server can forward the DNS query to upstream server. 119 self._verify_upstream_dns(br, router) 120 121 def _verify_upstream_dns(self, br, ed): 122 upstream_dns_enabled = br.dns_upstream_query_state 123 if not upstream_dns_enabled: 124 br.dns_upstream_query_state = True 125 self.assertTrue(br.dns_upstream_query_state) 126 127 resolved_names = ed.dns_resolve(TEST_DOMAIN) 128 self.assertEqual(len(resolved_names), len(TEST_DOMAIN_IP6_ADDRESSES)) 129 for record in resolved_names: 130 self.assertIn(ipaddress.IPv6Address(record[0]).compressed, TEST_DOMAIN_IP6_ADDRESSES) 131 132 def _start_dns_server(self, dns_server): 133 dns_server.start(start_radvd=False) 134 dns_server.bash('service bind9 stop') 135 136 dns_server.bash(shlex.join(['echo', TEST_DOMAIN_BIND_CONF]) + ' >> /etc/bind/named.conf.local') 137 dns_server.bash(shlex.join(['echo', TEST_DOMAIN_BIND_ZONE]) + ' >> /etc/bind/db.test.domain') 138 139 dns_server.bash('service bind9 start') 140 141 142if __name__ == '__main__': 143 unittest.main() 144