| # Copyright 2015 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. |
| |
| """ |
| Encapsulate functionality of the dhcpd Daemon. Support writing out a |
| configuration file as well as starting and stopping the service. |
| """ |
| |
| import os |
| import signal |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.client.common_lib import utils |
| |
| # Filenames used for execution. |
| DHCPV6_SERVER_EXECUTABLE = '/usr/local/sbin/dhcpd' |
| DHCPV6_SERVER_CONFIG_FILE = '/tmp/dhcpv6_test.conf' |
| DHCPV6_SERVER_PID_FILE = '/tmp/dhcpv6_test.pid' |
| |
| DHCPV6_SERVER_ADDRESS = '2001:db8:0:1::1' |
| DHCPV6_SERVER_SUBNET_PREFIX = '2001:db8:0:1::' |
| DHCPV6_SERVER_SUBNET_PREFIX_LENGTH = 64 |
| DHCPV6_ADDRESS_RANGE_LOW = 0x100 |
| DHCPV6_ADDRESS_RANGE_HIGH = 0x1ff |
| DHCPV6_PREFIX_DELEGATION_INDEX_LOW = 0x1 |
| DHCPV6_PREFIX_DELEGATION_INDEX_HIGH = 0xf |
| DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT = '2001:db8:0:%x00::' |
| DHCPV6_PREFIX_DELEGATION_RANGE_LOW = (DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT % |
| (DHCPV6_PREFIX_DELEGATION_INDEX_LOW)) |
| DHCPV6_PREFIX_DELEGATION_RANGE_HIGH = (DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT % |
| (DHCPV6_PREFIX_DELEGATION_INDEX_HIGH)) |
| DHCPV6_PREFIX_DELEGATION_PREFIX_LENGTH = 56 |
| DHCPV6_DEFAULT_LEASE_TIME = 600 |
| DHCPV6_MAX_LEASE_TIME = 7200 |
| DHCPV6_NAME_SERVERS = 'fec0:0:0:1::1' |
| DHCPV6_DOMAIN_SEARCH = 'domain.example' |
| |
| CONFIG_DEFAULT_LEASE_TIME = 'default_lease_time' |
| CONFIG_MAX_LEASE_TIME = 'max_lease_time' |
| CONFIG_SUBNET = 'subnet' |
| CONFIG_RANGE = 'range' |
| CONFIG_NAME_SERVERS = 'name_servers' |
| CONFIG_DOMAIN_SEARCH = 'domain_search' |
| CONFIG_PREFIX_RANGE = 'prefix_range' |
| |
| class Dhcpv6TestServer(object): |
| """ |
| This is an embodiment of the DHCPv6 server (dhcpd) process. It converts an |
| config dict into parameters for the dhcpd configuration file and |
| manages startup and cleanup of the process. |
| """ |
| |
| def __init__(self, interface = None): |
| if not os.path.exists(DHCPV6_SERVER_EXECUTABLE): |
| raise error.TestNAError('Could not find executable %s; ' |
| 'this is likely an old version of ' |
| 'ChromiumOS' % |
| DHCPV6_SERVER_EXECUTABLE) |
| self._interface = interface |
| # "2001:db8:0:1::/64" |
| subnet = '%s/%d' % (DHCPV6_SERVER_SUBNET_PREFIX, |
| DHCPV6_SERVER_SUBNET_PREFIX_LENGTH) |
| # "2001:db8:0:1::100 2001:db8:1::1ff" |
| range = '%s%x %s%x' % (DHCPV6_SERVER_SUBNET_PREFIX, |
| DHCPV6_ADDRESS_RANGE_LOW, |
| DHCPV6_SERVER_SUBNET_PREFIX, |
| DHCPV6_ADDRESS_RANGE_HIGH) |
| # "2001:db8:0:100:: 2001:db8:1:f00:: /56" |
| prefix_range = '%s %s /%d' % (DHCPV6_PREFIX_DELEGATION_RANGE_LOW, |
| DHCPV6_PREFIX_DELEGATION_RANGE_HIGH, |
| DHCPV6_PREFIX_DELEGATION_PREFIX_LENGTH) |
| self._config = { |
| CONFIG_DEFAULT_LEASE_TIME: DHCPV6_DEFAULT_LEASE_TIME, |
| CONFIG_MAX_LEASE_TIME: DHCPV6_MAX_LEASE_TIME, |
| CONFIG_SUBNET: subnet, |
| CONFIG_RANGE: range, |
| CONFIG_NAME_SERVERS: DHCPV6_NAME_SERVERS, |
| CONFIG_DOMAIN_SEARCH: DHCPV6_DOMAIN_SEARCH, |
| CONFIG_PREFIX_RANGE: prefix_range |
| } |
| |
| |
| def _write_config_file(self): |
| """ |
| Write out a configuration file for DHCPv6 server to use. |
| """ |
| config = '\n'.join([ |
| 'default-lease-time %(default_lease_time)d;', |
| 'max-lease-time %(max_lease_time)d;', |
| 'subnet6 %(subnet)s {', |
| ' range6 %(range)s;', |
| ' option dhcp6.name-servers %(name_servers)s;', |
| ' option dhcp6.domain-search \"%(domain_search)s\";', |
| ' prefix6 %(prefix_range)s;', |
| '}' |
| '']) % self._config |
| with open(DHCPV6_SERVER_CONFIG_FILE, 'w') as f: |
| f.write(config) |
| |
| |
| def _cleanup(self): |
| """ |
| Cleanup temporary files. If PID file exists, also kill the |
| associated process. |
| """ |
| if os.path.exists(DHCPV6_SERVER_PID_FILE): |
| pid = int(file(DHCPV6_SERVER_PID_FILE).read()) |
| os.remove(DHCPV6_SERVER_PID_FILE) |
| try: |
| os.kill(pid, signal.SIGTERM) |
| except OSError: |
| pass |
| if os.path.exists(DHCPV6_SERVER_CONFIG_FILE): |
| os.remove(DHCPV6_SERVER_CONFIG_FILE) |
| |
| |
| def start(self): |
| """ |
| Start the DHCPv6 server. The server will daemonize itself and |
| run in the background. |
| """ |
| self._cleanup() |
| self._write_config_file() |
| utils.system('%s -6 -pf %s -cf %s %s' % |
| (DHCPV6_SERVER_EXECUTABLE, |
| DHCPV6_SERVER_PID_FILE, |
| DHCPV6_SERVER_CONFIG_FILE, |
| self._interface)) |
| |
| |
| def stop(self): |
| """ |
| Halt the DHCPv6 server. |
| """ |
| self._cleanup() |