xref: /aosp_15_r20/external/autotest/client/cros/cellular/net_interface.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Lifrom __future__ import absolute_import
7*9c5db199SXin Lifrom __future__ import division
8*9c5db199SXin Lifrom __future__ import print_function
9*9c5db199SXin Li
10*9c5db199SXin Liimport os
11*9c5db199SXin Liimport six
12*9c5db199SXin Liimport six.moves.urllib.parse
13*9c5db199SXin Li
14*9c5db199SXin Liimport common
15*9c5db199SXin Lifrom autotest_lib.client.bin import utils
16*9c5db199SXin Lifrom autotest_lib.client.common_lib import error
17*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import virtual_ethernet_pair
18*9c5db199SXin Lifrom autotest_lib.client.cros import network, network_chroot
19*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import test_endpoint
20*9c5db199SXin Li
21*9c5db199SXin Liclass PseudoNetInterface(object):
22*9c5db199SXin Li    """
23*9c5db199SXin Li    PseudoNetInterface provides a pseudo modem network interface.  This
24*9c5db199SXin Li    network interface is one end of a virtual Ethernet pair.  The other end
25*9c5db199SXin Li    of the virtual Ethernet pair is connected to a minijail that provides DHCP
26*9c5db199SXin Li    and DNS services.  Also in the minijail is a test endpoint (web server)
27*9c5db199SXin Li    that is needed to pass portal detection and perform data transfer tests.
28*9c5db199SXin Li
29*9c5db199SXin Li    """
30*9c5db199SXin Li    ARP_ANNOUNCE_CONF = '/proc/sys/net/ipv4/conf/all/arp_announce'
31*9c5db199SXin Li    IFACE_NAME = 'pseudomodem0'
32*9c5db199SXin Li    PEER_IFACE_NAME = IFACE_NAME + 'p'
33*9c5db199SXin Li    IFACE_IP_BASE = '192.168.7'
34*9c5db199SXin Li    IFACE_NETWORK_PREFIX = 24
35*9c5db199SXin Li    NETWORK_CHROOT_CONFIG = {
36*9c5db199SXin Li            'etc/passwd' :
37*9c5db199SXin Li                    'root:x:0:0:root:/root:/bin/bash\n'
38*9c5db199SXin Li                    'nobody:x:65534:65534:nobody:/dev/null:/bin/false\n',
39*9c5db199SXin Li            'etc/group' :
40*9c5db199SXin Li                    'nobody::65534:\n'}
41*9c5db199SXin Li    SHILL_PORTAL_DETECTION_SERVER = 'www.gstatic.com'
42*9c5db199SXin Li
43*9c5db199SXin Li    def __init__(self):
44*9c5db199SXin Li        self._arp_announce = 0
45*9c5db199SXin Li        peer_ip = self.IFACE_IP_BASE + '.1'
46*9c5db199SXin Li        peer_interface_ip = peer_ip + '/' + str(self.IFACE_NETWORK_PREFIX)
47*9c5db199SXin Li        self.vif = virtual_ethernet_pair.VirtualEthernetPair(
48*9c5db199SXin Li                interface_name=self.IFACE_NAME,
49*9c5db199SXin Li                peer_interface_name=self.PEER_IFACE_NAME,
50*9c5db199SXin Li                interface_ip=None,
51*9c5db199SXin Li                peer_interface_ip=peer_interface_ip,
52*9c5db199SXin Li                ignore_shutdown_errors=True)
53*9c5db199SXin Li        self.chroot = network_chroot.NetworkChroot(self.PEER_IFACE_NAME,
54*9c5db199SXin Li                                                   peer_ip,
55*9c5db199SXin Li                                                   self.IFACE_NETWORK_PREFIX)
56*9c5db199SXin Li        self.chroot.add_config_templates(self.NETWORK_CHROOT_CONFIG)
57*9c5db199SXin Li        self.chroot.add_startup_command(
58*9c5db199SXin Li                'iptables -I INPUT -p udp --dport 67 -j ACCEPT')
59*9c5db199SXin Li        self.chroot.add_startup_command(
60*9c5db199SXin Li                'iptables -I INPUT -p tcp --dport 80 -j ACCEPT')
61*9c5db199SXin Li        self._dnsmasq_command = self._GetDnsmasqCommand(peer_ip)
62*9c5db199SXin Li        self.chroot.add_startup_command(self._dnsmasq_command)
63*9c5db199SXin Li        self._test_endpoint_command = self._GetTestEndpointCommand()
64*9c5db199SXin Li        self.chroot.add_startup_command(self._test_endpoint_command)
65*9c5db199SXin Li
66*9c5db199SXin Li    @staticmethod
67*9c5db199SXin Li    def _GetDnsmasqCommand(peer_ip):
68*9c5db199SXin Li        dnsmasq_command = (
69*9c5db199SXin Li                'dnsmasq '
70*9c5db199SXin Li                '--dhcp-leasefile=/tmp/dnsmasq.leases '
71*9c5db199SXin Li                '--dhcp-range=%s.2,%s.254 '
72*9c5db199SXin Li                '--no-resolv '
73*9c5db199SXin Li                '--no-hosts ' %
74*9c5db199SXin Li                (PseudoNetInterface.IFACE_IP_BASE,
75*9c5db199SXin Li                 PseudoNetInterface.IFACE_IP_BASE))
76*9c5db199SXin Li        test_fetch_url_host = \
77*9c5db199SXin Li                six.moves.urllib.parse.urlparse(network.FETCH_URL_PATTERN_FOR_TEST).netloc
78*9c5db199SXin Li        dns_lookup_table = {
79*9c5db199SXin Li                PseudoNetInterface.SHILL_PORTAL_DETECTION_SERVER: peer_ip,
80*9c5db199SXin Li                test_fetch_url_host: peer_ip }
81*9c5db199SXin Li        for host, ip in six.iteritems(dns_lookup_table):
82*9c5db199SXin Li            dnsmasq_command += '--address=/%s/%s ' % (host, ip)
83*9c5db199SXin Li        return dnsmasq_command
84*9c5db199SXin Li
85*9c5db199SXin Li    @staticmethod
86*9c5db199SXin Li    def _GetTestEndpointCommand():
87*9c5db199SXin Li        test_endpoint_path = os.path.abspath(test_endpoint.__file__)
88*9c5db199SXin Li        if test_endpoint_path.endswith('.pyc'):
89*9c5db199SXin Li            test_endpoint_path = test_endpoint_path[:-1]
90*9c5db199SXin Li        return test_endpoint_path
91*9c5db199SXin Li
92*9c5db199SXin Li    def _ChrootRunCmdIgnoreErrors(self, cmd):
93*9c5db199SXin Li        try:
94*9c5db199SXin Li            self.chroot.run(cmd)
95*9c5db199SXin Li        except error.CmdError:
96*9c5db199SXin Li            pass
97*9c5db199SXin Li
98*9c5db199SXin Li    def BringInterfaceUp(self):
99*9c5db199SXin Li        """
100*9c5db199SXin Li        Brings up the pseudo modem network interface.
101*9c5db199SXin Li
102*9c5db199SXin Li        """
103*9c5db199SXin Li        utils.run('sudo ip link set %s up' % self.IFACE_NAME)
104*9c5db199SXin Li
105*9c5db199SXin Li    def BringInterfaceDown(self):
106*9c5db199SXin Li        """
107*9c5db199SXin Li        Brings down the pseudo modem network interface.
108*9c5db199SXin Li
109*9c5db199SXin Li        """
110*9c5db199SXin Li        utils.run('sudo ip link set %s down' % self.IFACE_NAME);
111*9c5db199SXin Li
112*9c5db199SXin Li    def Setup(self):
113*9c5db199SXin Li        """
114*9c5db199SXin Li        Sets up the virtual Ethernet pair and starts dnsmasq.
115*9c5db199SXin Li
116*9c5db199SXin Li        """
117*9c5db199SXin Li        # Make sure ARP requests for the pseudo modem network addresses
118*9c5db199SXin Li        # go out the pseudo modem network interface.
119*9c5db199SXin Li        self._arp_announce = utils.system_output(
120*9c5db199SXin Li                'cat %s' % self.ARP_ANNOUNCE_CONF)
121*9c5db199SXin Li        utils.run('echo 1 > %s' % self.ARP_ANNOUNCE_CONF)
122*9c5db199SXin Li
123*9c5db199SXin Li        self.vif.setup()
124*9c5db199SXin Li        self.BringInterfaceDown()
125*9c5db199SXin Li        if not self.vif.is_healthy:
126*9c5db199SXin Li            raise Exception('Could not initialize virtual ethernet pair')
127*9c5db199SXin Li        self.chroot.startup()
128*9c5db199SXin Li
129*9c5db199SXin Li    def Teardown(self):
130*9c5db199SXin Li        """
131*9c5db199SXin Li        Stops dnsmasq and takes down the virtual Ethernet pair.
132*9c5db199SXin Li
133*9c5db199SXin Li        """
134*9c5db199SXin Li        self._ChrootRunCmdIgnoreErrors(['/bin/bash', '-c', '"pkill dnsmasq"'])
135*9c5db199SXin Li        self._ChrootRunCmdIgnoreErrors(['/bin/bash', '-c',
136*9c5db199SXin Li                                        '"pkill -f test_endpoint"'])
137*9c5db199SXin Li        self.vif.teardown()
138*9c5db199SXin Li        self.chroot.shutdown()
139*9c5db199SXin Li        utils.run('echo %s > %s' % (self._arp_announce, self.ARP_ANNOUNCE_CONF))
140*9c5db199SXin Li
141*9c5db199SXin Li    def Restart(self):
142*9c5db199SXin Li        """
143*9c5db199SXin Li        Restarts the configuration.
144*9c5db199SXin Li
145*9c5db199SXin Li        """
146*9c5db199SXin Li        self.Teardown()
147*9c5db199SXin Li        self.Setup()
148