• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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