1# Copyright 2020 - The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import re 16import time 17 18from acts import signals 19from acts import utils 20from acts.controllers.openwrt_lib import network_const 21 22 23SERVICE_DNSMASQ = "dnsmasq" 24SERVICE_STUNNEL = "stunnel" 25SERVICE_NETWORK = "network" 26SERVICE_PPTPD = "pptpd" 27SERVICE_FIREWALL = "firewall" 28SERVICE_IPSEC = "ipsec" 29SERVICE_XL2TPD = "xl2tpd" 30SERVICE_ODHCPD = "odhcpd" 31SERVICE_OPENNDS = "opennds" 32SERVICE_UHTTPD = "uhttpd" 33PPTP_PACKAGE = "pptpd kmod-nf-nathelper-extra" 34L2TP_PACKAGE = "strongswan-full openssl-util xl2tpd" 35NAT6_PACKAGE = "ip6tables kmod-ipt-nat6" 36CAPTIVE_PORTAL_PACKAGE = "opennds php7-cli php7-mod-openssl php7-cgi php7" 37MDNS_PACKAGE = "avahi-utils avahi-daemon-service-http avahi-daemon-service-ssh libavahi-client avahi-dbus-daemon" 38STUNNEL_CONFIG_PATH = "/etc/stunnel/DoTServer.conf" 39HISTORY_CONFIG_PATH = "/etc/dirty_configs" 40PPTPD_OPTION_PATH = "/etc/ppp/options.pptpd" 41XL2TPD_CONFIG_PATH = "/etc/xl2tpd/xl2tpd.conf" 42XL2TPD_OPTION_CONFIG_PATH = "/etc/ppp/options.xl2tpd" 43FIREWALL_CUSTOM_OPTION_PATH = "/etc/firewall.user" 44PPP_CHAP_SECRET_PATH = "/etc/ppp/chap-secrets" 45IKEV2_VPN_CERT_KEYS_PATH = "/var/ikev2_cert.sh" 46TCPDUMP_DIR = "/tmp/tcpdump/" 47LOCALHOST = "192.168.1.1" 48DEFAULT_PACKAGE_INSTALL_TIMEOUT = 200 49 50 51class NetworkSettings(object): 52 """Class for network settings. 53 54 Attributes: 55 ssh: ssh connection object. 56 ssh_settings: ssh settings for AccessPoint. 57 service_manager: Object manage service configuration. 58 user: username for ssh. 59 ip: ip address for AccessPoint. 60 log: Logging object for AccessPoint. 61 config: A list to store changes on network settings. 62 firewall_rules_list: A list of firewall rule name list. 63 cleanup_map: A dict for compare oppo functions. 64 l2tp: profile for vpn l2tp server. 65 """ 66 67 def __init__(self, ssh, ssh_settings, logger): 68 """Initialize wireless settings. 69 70 Args: 71 ssh: ssh connection object. 72 ssh_settings: ssh settings for AccessPoint. 73 logger: Logging object for AccessPoint. 74 """ 75 self.ssh = ssh 76 self.service_manager = ServiceManager(ssh) 77 self.ssh_settings = ssh_settings 78 self.user = self.ssh_settings.username 79 self.ip = self.ssh_settings.hostname 80 self.log = logger 81 self.config = set() 82 self.firewall_rules_list = [] 83 self.cleanup_map = { 84 "setup_dns_server": self.remove_dns_server, 85 "setup_vpn_pptp_server": self.remove_vpn_pptp_server, 86 "setup_vpn_l2tp_server": self.remove_vpn_l2tp_server, 87 "disable_ipv6": self.enable_ipv6, 88 "setup_ipv6_bridge": self.remove_ipv6_bridge, 89 "default_dns": self.del_default_dns, 90 "default_v6_dns": self.del_default_v6_dns, 91 "ipv6_prefer_option": self.remove_ipv6_prefer_option, 92 "block_dns_response": self.unblock_dns_response, 93 "setup_mdns": self.remove_mdns, 94 "add_dhcp_rapid_commit": self.remove_dhcp_rapid_commit, 95 "setup_captive_portal": self.remove_cpative_portal 96 } 97 # This map contains cleanup functions to restore the configuration to 98 # its default state. We write these keys to HISTORY_CONFIG_PATH prior to 99 # making any changes to that subsystem. 100 # This makes it easier to recover after an aborted test. 101 self.update_firewall_rules_list() 102 self.cleanup_network_settings() 103 self.clear_tcpdump() 104 105 def cleanup_network_settings(self): 106 """Reset all changes on Access point.""" 107 108 # Detect if any changes that is not clean up. 109 if self.file_exists(HISTORY_CONFIG_PATH): 110 out = self.ssh.run("cat %s" % HISTORY_CONFIG_PATH).stdout 111 if out: 112 self.config = set(out.split("\n")) 113 114 if self.config: 115 temp = self.config.copy() 116 for change in temp: 117 change_list = change.split() 118 if len(change_list) > 1: 119 self.cleanup_map[change_list[0]](*change_list[1:]) 120 else: 121 self.cleanup_map[change]() 122 self.config = set() 123 124 if self.file_exists(HISTORY_CONFIG_PATH): 125 out = self.ssh.run("cat %s" % HISTORY_CONFIG_PATH).stdout 126 if not out: 127 self.ssh.run("rm %s" % HISTORY_CONFIG_PATH) 128 129 def commit_changes(self): 130 """Apply changes on Access point.""" 131 self.ssh.run("uci commit") 132 self.service_manager.restart_services() 133 self.create_config_file("\n".join(self.config), 134 HISTORY_CONFIG_PATH) 135 136 def package_install(self, package_list): 137 """Install packages on OpenWrtAP via opkg If not installed. 138 139 Args: 140 package_list: package list to install. 141 e.g. "pptpd kmod-mppe kmod-nf-nathelper-extra" 142 """ 143 self.ssh.run("opkg update") 144 for package_name in package_list.split(" "): 145 if not self._package_installed(package_name): 146 self.ssh.run("opkg install %s" % package_name, 147 timeout=DEFAULT_PACKAGE_INSTALL_TIMEOUT) 148 self.log.info("Package: %s installed." % package_name) 149 else: 150 self.log.info("Package: %s skipped (already installed)." % package_name) 151 152 def package_remove(self, package_list): 153 """Remove packages on OpenWrtAP via opkg If existed. 154 155 Args: 156 package_list: package list to remove. 157 """ 158 for package_name in package_list.split(" "): 159 if self._package_installed(package_name): 160 self.ssh.run("opkg remove %s" % package_name) 161 self.log.info("Package: %s removed." % package_name) 162 else: 163 self.log.info("No exist package %s found." % package_name) 164 165 def _package_installed(self, package_name): 166 """Check if target package installed on OpenWrtAP. 167 168 Args: 169 package_name: package name want to check. 170 171 Returns: 172 True if installed. 173 """ 174 if self.ssh.run("opkg list-installed %s" % package_name).stdout: 175 return True 176 return False 177 178 def file_exists(self, abs_file_path): 179 """Check if target file exist on specific path on OpenWrt. 180 181 Args: 182 abs_file_path: Absolute path for the file. 183 184 Returns: 185 True if Existed. 186 """ 187 path, file_name = abs_file_path.rsplit("/", 1) 188 if self.ssh.run("ls %s | grep %s" % (path, file_name), 189 ignore_status=True).stdout: 190 return True 191 return False 192 193 def path_exists(self, abs_path): 194 """Check if dir exist on OpenWrt. 195 196 Args: 197 abs_path: absolutely path for create folder. 198 """ 199 try: 200 self.ssh.run("ls %s" % abs_path) 201 except: 202 return False 203 return True 204 205 def create_folder(self, abs_path): 206 """If dir not exist, create it. 207 208 Args: 209 abs_path: absolutely path for create folder. 210 """ 211 if not self.path_exists(abs_path): 212 self.ssh.run("mkdir %s" % abs_path) 213 else: 214 self.log.info("%s already existed." %abs_path) 215 216 def count(self, config, key): 217 """Count in uci config. 218 219 Args: 220 config: config or section to research 221 key: keywords to e.g. rule, domain 222 Returns: 223 Numbers of the count. 224 """ 225 count = self.ssh.run("uci show %s | grep =%s" % (config, key), 226 ignore_status=True).stdout 227 return len(count.split("\n")) 228 229 def create_config_file(self, config, file_path): 230 """Create config file. Overwrite if file already exist. 231 232 Args: 233 config: A string of content of config. 234 file_path: Config's abs_path. 235 """ 236 self.ssh.run("echo -e \"%s\" > %s" % (config, file_path)) 237 238 def replace_config_option(self, old_option, new_option, file_path): 239 """Replace config option if pattern match. 240 241 If find match pattern with old_option, then replace it with new_option. 242 Else add new_option to the file. 243 244 Args: 245 old_option: the regexp pattern to replace. 246 new_option: the option to add. 247 file_path: Config's abs_path. 248 """ 249 config = self.ssh.run("cat %s" % file_path).stdout 250 config, count = re.subn(old_option, new_option, config) 251 if not count: 252 config = "\n".join([config, new_option]) 253 self.create_config_file(config, file_path) 254 255 def remove_config_option(self, option, file_path): 256 """Remove option from config file. 257 258 Args: 259 option: Option to remove. Support regular expression. 260 file_path: Config's abs_path. 261 Returns: 262 Boolean for find option to remove. 263 """ 264 config = self.ssh.run("cat %s" % file_path).stdout.split("\n") 265 for line in config: 266 count = re.subn(option, "", line)[1] 267 if count > 0: 268 config.remove(line) 269 self.create_config_file("\n".join(config), file_path) 270 return True 271 self.log.warning("No match option to remove.") 272 return False 273 274 def setup_dns_server(self, domain_name): 275 """Setup DNS server on OpenWrtAP. 276 277 Args: 278 domain_name: Local dns domain name. 279 """ 280 self.config.add("setup_dns_server") 281 self.log.info("Setup DNS server with domain name %s" % domain_name) 282 self.ssh.run("uci set dhcp.@dnsmasq[0].local='/%s/'" % domain_name) 283 self.ssh.run("uci set dhcp.@dnsmasq[0].domain='%s'" % domain_name) 284 self.add_resource_record(domain_name, self.ip) 285 self.service_manager.need_restart(SERVICE_DNSMASQ) 286 self.commit_changes() 287 288 # Check stunnel package is installed 289 self.package_install("stunnel") 290 self.service_manager.stop(SERVICE_STUNNEL) 291 self.service_manager.disable(SERVICE_STUNNEL) 292 293 # Enable stunnel 294 self.create_stunnel_config() 295 self.ssh.run("stunnel /etc/stunnel/DoTServer.conf") 296 297 def remove_dns_server(self): 298 """Remove DNS server on OpenWrtAP.""" 299 if self.file_exists("/var/run/stunnel.pid"): 300 self.ssh.run("kill $(cat /var/run/stunnel.pid)") 301 self.ssh.run("uci set dhcp.@dnsmasq[0].local='/lan/'") 302 self.ssh.run("uci set dhcp.@dnsmasq[0].domain='lan'") 303 self.clear_resource_record() 304 self.service_manager.need_restart(SERVICE_DNSMASQ) 305 self.config.discard("setup_dns_server") 306 self.commit_changes() 307 308 def add_resource_record(self, domain_name, domain_ip): 309 """Add resource record. 310 311 Args: 312 domain_name: A string for domain name. 313 domain_ip: A string for domain ip. 314 """ 315 self.ssh.run("uci add dhcp domain") 316 self.ssh.run("uci set dhcp.@domain[-1].name='%s'" % domain_name) 317 self.ssh.run("uci set dhcp.@domain[-1].ip='%s'" % domain_ip) 318 self.service_manager.need_restart(SERVICE_DNSMASQ) 319 320 def del_resource_record(self): 321 """Delete the last resource record.""" 322 self.ssh.run("uci delete dhcp.@domain[-1]") 323 self.service_manager.need_restart(SERVICE_DNSMASQ) 324 325 def clear_resource_record(self): 326 """Delete the all resource record.""" 327 rr = self.ssh.run("uci show dhcp | grep =domain", 328 ignore_status=True).stdout 329 if rr: 330 for _ in rr.split("\n"): 331 self.del_resource_record() 332 self.service_manager.need_restart(SERVICE_DNSMASQ) 333 334 def create_stunnel_config(self): 335 """Create config for stunnel service.""" 336 stunnel_config = [ 337 "pid = /var/run/stunnel.pid", 338 "[dns]", 339 "accept = 853", 340 "connect = 127.0.0.1:53", 341 "cert = /etc/stunnel/fullchain.pem", 342 "key = /etc/stunnel/privkey.pem", 343 ] 344 config_string = "\n".join(stunnel_config) 345 self.create_config_file(config_string, STUNNEL_CONFIG_PATH) 346 347 def setup_vpn_pptp_server(self, local_ip, user, password): 348 """Setup pptp vpn server on OpenWrt. 349 350 Args: 351 local_ip: local pptp server ip address. 352 user: username for pptp user. 353 password: password for pptp user. 354 """ 355 # Install pptp service 356 self.package_install(PPTP_PACKAGE) 357 358 self.config.add("setup_vpn_pptp_server") 359 # Edit /etc/config/pptpd & /etc/ppp/options.pptpd 360 self.setup_pptpd(local_ip, user, password) 361 # Edit /etc/config/firewall & /etc/firewall.user 362 self.setup_firewall_rules_for_pptp() 363 # Enable service 364 self.service_manager.enable(SERVICE_PPTPD) 365 self.service_manager.need_restart(SERVICE_PPTPD) 366 self.service_manager.need_restart(SERVICE_FIREWALL) 367 self.commit_changes() 368 369 def remove_vpn_pptp_server(self): 370 """Remove pptp vpn server on OpenWrt.""" 371 # Edit /etc/config/pptpd 372 self.restore_pptpd() 373 # Edit /etc/config/firewall & /etc/firewall.user 374 self.restore_firewall_rules_for_pptp() 375 # Disable service 376 self.service_manager.disable(SERVICE_PPTPD) 377 self.service_manager.need_restart(SERVICE_PPTPD) 378 self.service_manager.need_restart(SERVICE_FIREWALL) 379 self.config.discard("setup_vpn_pptp_server") 380 self.commit_changes() 381 382 self.package_remove(PPTP_PACKAGE) 383 self.ssh.run("rm /etc/ppp/options.pptpd") 384 self.ssh.run("rm /etc/config/pptpd") 385 386 def setup_pptpd(self, local_ip, username, password, ms_dns="8.8.8.8"): 387 """Setup pptpd config for ip addr and account. 388 389 Args: 390 local_ip: vpn server address 391 username: pptp vpn username 392 password: pptp vpn password 393 ms_dns: DNS server 394 """ 395 # Calculate remote ip address 396 # e.g. local_ip = 10.10.10.9 397 # remote_ip = 10.10.10.10 -250 398 remote_ip = local_ip.split(".") 399 remote_ip.append(str(int(remote_ip.pop(-1)) + 1)) 400 remote_ip = ".".join(remote_ip) 401 # Enable pptp service and set ip addr 402 self.ssh.run("uci set pptpd.pptpd.enabled=1") 403 self.ssh.run("uci set pptpd.pptpd.localip='%s'" % local_ip) 404 self.ssh.run("uci set pptpd.pptpd.remoteip='%s-250'" % remote_ip) 405 406 # Setup pptp service account 407 self.ssh.run("uci set pptpd.@login[0].username='%s'" % username) 408 self.ssh.run("uci set pptpd.@login[0].password='%s'" % password) 409 self.service_manager.need_restart(SERVICE_PPTPD) 410 411 self.replace_config_option(r"#*ms-dns \d+.\d+.\d+.\d+", 412 "ms-dns %s" % ms_dns, PPTPD_OPTION_PATH) 413 self.replace_config_option("(#no)*proxyarp", 414 "proxyarp", PPTPD_OPTION_PATH) 415 416 def restore_pptpd(self): 417 """Disable pptpd.""" 418 self.ssh.run("uci set pptpd.pptpd.enabled=0") 419 self.remove_config_option(r"\S+ pptp-server \S+ \*", 420 PPP_CHAP_SECRET_PATH) 421 self.service_manager.need_restart(SERVICE_PPTPD) 422 423 def setup_vpn_l2tp_server(self, 424 vpn_server_hostname, 425 vpn_server_address, 426 vpn_username, 427 vpn_password, 428 psk_secret, 429 server_name, 430 country, 431 org): 432 """Setup l2tp vpn server on OpenWrt. 433 434 Args: 435 vpn_server_hostname: vpn server domain name 436 vpn_server_address: vpn server addr 437 vpn_username: vpn account 438 vpn_password: vpn password 439 psk_secret: psk for ipsec 440 server_name: vpn server name for register in OpenWrt 441 country: country code for generate cert keys. 442 org: Organization name for generate cert keys. 443 """ 444 self.l2tp = network_const.VpnL2tp(vpn_server_hostname, 445 vpn_server_address, 446 vpn_username, 447 vpn_password, 448 psk_secret, 449 server_name) 450 451 self.package_install(L2TP_PACKAGE) 452 self.config.add("setup_vpn_l2tp_server") 453 454 # /etc/strongswan.conf: Strongswan configuration file 455 self.setup_strongswan() 456 # /etc/ipsec.conf /etc/ipsec.secrets 457 self.setup_ipsec() 458 # /etc/xl2tpd/xl2tpd.conf & /etc/ppp/options.xl2tpd 459 self.setup_xl2tpd() 460 # /etc/ppp/chap-secrets 461 self.setup_ppp_secret() 462 # /etc/config/firewall & /etc/firewall.user 463 self.setup_firewall_rules_for_l2tp() 464 # setup vpn server local ip 465 self.setup_vpn_local_ip() 466 # generate cert and key for rsa 467 if self.l2tp.name == "ikev2-server": 468 self.generate_ikev2_vpn_cert_keys(country, org) 469 self.add_resource_record(self.l2tp.hostname, LOCALHOST) 470 else: 471 self.generate_vpn_cert_keys(country, org) 472 # restart service 473 self.service_manager.need_restart(SERVICE_IPSEC) 474 self.service_manager.need_restart(SERVICE_XL2TPD) 475 self.service_manager.need_restart(SERVICE_FIREWALL) 476 self.commit_changes() 477 478 def remove_vpn_l2tp_server(self): 479 """Remove l2tp vpn server on OpenWrt.""" 480 self.config.discard("setup_vpn_l2tp_server") 481 self.restore_firewall_rules_for_l2tp() 482 self.remove_vpn_local_ip() 483 if self.l2tp.name == "ikev2-server": 484 self.clear_resource_record() 485 self.service_manager.need_restart(SERVICE_IPSEC) 486 self.service_manager.need_restart(SERVICE_XL2TPD) 487 self.service_manager.need_restart(SERVICE_FIREWALL) 488 self.commit_changes() 489 self.package_remove(L2TP_PACKAGE) 490 if hasattr(self, "l2tp"): 491 delattr(self, "l2tp") 492 493 def setup_strongswan(self, dns="8.8.8.8"): 494 """Setup strongswan config.""" 495 config = [ 496 "charon {", 497 " load_modular = yes", 498 " plugins {", 499 " include strongswan.d/charon/*.conf", 500 " }", 501 " dns1=%s" % dns, 502 "}" 503 ] 504 self.create_config_file("\n".join(config), "/etc/strongswan.conf") 505 506 def setup_ipsec(self): 507 """Setup ipsec config.""" 508 def load_ipsec_config(data, rightsourceip=False): 509 for i in data.keys(): 510 config.append(i) 511 for j in data[i].keys(): 512 config.append("\t %s=%s" % (j, data[i][j])) 513 if rightsourceip: 514 config.append("\t rightsourceip=%s.16/26" % self.l2tp.address.rsplit(".", 1)[0]) 515 config.append("") 516 517 config = [] 518 load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2, True) 519 load_ipsec_config(network_const.IPSEC_IKEV2_PSK, True) 520 load_ipsec_config(network_const.IPSEC_IKEV2_RSA, True) 521 load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2_HOSTNAME, True) 522 load_ipsec_config(network_const.IPSEC_IKEV2_PSK_HOSTNAME, True) 523 load_ipsec_config(network_const.IPSEC_IKEV2_RSA_HOSTNAME, True) 524 load_ipsec_config(network_const.IPSEC_CONF) 525 load_ipsec_config(network_const.IPSEC_L2TP_PSK) 526 load_ipsec_config(network_const.IPSEC_L2TP_RSA) 527 load_ipsec_config(network_const.IPSEC_HYBRID_RSA, True) 528 load_ipsec_config(network_const.IPSEC_XAUTH_PSK, True) 529 load_ipsec_config(network_const.IPSEC_XAUTH_RSA, True) 530 self.create_config_file("\n".join(config), "/etc/ipsec.conf") 531 532 ipsec_secret = [] 533 ipsec_secret.append(r": PSK \"%s\"" % self.l2tp.psk_secret) 534 ipsec_secret.append(r": RSA \"%s\"" % "serverKey.der") 535 ipsec_secret.append(r"%s : XAUTH \"%s\"" % (self.l2tp.username, 536 self.l2tp.password)) 537 self.create_config_file("\n".join(ipsec_secret), "/etc/ipsec.secrets") 538 539 def setup_xl2tpd(self, ip_range=20): 540 """Setup xl2tpd config.""" 541 net_id, host_id = self.l2tp.address.rsplit(".", 1) 542 xl2tpd_conf = list(network_const.XL2TPD_CONF_GLOBAL) 543 xl2tpd_conf.append("auth file = %s" % PPP_CHAP_SECRET_PATH) 544 xl2tpd_conf.extend(network_const.XL2TPD_CONF_INS) 545 xl2tpd_conf.append("ip range = %s.%s-%s.%s" % 546 (net_id, host_id, net_id, 547 str(int(host_id)+ip_range))) 548 xl2tpd_conf.append("local ip = %s" % self.l2tp.address) 549 xl2tpd_conf.append("name = %s" % self.l2tp.name) 550 xl2tpd_conf.append("pppoptfile = %s" % XL2TPD_OPTION_CONFIG_PATH) 551 552 self.create_config_file("\n".join(xl2tpd_conf), XL2TPD_CONFIG_PATH) 553 xl2tpd_option = list(network_const.XL2TPD_OPTION) 554 xl2tpd_option.append("name %s" % self.l2tp.name) 555 self.create_config_file("\n".join(xl2tpd_option), 556 XL2TPD_OPTION_CONFIG_PATH) 557 558 def setup_ppp_secret(self): 559 self.replace_config_option( 560 r"\S+ %s \S+ \*" % self.l2tp.name, 561 "%s %s %s *" % (self.l2tp.username, 562 self.l2tp.name, 563 self.l2tp.password), 564 PPP_CHAP_SECRET_PATH) 565 566 def generate_vpn_cert_keys(self, country, org): 567 """Generate cert and keys for vpn server.""" 568 rsa = "--type rsa" 569 lifetime = "--lifetime 365" 570 size = "--size 4096" 571 572 self.ssh.run("ipsec pki --gen %s %s --outform der > caKey.der" % 573 (rsa, size)) 574 self.ssh.run("ipsec pki --self --ca %s --in caKey.der %s --dn " 575 "\"C=%s, O=%s, CN=%s\" --outform der > caCert.der" % 576 (lifetime, rsa, country, org, self.l2tp.hostname)) 577 self.ssh.run("ipsec pki --gen %s %s --outform der > serverKey.der" % 578 (size, rsa)) 579 self.ssh.run("ipsec pki --pub --in serverKey.der %s | ipsec pki " 580 "--issue %s --cacert caCert.der --cakey caKey.der " 581 "--dn \"C=%s, O=%s, CN=%s\" --san %s --flag serverAuth" 582 " --flag ikeIntermediate --outform der > serverCert.der" % 583 (rsa, lifetime, country, org, self.l2tp.hostname, LOCALHOST)) 584 self.ssh.run("ipsec pki --gen %s %s --outform der > clientKey.der" % 585 (size, rsa)) 586 self.ssh.run("ipsec pki --pub --in clientKey.der %s | ipsec pki " 587 "--issue %s --cacert caCert.der --cakey caKey.der " 588 "--dn \"C=%s, O=%s, CN=%s@%s\" --outform der > " 589 "clientCert.der" % (rsa, lifetime, country, org, 590 self.l2tp.username, self.l2tp.hostname)) 591 592 self.ssh.run( 593 "openssl rsa -inform DER -in clientKey.der" 594 " -out clientKey.pem -outform PEM" 595 ) 596 self.ssh.run( 597 "openssl x509 -inform DER -in clientCert.der" 598 " -out clientCert.pem -outform PEM" 599 ) 600 self.ssh.run( 601 "openssl x509 -inform DER -in caCert.der" 602 " -out caCert.pem -outform PEM" 603 ) 604 self.ssh.run( 605 "openssl pkcs12 -in clientCert.pem -inkey clientKey.pem" 606 " -certfile caCert.pem -export -out clientPkcs.p12 -passout pass:" 607 ) 608 609 self.ssh.run("mv caCert.pem /etc/ipsec.d/cacerts/") 610 self.ssh.run("mv *Cert* /etc/ipsec.d/certs/") 611 self.ssh.run("mv *Key* /etc/ipsec.d/private/") 612 if not self.path_exists("/www/downloads/"): 613 self.ssh.run("mkdir /www/downloads/") 614 self.ssh.run("mv clientPkcs.p12 /www/downloads/") 615 self.ssh.run("chmod 664 /www/downloads/clientPkcs.p12") 616 617 def generate_ikev2_vpn_cert_keys(self, country, org): 618 rsa = "--type rsa" 619 lifetime = "--lifetime 365" 620 size = "--size 4096" 621 622 if not self.path_exists("/www/downloads/"): 623 self.ssh.run("mkdir /www/downloads/") 624 625 ikev2_vpn_cert_keys = [ 626 "ipsec pki --gen %s %s --outform der > caKey.der" % (rsa, size), 627 "ipsec pki --self --ca %s --in caKey.der %s --dn " 628 "\"C=%s, O=%s, CN=%s\" --outform der > caCert.der" % 629 (lifetime, rsa, country, org, self.l2tp.hostname), 630 "ipsec pki --gen %s %s --outform der > serverKey.der" % (size, rsa), 631 "ipsec pki --pub --in serverKey.der %s | ipsec pki --issue %s " 632 r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s\" " 633 "--san %s --san %s --flag serverAuth --flag ikeIntermediate " 634 "--outform der > serverCert.der" % (rsa, lifetime, country, org, 635 self.l2tp.hostname, LOCALHOST, 636 self.l2tp.hostname), 637 "ipsec pki --gen %s %s --outform der > clientKey.der" % (size, rsa), 638 "ipsec pki --pub --in clientKey.der %s | ipsec pki --issue %s " 639 r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s@%s\" " 640 r"--san \"%s\" --san \"%s@%s\" --san \"%s@%s\" --outform der " 641 "> clientCert.der" % (rsa, lifetime, country, org, self.l2tp.username, 642 self.l2tp.hostname, self.l2tp.username, 643 self.l2tp.username, LOCALHOST, 644 self.l2tp.username, self.l2tp.hostname), 645 "openssl rsa -inform DER -in clientKey.der " 646 "-out clientKey.pem -outform PEM", 647 "openssl x509 -inform DER -in clientCert.der " 648 "-out clientCert.pem -outform PEM", 649 "openssl x509 -inform DER -in caCert.der " 650 "-out caCert.pem -outform PEM", 651 "openssl pkcs12 -in clientCert.pem -inkey clientKey.pem " 652 "-certfile caCert.pem -export -out clientPkcs.p12 -passout pass:", 653 "mv caCert.pem /etc/ipsec.d/cacerts/", 654 "mv *Cert* /etc/ipsec.d/certs/", 655 "mv *Key* /etc/ipsec.d/private/", 656 "mv clientPkcs.p12 /www/downloads/", 657 "chmod 664 /www/downloads/clientPkcs.p12", 658 ] 659 file_string = "\n".join(ikev2_vpn_cert_keys) 660 self.create_config_file(file_string, IKEV2_VPN_CERT_KEYS_PATH) 661 662 self.ssh.run("chmod +x %s" % IKEV2_VPN_CERT_KEYS_PATH) 663 self.ssh.run("%s" % IKEV2_VPN_CERT_KEYS_PATH) 664 665 def update_firewall_rules_list(self): 666 """Update rule list in /etc/config/firewall.""" 667 new_rules_list = [] 668 for i in range(self.count("firewall", "rule")): 669 rule = self.ssh.run("uci get firewall.@rule[%s].name" % i).stdout 670 new_rules_list.append(rule) 671 self.firewall_rules_list = new_rules_list 672 673 def setup_firewall_rules_for_pptp(self): 674 """Setup firewall for vpn pptp server.""" 675 self.update_firewall_rules_list() 676 if "pptpd" not in self.firewall_rules_list: 677 self.ssh.run("uci add firewall rule") 678 self.ssh.run("uci set firewall.@rule[-1].name='pptpd'") 679 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 680 self.ssh.run("uci set firewall.@rule[-1].proto='tcp'") 681 self.ssh.run("uci set firewall.@rule[-1].dest_port='1723'") 682 self.ssh.run("uci set firewall.@rule[-1].family='ipv4'") 683 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 684 685 if "GRP" not in self.firewall_rules_list: 686 self.ssh.run("uci add firewall rule") 687 self.ssh.run("uci set firewall.@rule[-1].name='GRP'") 688 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 689 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 690 self.ssh.run("uci set firewall.@rule[-1].proto='47'") 691 692 iptable_rules = list(network_const.FIREWALL_RULES_FOR_PPTP) 693 self.add_custom_firewall_rules(iptable_rules) 694 self.service_manager.need_restart(SERVICE_FIREWALL) 695 696 def restore_firewall_rules_for_pptp(self): 697 """Restore firewall for vpn pptp server.""" 698 self.update_firewall_rules_list() 699 if "pptpd" in self.firewall_rules_list: 700 self.ssh.run("uci del firewall.@rule[%s]" 701 % self.firewall_rules_list.index("pptpd")) 702 self.update_firewall_rules_list() 703 if "GRP" in self.firewall_rules_list: 704 self.ssh.run("uci del firewall.@rule[%s]" 705 % self.firewall_rules_list.index("GRP")) 706 self.remove_custom_firewall_rules() 707 self.service_manager.need_restart(SERVICE_FIREWALL) 708 709 def setup_firewall_rules_for_l2tp(self): 710 """Setup firewall for vpn l2tp server.""" 711 self.update_firewall_rules_list() 712 if "ipsec esp" not in self.firewall_rules_list: 713 self.ssh.run("uci add firewall rule") 714 self.ssh.run("uci set firewall.@rule[-1].name='ipsec esp'") 715 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 716 self.ssh.run("uci set firewall.@rule[-1].proto='esp'") 717 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 718 719 if "ipsec nat-t" not in self.firewall_rules_list: 720 self.ssh.run("uci add firewall rule") 721 self.ssh.run("uci set firewall.@rule[-1].name='ipsec nat-t'") 722 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 723 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 724 self.ssh.run("uci set firewall.@rule[-1].proto='udp'") 725 self.ssh.run("uci set firewall.@rule[-1].dest_port='4500'") 726 727 if "auth header" not in self.firewall_rules_list: 728 self.ssh.run("uci add firewall rule") 729 self.ssh.run("uci set firewall.@rule[-1].name='auth header'") 730 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 731 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 732 self.ssh.run("uci set firewall.@rule[-1].proto='ah'") 733 734 net_id = self.l2tp.address.rsplit(".", 1)[0] 735 iptable_rules = list(network_const.FIREWALL_RULES_FOR_L2TP) 736 iptable_rules.append("iptables -A FORWARD -s %s.0/24" 737 " -j ACCEPT" % net_id) 738 iptable_rules.append("iptables -t nat -A POSTROUTING" 739 " -s %s.0/24 -o eth0.2 -j MASQUERADE" % net_id) 740 741 self.add_custom_firewall_rules(iptable_rules) 742 self.service_manager.need_restart(SERVICE_FIREWALL) 743 744 def restore_firewall_rules_for_l2tp(self): 745 """Restore firewall for vpn l2tp server.""" 746 self.update_firewall_rules_list() 747 if "ipsec esp" in self.firewall_rules_list: 748 self.ssh.run("uci del firewall.@rule[%s]" 749 % self.firewall_rules_list.index("ipsec esp")) 750 self.update_firewall_rules_list() 751 if "ipsec nat-t" in self.firewall_rules_list: 752 self.ssh.run("uci del firewall.@rule[%s]" 753 % self.firewall_rules_list.index("ipsec nat-t")) 754 self.update_firewall_rules_list() 755 if "auth header" in self.firewall_rules_list: 756 self.ssh.run("uci del firewall.@rule[%s]" 757 % self.firewall_rules_list.index("auth header")) 758 self.remove_custom_firewall_rules() 759 self.service_manager.need_restart(SERVICE_FIREWALL) 760 761 def add_custom_firewall_rules(self, rules): 762 """Backup current custom rules and replace with arguments. 763 764 Args: 765 rules: A list of iptable rules to apply. 766 """ 767 backup_file_path = FIREWALL_CUSTOM_OPTION_PATH+".backup" 768 if not self.file_exists(backup_file_path): 769 self.ssh.run("mv %s %s" % (FIREWALL_CUSTOM_OPTION_PATH, 770 backup_file_path)) 771 for rule in rules: 772 self.ssh.run("echo %s >> %s" % (rule, FIREWALL_CUSTOM_OPTION_PATH)) 773 774 def remove_custom_firewall_rules(self): 775 """Clean up and recover custom firewall rules.""" 776 backup_file_path = FIREWALL_CUSTOM_OPTION_PATH+".backup" 777 if self.file_exists(backup_file_path): 778 self.ssh.run("mv %s %s" % (backup_file_path, 779 FIREWALL_CUSTOM_OPTION_PATH)) 780 else: 781 self.log.debug("Did not find %s" % backup_file_path) 782 self.ssh.run("echo "" > %s" % FIREWALL_CUSTOM_OPTION_PATH) 783 784 def disable_pptp_service(self): 785 """Disable pptp service.""" 786 self.package_remove(PPTP_PACKAGE) 787 788 def setup_vpn_local_ip(self): 789 """Setup VPN Server local ip on OpenWrt for client ping verify.""" 790 self.ssh.run("uci set network.lan2=interface") 791 self.ssh.run("uci set network.lan2.type=bridge") 792 self.ssh.run("uci set network.lan2.ifname=eth1.2") 793 self.ssh.run("uci set network.lan2.proto=static") 794 self.ssh.run("uci set network.lan2.ipaddr=\"%s\"" % self.l2tp.address) 795 self.ssh.run("uci set network.lan2.netmask=255.255.255.0") 796 self.ssh.run("uci set network.lan2=interface") 797 self.service_manager.reload(SERVICE_NETWORK) 798 self.commit_changes() 799 800 def remove_vpn_local_ip(self): 801 """Discard vpn local ip on OpenWrt.""" 802 self.ssh.run("uci delete network.lan2") 803 self.service_manager.reload(SERVICE_NETWORK) 804 self.commit_changes() 805 806 def enable_ipv6(self): 807 """Enable ipv6 on OpenWrt.""" 808 self.ssh.run("uci set network.lan.ipv6=1") 809 self.ssh.run("uci set network.wan.ipv6=1") 810 self.service_manager.enable("odhcpd") 811 self.service_manager.reload(SERVICE_NETWORK) 812 self.config.discard("disable_ipv6") 813 self.commit_changes() 814 815 def disable_ipv6(self): 816 """Disable ipv6 on OpenWrt.""" 817 self.config.add("disable_ipv6") 818 self.ssh.run("uci set network.lan.ipv6=0") 819 self.ssh.run("uci set network.wan.ipv6=0") 820 self.service_manager.disable("odhcpd") 821 self.service_manager.reload(SERVICE_NETWORK) 822 self.commit_changes() 823 824 def setup_ipv6_bridge(self): 825 """Setup ipv6 bridge for client have ability to access network.""" 826 self.config.add("setup_ipv6_bridge") 827 828 self.ssh.run("uci set dhcp.lan.dhcpv6=relay") 829 self.ssh.run("uci set dhcp.lan.ra=relay") 830 self.ssh.run("uci set dhcp.lan.ndp=relay") 831 832 self.ssh.run("uci set dhcp.wan6=dhcp") 833 self.ssh.run("uci set dhcp.wan6.dhcpv6=relay") 834 self.ssh.run("uci set dhcp.wan6.ra=relay") 835 self.ssh.run("uci set dhcp.wan6.ndp=relay") 836 self.ssh.run("uci set dhcp.wan6.master=1") 837 self.ssh.run("uci set dhcp.wan6.interface=wan6") 838 839 # Enable service 840 self.service_manager.need_restart(SERVICE_ODHCPD) 841 self.commit_changes() 842 843 def remove_ipv6_bridge(self): 844 """Discard ipv6 bridge on OpenWrt.""" 845 if "setup_ipv6_bridge" in self.config: 846 self.config.discard("setup_ipv6_bridge") 847 848 self.ssh.run("uci set dhcp.lan.dhcpv6=server") 849 self.ssh.run("uci set dhcp.lan.ra=server") 850 self.ssh.run("uci delete dhcp.lan.ndp") 851 852 self.ssh.run("uci delete dhcp.wan6") 853 854 self.service_manager.need_restart(SERVICE_ODHCPD) 855 self.commit_changes() 856 857 def _add_dhcp_option(self, args): 858 self.ssh.run("uci add_list dhcp.lan.dhcp_option=\"%s\"" % args) 859 860 def _remove_dhcp_option(self, args): 861 self.ssh.run("uci del_list dhcp.lan.dhcp_option=\"%s\"" % args) 862 863 def add_default_dns(self, addr_list): 864 """Add default dns server for client. 865 866 Args: 867 addr_list: dns ip address for Openwrt client. 868 """ 869 self._add_dhcp_option("6,%s" % ",".join(addr_list)) 870 self.config.add("default_dns %s" % addr_list) 871 self.service_manager.need_restart(SERVICE_DNSMASQ) 872 self.commit_changes() 873 874 def del_default_dns(self, addr_list): 875 """Remove default dns server for client. 876 877 Args: 878 addr_list: list of dns ip address for Openwrt client. 879 """ 880 self._remove_dhcp_option("6,%s" % addr_list) 881 self.config.discard("default_dns %s" % addr_list) 882 self.service_manager.need_restart(SERVICE_DNSMASQ) 883 self.commit_changes() 884 885 def add_default_v6_dns(self, addr_list): 886 """Add default v6 dns server for client. 887 888 Args: 889 addr_list: dns ip address for Openwrt client. 890 """ 891 self.ssh.run("uci add_list dhcp.lan.dns=\"%s\"" % addr_list) 892 self.config.add("default_v6_dns %s" % addr_list) 893 self.service_manager.need_restart(SERVICE_ODHCPD) 894 self.commit_changes() 895 896 def del_default_v6_dns(self, addr_list): 897 """Del default v6 dns server for client. 898 899 Args: 900 addr_list: dns ip address for Openwrt client. 901 """ 902 self.ssh.run("uci del_list dhcp.lan.dns=\"%s\"" % addr_list) 903 self.config.add("default_v6_dns %s" % addr_list) 904 self.service_manager.need_restart(SERVICE_ODHCPD) 905 self.commit_changes() 906 907 def add_ipv6_prefer_option(self): 908 self._add_dhcp_option("108,1800i") 909 self.config.add("ipv6_prefer_option") 910 self.service_manager.need_restart(SERVICE_DNSMASQ) 911 self.commit_changes() 912 913 def remove_ipv6_prefer_option(self): 914 self._remove_dhcp_option("108,1800i") 915 self.config.discard("ipv6_prefer_option") 916 self.service_manager.need_restart(SERVICE_DNSMASQ) 917 self.commit_changes() 918 919 def add_dhcp_rapid_commit(self): 920 self.create_config_file("dhcp-rapid-commit\n","/etc/dnsmasq.conf") 921 self.config.add("add_dhcp_rapid_commit") 922 self.service_manager.need_restart(SERVICE_DNSMASQ) 923 self.commit_changes() 924 925 def remove_dhcp_rapid_commit(self): 926 self.create_config_file("","/etc/dnsmasq.conf") 927 self.config.discard("add_dhcp_rapid_commit") 928 self.service_manager.need_restart(SERVICE_DNSMASQ) 929 self.commit_changes() 930 931 def start_tcpdump(self, test_name, args="", interface="br-lan"): 932 """"Start tcpdump on OpenWrt. 933 934 Args: 935 test_name: Test name for create tcpdump file name. 936 args: Option args for tcpdump. 937 interface: Interface to logging. 938 Returns: 939 tcpdump_file_name: tcpdump file name on OpenWrt. 940 pid: tcpdump process id. 941 """ 942 self.package_install("tcpdump") 943 if not self.path_exists(TCPDUMP_DIR): 944 self.ssh.run("mkdir %s" % TCPDUMP_DIR) 945 tcpdump_file_name = "openwrt_%s_%s.pcap" % (test_name, 946 time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time()))) 947 tcpdump_file_path = "".join([TCPDUMP_DIR, tcpdump_file_name]) 948 cmd = "tcpdump -i %s -s0 %s -w %s" % (interface, args, tcpdump_file_path) 949 self.ssh.run_async(cmd) 950 pid = self._get_tcpdump_pid(tcpdump_file_name) 951 if not pid: 952 raise signals.TestFailure("Fail to start tcpdump on OpenWrt.") 953 # Set delay to prevent tcpdump fail to capture target packet. 954 time.sleep(15) 955 return tcpdump_file_name 956 957 def stop_tcpdump(self, tcpdump_file_name, pull_dir=None): 958 """Stop tcpdump on OpenWrt and pull the pcap file. 959 960 Args: 961 tcpdump_file_name: tcpdump file name on OpenWrt. 962 pull_dir: Keep none if no need to pull. 963 Returns: 964 tcpdump abs_path on host. 965 """ 966 # Set delay to prevent tcpdump fail to capture target packet. 967 time.sleep(15) 968 pid = self._get_tcpdump_pid(tcpdump_file_name) 969 self.ssh.run("kill -9 %s" % pid, ignore_status=True) 970 if self.path_exists(TCPDUMP_DIR) and pull_dir: 971 tcpdump_path = "".join([TCPDUMP_DIR, tcpdump_file_name]) 972 tcpdump_remote_path = "/".join([pull_dir, tcpdump_file_name]) 973 tcpdump_local_path = "%s@%s:%s" % (self.user, self.ip, tcpdump_path) 974 utils.exe_cmd("scp %s %s" % (tcpdump_local_path, tcpdump_remote_path)) 975 976 if self._get_tcpdump_pid(tcpdump_file_name): 977 raise signals.TestFailure("Failed to stop tcpdump on OpenWrt.") 978 if self.file_exists(tcpdump_path): 979 self.ssh.run("rm -f %s" % tcpdump_path) 980 return tcpdump_remote_path if pull_dir else None 981 982 def clear_tcpdump(self): 983 self.ssh.run("killall tcpdump", ignore_status=True) 984 if self.ssh.run("pgrep tcpdump", ignore_status=True).stdout: 985 raise signals.TestFailure("Failed to clean up tcpdump process.") 986 if self.path_exists(TCPDUMP_DIR): 987 self.ssh.run("rm -f %s/*" % TCPDUMP_DIR) 988 989 def _get_tcpdump_pid(self, tcpdump_file_name): 990 """Check tcpdump process on OpenWrt.""" 991 return self.ssh.run("pgrep -f %s" % (tcpdump_file_name), ignore_status=True).stdout 992 993 def setup_mdns(self): 994 self.config.add("setup_mdns") 995 self.package_install(MDNS_PACKAGE) 996 self.commit_changes() 997 998 def remove_mdns(self): 999 self.config.discard("setup_mdns") 1000 self.package_remove(MDNS_PACKAGE) 1001 self.commit_changes() 1002 1003 def block_dns_response(self): 1004 self.config.add("block_dns_response") 1005 iptable_rules = list(network_const.FIREWALL_RULES_DISABLE_DNS_RESPONSE) 1006 self.add_custom_firewall_rules(iptable_rules) 1007 self.service_manager.need_restart(SERVICE_FIREWALL) 1008 self.commit_changes() 1009 1010 def unblock_dns_response(self): 1011 self.config.discard("block_dns_response") 1012 self.remove_custom_firewall_rules() 1013 self.service_manager.need_restart(SERVICE_FIREWALL) 1014 self.commit_changes() 1015 1016 def setup_captive_portal(self, fas_fdqn,fas_port=2080): 1017 """Create captive portal with Forwarding Authentication Service. 1018 1019 Args: 1020 fas_fdqn: String for captive portal page's fdqn add to local dns server. 1021 fas_port: Port for captive portal page. 1022 """ 1023 self.package_install(CAPTIVE_PORTAL_PACKAGE) 1024 self.config.add("setup_captive_portal %s" % fas_port) 1025 self.ssh.run("uci set opennds.@opennds[0].fas_secure_enabled=2") 1026 self.ssh.run("uci set opennds.@opennds[0].gatewayport=2050") 1027 self.ssh.run("uci set opennds.@opennds[0].fasport=%s" % fas_port) 1028 self.ssh.run("uci set opennds.@opennds[0].fasremotefqdn=%s" % fas_fdqn) 1029 self.ssh.run("uci set opennds.@opennds[0].faspath=\"/nds/fas-aes.php\"") 1030 self.ssh.run("uci set opennds.@opennds[0].faskey=1234567890") 1031 self.service_manager.need_restart(SERVICE_OPENNDS) 1032 # Config uhttpd 1033 self.ssh.run("uci set uhttpd.main.interpreter=.php=/usr/bin/php-cgi") 1034 self.ssh.run("uci add_list uhttpd.main.listen_http=0.0.0.0:%s" % fas_port) 1035 self.ssh.run("uci add_list uhttpd.main.listen_http=[::]:%s" % fas_port) 1036 self.service_manager.need_restart(SERVICE_UHTTPD) 1037 # cp fas-aes.php 1038 self.create_folder("/www/nds/") 1039 self.ssh.run("cp /etc/opennds/fas-aes.php /www/nds") 1040 # Add fdqn 1041 self.add_resource_record(fas_fdqn, LOCALHOST) 1042 self.commit_changes() 1043 1044 def remove_cpative_portal(self, fas_port=2080): 1045 """Remove captive portal. 1046 1047 Args: 1048 fas_port: Port for captive portal page. 1049 """ 1050 # Remove package 1051 self.package_remove(CAPTIVE_PORTAL_PACKAGE) 1052 # Clean up config 1053 self.ssh.run("rm /etc/config/opennds") 1054 # Remove fdqn 1055 self.clear_resource_record() 1056 # Restore uhttpd 1057 self.ssh.run("uci del uhttpd.main.interpreter") 1058 self.ssh.run("uci del_list uhttpd.main.listen_http=\'0.0.0.0:%s\'" % fas_port) 1059 self.ssh.run("uci del_list uhttpd.main.listen_http=\'[::]:%s\'" % fas_port) 1060 self.service_manager.need_restart(SERVICE_UHTTPD) 1061 # Clean web root 1062 self.ssh.run("rm -r /www/nds") 1063 self.config.discard("setup_captive_portal %s" % fas_port) 1064 self.commit_changes() 1065 1066 1067class ServiceManager(object): 1068 """Class for service on OpenWrt. 1069 1070 Attributes: 1071 ssh: ssh object for the AP. 1072 _need_restart: Record service need to restart. 1073 """ 1074 1075 def __init__(self, ssh): 1076 self.ssh = ssh 1077 self._need_restart = set() 1078 1079 def enable(self, service_name): 1080 """Enable service auto start.""" 1081 self.ssh.run("/etc/init.d/%s enable" % service_name) 1082 1083 def disable(self, service_name): 1084 """Disable service auto start.""" 1085 self.ssh.run("/etc/init.d/%s disable" % service_name) 1086 1087 def restart(self, service_name): 1088 """Restart the service.""" 1089 self.ssh.run("/etc/init.d/%s restart" % service_name) 1090 1091 def reload(self, service_name): 1092 """Restart the service.""" 1093 self.ssh.run("/etc/init.d/%s reload" % service_name) 1094 1095 def restart_services(self): 1096 """Restart all services need to restart.""" 1097 for service in self._need_restart: 1098 if service == SERVICE_NETWORK: 1099 self.reload(service) 1100 self.restart(service) 1101 self._need_restart = set() 1102 1103 def stop(self, service_name): 1104 """Stop the service.""" 1105 self.ssh.run("/etc/init.d/%s stop" % service_name) 1106 1107 def need_restart(self, service_name): 1108 self._need_restart.add(service_name) 1109