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