144 lines
5.3 KiB
Python
144 lines
5.3 KiB
Python
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import os
|
|
import urlparse
|
|
|
|
|
|
import common
|
|
from autotest_lib.client.bin import utils
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.common_lib.cros import virtual_ethernet_pair
|
|
from autotest_lib.client.cros import network, network_chroot
|
|
from autotest_lib.client.cros.cellular import test_endpoint
|
|
|
|
class PseudoNetInterface(object):
|
|
"""
|
|
PseudoNetInterface provides a pseudo modem network interface. This
|
|
network interface is one end of a virtual Ethernet pair. The other end
|
|
of the virtual Ethernet pair is connected to a minijail that provides DHCP
|
|
and DNS services. Also in the minijail is a test endpoint (web server)
|
|
that is needed to pass portal detection and perform data transfer tests.
|
|
|
|
"""
|
|
ARP_ANNOUNCE_CONF = '/proc/sys/net/ipv4/conf/all/arp_announce'
|
|
IFACE_NAME = 'pseudomodem0'
|
|
PEER_IFACE_NAME = IFACE_NAME + 'p'
|
|
IFACE_IP_BASE = '192.168.7'
|
|
IFACE_NETWORK_PREFIX = 24
|
|
NETWORK_CHROOT_CONFIG = {
|
|
'etc/passwd' :
|
|
'root:x:0:0:root:/root:/bin/bash\n'
|
|
'nobody:x:65534:65534:nobody:/dev/null:/bin/false\n',
|
|
'etc/group' :
|
|
'nobody::65534:\n'}
|
|
SHILL_PORTAL_DETECTION_SERVER = 'www.gstatic.com'
|
|
|
|
def __init__(self):
|
|
self._arp_announce = 0
|
|
peer_ip = self.IFACE_IP_BASE + '.1'
|
|
peer_interface_ip = peer_ip + '/' + str(self.IFACE_NETWORK_PREFIX)
|
|
self.vif = virtual_ethernet_pair.VirtualEthernetPair(
|
|
interface_name=self.IFACE_NAME,
|
|
peer_interface_name=self.PEER_IFACE_NAME,
|
|
interface_ip=None,
|
|
peer_interface_ip=peer_interface_ip,
|
|
ignore_shutdown_errors=True)
|
|
self.chroot = network_chroot.NetworkChroot(self.PEER_IFACE_NAME,
|
|
peer_ip,
|
|
self.IFACE_NETWORK_PREFIX)
|
|
self.chroot.add_config_templates(self.NETWORK_CHROOT_CONFIG)
|
|
self.chroot.add_startup_command(
|
|
'iptables -I INPUT -p udp --dport 67 -j ACCEPT')
|
|
self.chroot.add_startup_command(
|
|
'iptables -I INPUT -p tcp --dport 80 -j ACCEPT')
|
|
self._dnsmasq_command = self._GetDnsmasqCommand(peer_ip)
|
|
self.chroot.add_startup_command(self._dnsmasq_command)
|
|
self._test_endpoint_command = self._GetTestEndpointCommand()
|
|
self.chroot.add_startup_command(self._test_endpoint_command)
|
|
|
|
@staticmethod
|
|
def _GetDnsmasqCommand(peer_ip):
|
|
dnsmasq_command = (
|
|
'dnsmasq '
|
|
'--dhcp-leasefile=/tmp/dnsmasq.leases '
|
|
'--dhcp-range=%s.2,%s.254 '
|
|
'--no-resolv '
|
|
'--no-hosts ' %
|
|
(PseudoNetInterface.IFACE_IP_BASE,
|
|
PseudoNetInterface.IFACE_IP_BASE))
|
|
test_fetch_url_host = \
|
|
urlparse.urlparse(network.FETCH_URL_PATTERN_FOR_TEST).netloc
|
|
dns_lookup_table = {
|
|
PseudoNetInterface.SHILL_PORTAL_DETECTION_SERVER: peer_ip,
|
|
test_fetch_url_host: peer_ip }
|
|
for host, ip in dns_lookup_table.iteritems():
|
|
dnsmasq_command += '--address=/%s/%s ' % (host, ip)
|
|
return dnsmasq_command
|
|
|
|
@staticmethod
|
|
def _GetTestEndpointCommand():
|
|
test_endpoint_path = os.path.abspath(test_endpoint.__file__)
|
|
if test_endpoint_path.endswith('.pyc'):
|
|
test_endpoint_path = test_endpoint_path[:-1]
|
|
return test_endpoint_path
|
|
|
|
def _ChrootRunCmdIgnoreErrors(self, cmd):
|
|
try:
|
|
self.chroot.run(cmd)
|
|
except error.CmdError:
|
|
pass
|
|
|
|
def BringInterfaceUp(self):
|
|
"""
|
|
Brings up the pseudo modem network interface.
|
|
|
|
"""
|
|
utils.run('sudo ip link set %s up' % self.IFACE_NAME)
|
|
|
|
def BringInterfaceDown(self):
|
|
"""
|
|
Brings down the pseudo modem network interface.
|
|
|
|
"""
|
|
utils.run('sudo ip link set %s down' % self.IFACE_NAME);
|
|
|
|
def Setup(self):
|
|
"""
|
|
Sets up the virtual Ethernet pair and starts dnsmasq.
|
|
|
|
"""
|
|
# Make sure ARP requests for the pseudo modem network addresses
|
|
# go out the pseudo modem network interface.
|
|
self._arp_announce = utils.system_output(
|
|
'cat %s' % self.ARP_ANNOUNCE_CONF)
|
|
utils.run('echo 1 > %s' % self.ARP_ANNOUNCE_CONF)
|
|
|
|
self.vif.setup()
|
|
self.BringInterfaceDown()
|
|
if not self.vif.is_healthy:
|
|
raise Exception('Could not initialize virtual ethernet pair')
|
|
self.chroot.startup()
|
|
|
|
def Teardown(self):
|
|
"""
|
|
Stops dnsmasq and takes down the virtual Ethernet pair.
|
|
|
|
"""
|
|
self._ChrootRunCmdIgnoreErrors(['/bin/bash', '-c', '"pkill dnsmasq"'])
|
|
self._ChrootRunCmdIgnoreErrors(['/bin/bash', '-c',
|
|
'"pkill -f test_endpoint"'])
|
|
self.vif.teardown()
|
|
self.chroot.shutdown()
|
|
utils.run('echo %s > %s' % (self._arp_announce, self.ARP_ANNOUNCE_CONF))
|
|
|
|
def Restart(self):
|
|
"""
|
|
Restarts the configuration.
|
|
|
|
"""
|
|
self.Teardown()
|
|
self.Setup()
|
|
|