1 # Copyright 2015 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """ 6 Encapsulate functionality of the dhcpd Daemon. Support writing out a 7 configuration file as well as starting and stopping the service. 8 """ 9 10 import os 11 import signal 12 13 from autotest_lib.client.common_lib import error 14 from autotest_lib.client.common_lib import utils 15 16 # Filenames used for execution. 17 DHCPV6_SERVER_EXECUTABLE = '/usr/local/sbin/dhcpd' 18 DHCPV6_SERVER_CONFIG_FILE = '/tmp/dhcpv6_test.conf' 19 DHCPV6_SERVER_PID_FILE = '/tmp/dhcpv6_test.pid' 20 21 DHCPV6_SERVER_ADDRESS = '2001:db8:0:1::1' 22 DHCPV6_SERVER_SUBNET_PREFIX = '2001:db8:0:1::' 23 DHCPV6_SERVER_SUBNET_PREFIX_LENGTH = 64 24 DHCPV6_ADDRESS_RANGE_LOW = 0x100 25 DHCPV6_ADDRESS_RANGE_HIGH = 0x1ff 26 DHCPV6_PREFIX_DELEGATION_INDEX_LOW = 0x1 27 DHCPV6_PREFIX_DELEGATION_INDEX_HIGH = 0xf 28 DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT = '2001:db8:0:%x00::' 29 DHCPV6_PREFIX_DELEGATION_RANGE_LOW = (DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT % 30 (DHCPV6_PREFIX_DELEGATION_INDEX_LOW)) 31 DHCPV6_PREFIX_DELEGATION_RANGE_HIGH = (DHCPV6_PREFIX_DELEGATION_RANGE_FORMAT % 32 (DHCPV6_PREFIX_DELEGATION_INDEX_HIGH)) 33 DHCPV6_PREFIX_DELEGATION_PREFIX_LENGTH = 56 34 DHCPV6_DEFAULT_LEASE_TIME = 600 35 DHCPV6_MAX_LEASE_TIME = 7200 36 DHCPV6_NAME_SERVERS = 'fec0:0:0:1::1' 37 DHCPV6_DOMAIN_SEARCH = 'domain.example' 38 39 CONFIG_DEFAULT_LEASE_TIME = 'default_lease_time' 40 CONFIG_MAX_LEASE_TIME = 'max_lease_time' 41 CONFIG_SUBNET = 'subnet' 42 CONFIG_RANGE = 'range' 43 CONFIG_NAME_SERVERS = 'name_servers' 44 CONFIG_DOMAIN_SEARCH = 'domain_search' 45 CONFIG_PREFIX_RANGE = 'prefix_range' 46 47 class Dhcpv6TestServer(object): 48 """ 49 This is an embodiment of the DHCPv6 server (dhcpd) process. It converts an 50 config dict into parameters for the dhcpd configuration file and 51 manages startup and cleanup of the process. 52 """ 53 54 def __init__(self, interface = None): 55 if not os.path.exists(DHCPV6_SERVER_EXECUTABLE): 56 raise error.TestNAError('Could not find executable %s; ' 57 'this is likely an old version of ' 58 'ChromiumOS' % 59 DHCPV6_SERVER_EXECUTABLE) 60 self._interface = interface 61 # "2001:db8:0:1::/64" 62 subnet = '%s/%d' % (DHCPV6_SERVER_SUBNET_PREFIX, 63 DHCPV6_SERVER_SUBNET_PREFIX_LENGTH) 64 # "2001:db8:0:1::100 2001:db8:1::1ff" 65 range = '%s%x %s%x' % (DHCPV6_SERVER_SUBNET_PREFIX, 66 DHCPV6_ADDRESS_RANGE_LOW, 67 DHCPV6_SERVER_SUBNET_PREFIX, 68 DHCPV6_ADDRESS_RANGE_HIGH) 69 # "2001:db8:0:100:: 2001:db8:1:f00:: /56" 70 prefix_range = '%s %s /%d' % (DHCPV6_PREFIX_DELEGATION_RANGE_LOW, 71 DHCPV6_PREFIX_DELEGATION_RANGE_HIGH, 72 DHCPV6_PREFIX_DELEGATION_PREFIX_LENGTH) 73 self._config = { 74 CONFIG_DEFAULT_LEASE_TIME: DHCPV6_DEFAULT_LEASE_TIME, 75 CONFIG_MAX_LEASE_TIME: DHCPV6_MAX_LEASE_TIME, 76 CONFIG_SUBNET: subnet, 77 CONFIG_RANGE: range, 78 CONFIG_NAME_SERVERS: DHCPV6_NAME_SERVERS, 79 CONFIG_DOMAIN_SEARCH: DHCPV6_DOMAIN_SEARCH, 80 CONFIG_PREFIX_RANGE: prefix_range 81 } 82 83 84 def _write_config_file(self): 85 """ 86 Write out a configuration file for DHCPv6 server to use. 87 """ 88 config = '\n'.join([ 89 'default-lease-time %(default_lease_time)d;', 90 'max-lease-time %(max_lease_time)d;', 91 'subnet6 %(subnet)s {', 92 ' range6 %(range)s;', 93 ' option dhcp6.name-servers %(name_servers)s;', 94 ' option dhcp6.domain-search \"%(domain_search)s\";', 95 ' prefix6 %(prefix_range)s;', 96 '}' 97 '']) % self._config 98 with open(DHCPV6_SERVER_CONFIG_FILE, 'w') as f: 99 f.write(config) 100 101 102 def _cleanup(self): 103 """ 104 Cleanup temporary files. If PID file exists, also kill the 105 associated process. 106 """ 107 if os.path.exists(DHCPV6_SERVER_PID_FILE): 108 pid = int(file(DHCPV6_SERVER_PID_FILE).read()) 109 os.remove(DHCPV6_SERVER_PID_FILE) 110 try: 111 os.kill(pid, signal.SIGTERM) 112 except OSError: 113 pass 114 if os.path.exists(DHCPV6_SERVER_CONFIG_FILE): 115 os.remove(DHCPV6_SERVER_CONFIG_FILE) 116 117 118 def start(self): 119 """ 120 Start the DHCPv6 server. The server will daemonize itself and 121 run in the background. 122 """ 123 self._cleanup() 124 self._write_config_file() 125 utils.system('%s -6 -pf %s -cf %s %s' % 126 (DHCPV6_SERVER_EXECUTABLE, 127 DHCPV6_SERVER_PID_FILE, 128 DHCPV6_SERVER_CONFIG_FILE, 129 self._interface)) 130 131 132 def stop(self): 133 """ 134 Halt the DHCPv6 server. 135 """ 136 self._cleanup() 137