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