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 16from acts.controllers.openwrt_lib import network_const 17 18SERVICE_DNSMASQ = "dnsmasq" 19SERVICE_STUNNEL = "stunnel" 20SERVICE_NETWORK = "network" 21SERVICE_PPTPD = "pptpd" 22SERVICE_FIREWALL = "firewall" 23SERVICE_IPSEC = "ipsec" 24SERVICE_XL2TPD = "xl2tpd" 25PPTP_PACKAGE = "pptpd kmod-nf-nathelper-extra" 26L2TP_PACKAGE = "strongswan-full openssl-util xl2tpd" 27STUNNEL_CONFIG_PATH = "/etc/stunnel/DoTServer.conf" 28HISTORY_CONFIG_PATH = "/etc/dirty_configs" 29PPTPD_OPTION_PATH = "/etc/ppp/options.pptpd" 30XL2TPD_CONFIG_PATH = "/etc/xl2tpd/xl2tpd.conf" 31XL2TPD_OPTION_CONFIG_PATH = "/etc/ppp/options.xl2tpd" 32FIREWALL_CUSTOM_OPTION_PATH = "/etc/firewall.user" 33PPP_CHAP_SECRET_PATH = "/etc/ppp/chap-secrets" 34LOCALHOST = "192.168.1.1" 35DEFAULT_PACKAGE_INSTALL_TIMEOUT = 200 36 37 38class NetworkSettings(object): 39 """Class for network settings. 40 41 Attributes: 42 ssh: ssh connection object. 43 service_manager: Object manage service configuration 44 ip: ip address for AccessPoint. 45 log: Logging object for AccessPoint. 46 config: A list to store changes on network settings. 47 firewall_rules_list: A list of firewall rule name list 48 cleanup_map: A dict for compare oppo functions. 49 l2tp: profile for vpn l2tp server. 50 """ 51 52 def __init__(self, ssh, ip, logger): 53 """Initialize wireless settings. 54 55 Args: 56 ssh: ssh connection object. 57 ip: ip address for AccessPoint. 58 logger: Logging object for AccessPoint. 59 """ 60 self.ssh = ssh 61 self.service_manager = ServiceManager(ssh) 62 self.ip = ip 63 self.log = logger 64 self.config = set() 65 self.firewall_rules_list = [] 66 self.cleanup_map = { 67 "setup_dns_server": self.remove_dns_server, 68 "setup_vpn_pptp_server": self.remove_vpn_pptp_server, 69 "setup_vpn_l2tp_server": self.remove_vpn_l2tp_server, 70 "disable_ipv6": self.enable_ipv6 71 } 72 # This map contains cleanup functions to restore the configuration to 73 # its default state. We write these keys to HISTORY_CONFIG_PATH prior to 74 # making any changes to that subsystem. 75 # This makes it easier to recover after an aborted test. 76 self.update_firewall_rules_list() 77 self.cleanup_network_settings() 78 79 def cleanup_network_settings(self): 80 """Reset all changes on Access point.""" 81 82 # Detect if any changes that is not clean up. 83 if self.file_exists(HISTORY_CONFIG_PATH): 84 out = self.ssh.run("cat %s" % HISTORY_CONFIG_PATH).stdout 85 if out: 86 self.config = set(out.split("\n")) 87 88 if self.config: 89 temp = self.config.copy() 90 for change in temp: 91 self.cleanup_map[change]() 92 self.config = set() 93 94 if self.file_exists(HISTORY_CONFIG_PATH): 95 out = self.ssh.run("cat %s" % HISTORY_CONFIG_PATH).stdout 96 if not out: 97 self.ssh.run("rm %s" % HISTORY_CONFIG_PATH) 98 99 def commit_changes(self): 100 """Apply changes on Access point.""" 101 self.ssh.run("uci commit") 102 self.service_manager.restart_services() 103 self.create_config_file("\n".join(self.config), 104 HISTORY_CONFIG_PATH) 105 106 def package_install(self, package_list): 107 """Install packages on OpenWrtAP via opkg If not installed. 108 109 Args: 110 package_list: package list to install. 111 e.g. "pptpd kmod-mppe kmod-nf-nathelper-extra" 112 """ 113 self.ssh.run("opkg update") 114 for package_name in package_list.split(" "): 115 if not self._package_installed(package_name): 116 self.ssh.run("opkg install %s" % package_name, 117 timeout=DEFAULT_PACKAGE_INSTALL_TIMEOUT) 118 self.log.info("Package: %s installed." % package_name) 119 else: 120 self.log.info("Package: %s skipped (already installed)." % package_name) 121 122 def package_remove(self, package_list): 123 """Remove packages on OpenWrtAP via opkg If existed. 124 125 Args: 126 package_list: package list to remove. 127 """ 128 for package_name in package_list.split(" "): 129 if self._package_installed(package_name): 130 self.ssh.run("opkg remove %s" % package_name) 131 self.log.info("Package: %s removed." % package_name) 132 else: 133 self.log.info("No exist package %s found." % package_name) 134 135 def _package_installed(self, package_name): 136 """Check if target package installed on OpenWrtAP. 137 138 Args: 139 package_name: package name want to check. 140 141 Returns: 142 True if installed. 143 """ 144 if self.ssh.run("opkg list-installed %s" % package_name).stdout: 145 return True 146 return False 147 148 def file_exists(self, abs_file_path): 149 """Check if target file exist on specific path on OpenWrt. 150 151 Args: 152 abs_file_path: Absolute path for the file. 153 154 Returns: 155 True if Existed. 156 """ 157 path, file_name = abs_file_path.rsplit("/", 1) 158 if self.ssh.run("ls %s | grep %s" % (path, file_name), 159 ignore_status=True).stdout: 160 return True 161 return False 162 163 def path_exists(self, abs_path): 164 """Check if dir exist on OpenWrt.""" 165 try: 166 self.ssh.run("ls %s" % abs_path) 167 except: 168 return False 169 return True 170 171 def count(self, config, key): 172 """Count in uci config. 173 174 Args: 175 config: config or section to research 176 key: keywords to e.g. rule, domain 177 Returns: 178 Numbers of the count. 179 """ 180 count = self.ssh.run("uci show %s | grep =%s" % (config, key), 181 ignore_status=True).stdout 182 return len(count.split("\n")) 183 184 def create_config_file(self, config, file_path): 185 """Create config file. Overwrite if file already exist. 186 187 Args: 188 config: A string of content of config. 189 file_path: Config's abs_path. 190 """ 191 self.ssh.run("echo -e \"%s\" > %s" % (config, file_path)) 192 193 def replace_config_option(self, old_option, new_option, file_path): 194 """Replace config option if pattern match. 195 196 If find match pattern with old_option, then replace it with new_option. 197 Else add new_option to the file. 198 199 Args: 200 old_option: the regexp pattern to replace. 201 new_option: the option to add. 202 file_path: Config's abs_path. 203 """ 204 config = self.ssh.run("cat %s" % file_path).stdout 205 config, count = re.subn(old_option, new_option, config) 206 if not count: 207 config = "\n".join([config, new_option]) 208 self.create_config_file(config, file_path) 209 210 def remove_config_option(self, option, file_path): 211 """Remove option from config file. 212 213 Args: 214 option: Option to remove. Support regular expression. 215 file_path: Config's abs_path. 216 Returns: 217 Boolean for find option to remove. 218 """ 219 config = self.ssh.run("cat %s" % file_path).stdout.split("\n") 220 for line in config: 221 count = re.subn(option, "", line)[1] 222 if count > 0: 223 config.remove(line) 224 self.create_config_file("\n".join(config), file_path) 225 return True 226 self.log.warning("No match option to remove.") 227 return False 228 229 def setup_dns_server(self, domain_name): 230 """Setup DNS server on OpenWrtAP. 231 232 Args: 233 domain_name: Local dns domain name. 234 """ 235 self.config.add("setup_dns_server") 236 self.log.info("Setup DNS server with domain name %s" % domain_name) 237 self.ssh.run("uci set dhcp.@dnsmasq[0].local='/%s/'" % domain_name) 238 self.ssh.run("uci set dhcp.@dnsmasq[0].domain='%s'" % domain_name) 239 self.add_resource_record(domain_name, self.ip) 240 self.service_manager.need_restart(SERVICE_DNSMASQ) 241 self.commit_changes() 242 243 # Check stunnel package is installed 244 self.package_install("stunnel") 245 self.service_manager.stop(SERVICE_STUNNEL) 246 self.service_manager.disable(SERVICE_STUNNEL) 247 248 # Enable stunnel 249 self.create_stunnel_config() 250 self.ssh.run("stunnel /etc/stunnel/DoTServer.conf") 251 252 def remove_dns_server(self): 253 """Remove DNS server on OpenWrtAP.""" 254 if self.file_exists("/var/run/stunnel.pid"): 255 self.ssh.run("kill $(cat /var/run/stunnel.pid)") 256 self.ssh.run("uci set dhcp.@dnsmasq[0].local='/lan/'") 257 self.ssh.run("uci set dhcp.@dnsmasq[0].domain='lan'") 258 self.clear_resource_record() 259 self.service_manager.need_restart(SERVICE_DNSMASQ) 260 self.config.discard("setup_dns_server") 261 self.commit_changes() 262 263 def add_resource_record(self, domain_name, domain_ip): 264 """Add resource record. 265 266 Args: 267 domain_name: A string for domain name. 268 domain_ip: A string for domain ip. 269 """ 270 self.ssh.run("uci add dhcp domain") 271 self.ssh.run("uci set dhcp.@domain[-1].name='%s'" % domain_name) 272 self.ssh.run("uci set dhcp.@domain[-1].ip='%s'" % domain_ip) 273 self.service_manager.need_restart(SERVICE_DNSMASQ) 274 275 def del_resource_record(self): 276 """Delete the last resource record.""" 277 self.ssh.run("uci delete dhcp.@domain[-1]") 278 self.service_manager.need_restart(SERVICE_DNSMASQ) 279 280 def clear_resource_record(self): 281 """Delete the all resource record.""" 282 rr = self.ssh.run("uci show dhcp | grep =domain", 283 ignore_status=True).stdout 284 if rr: 285 for _ in rr.split("\n"): 286 self.del_resource_record() 287 self.service_manager.need_restart(SERVICE_DNSMASQ) 288 289 def create_stunnel_config(self): 290 """Create config for stunnel service.""" 291 stunnel_config = [ 292 "pid = /var/run/stunnel.pid", 293 "[dns]", 294 "accept = 853", 295 "connect = 127.0.0.1:53", 296 "cert = /etc/stunnel/fullchain.pem", 297 "key = /etc/stunnel/privkey.pem", 298 ] 299 config_string = "\n".join(stunnel_config) 300 self.create_config_file(config_string, STUNNEL_CONFIG_PATH) 301 302 def setup_vpn_pptp_server(self, local_ip, user, password): 303 """Setup pptp vpn server on OpenWrt. 304 305 Args: 306 local_ip: local pptp server ip address. 307 user: username for pptp user. 308 password: password for pptp user. 309 """ 310 # Install pptp service 311 self.package_install(PPTP_PACKAGE) 312 313 self.config.add("setup_vpn_pptp_server") 314 # Edit /etc/config/pptpd & /etc/ppp/options.pptpd 315 self.setup_pptpd(local_ip, user, password) 316 # Edit /etc/config/firewall & /etc/firewall.user 317 self.setup_firewall_rules_for_pptp() 318 # Enable service 319 self.service_manager.enable(SERVICE_PPTPD) 320 self.service_manager.need_restart(SERVICE_PPTPD) 321 self.service_manager.need_restart(SERVICE_FIREWALL) 322 self.commit_changes() 323 324 def remove_vpn_pptp_server(self): 325 """Remove pptp vpn server on OpenWrt.""" 326 # Edit /etc/config/pptpd 327 self.restore_pptpd() 328 # Edit /etc/config/firewall & /etc/firewall.user 329 self.restore_firewall_rules_for_pptp() 330 # Disable service 331 self.service_manager.disable(SERVICE_PPTPD) 332 self.service_manager.need_restart(SERVICE_PPTPD) 333 self.service_manager.need_restart(SERVICE_FIREWALL) 334 self.config.discard("setup_vpn_pptp_server") 335 self.commit_changes() 336 337 self.package_remove(PPTP_PACKAGE) 338 self.ssh.run("rm /etc/ppp/options.pptpd") 339 self.ssh.run("rm /etc/config/pptpd") 340 341 def setup_pptpd(self, local_ip, username, password, ms_dns="8.8.8.8"): 342 """Setup pptpd config for ip addr and account. 343 344 Args: 345 local_ip: vpn server address 346 username: pptp vpn username 347 password: pptp vpn password 348 ms_dns: DNS server 349 """ 350 # Calculate remote ip address 351 # e.g. local_ip = 10.10.10.9 352 # remote_ip = 10.10.10.10 -250 353 remote_ip = local_ip.split(".") 354 remote_ip.append(str(int(remote_ip.pop(-1)) + 1)) 355 remote_ip = ".".join(remote_ip) 356 # Enable pptp service and set ip addr 357 self.ssh.run("uci set pptpd.pptpd.enabled=1") 358 self.ssh.run("uci set pptpd.pptpd.localip='%s'" % local_ip) 359 self.ssh.run("uci set pptpd.pptpd.remoteip='%s-250'" % remote_ip) 360 361 # Setup pptp service account 362 self.ssh.run("uci set pptpd.@login[0].username='%s'" % username) 363 self.ssh.run("uci set pptpd.@login[0].password='%s'" % password) 364 self.service_manager.need_restart(SERVICE_PPTPD) 365 366 self.replace_config_option(r"#*ms-dns \d+.\d+.\d+.\d+", 367 "ms-dns %s" % ms_dns, PPTPD_OPTION_PATH) 368 self.replace_config_option("(#no)*proxyarp", 369 "proxyarp", PPTPD_OPTION_PATH) 370 371 def restore_pptpd(self): 372 """Disable pptpd.""" 373 self.ssh.run("uci set pptpd.pptpd.enabled=0") 374 self.remove_config_option(r"\S+ pptp-server \S+ \*", 375 PPP_CHAP_SECRET_PATH) 376 self.service_manager.need_restart(SERVICE_PPTPD) 377 378 def setup_vpn_l2tp_server(self, 379 vpn_server_hostname, 380 vpn_server_address, 381 vpn_username, 382 vpn_password, 383 psk_secret, 384 server_name, 385 country, 386 org): 387 """Setup l2tp vpn server on OpenWrt. 388 389 Args: 390 vpn_server_hostname: vpn server domain name 391 vpn_server_address: vpn server addr 392 vpn_username: vpn account 393 vpn_password: vpn password 394 psk_secret: psk for ipsec 395 server_name: vpn server name for register in OpenWrt 396 country: country code for generate cert keys. 397 org: Organization name for generate cert keys. 398 """ 399 self.l2tp = network_const.VpnL2tp(vpn_server_hostname, 400 vpn_server_address, 401 vpn_username, 402 vpn_password, 403 psk_secret, 404 server_name) 405 406 self.package_install(L2TP_PACKAGE) 407 self.config.add("setup_vpn_l2tp_server") 408 409 # /etc/strongswan.conf: Strongswan configuration file 410 self.setup_strongswan() 411 # /etc/ipsec.conf /etc/ipsec.secrets 412 self.setup_ipsec() 413 # /etc/xl2tpd/xl2tpd.conf & /etc/ppp/options.xl2tpd 414 self.setup_xl2tpd() 415 # /etc/ppp/chap-secrets 416 self.setup_ppp_secret() 417 # /etc/config/firewall & /etc/firewall.user 418 self.setup_firewall_rules_for_l2tp() 419 # generate cert and key for rsa 420 self.generate_vpn_cert_keys(country, org) 421 # restart service 422 self.service_manager.need_restart(SERVICE_IPSEC) 423 self.service_manager.need_restart(SERVICE_XL2TPD) 424 self.service_manager.need_restart(SERVICE_FIREWALL) 425 self.commit_changes() 426 427 def remove_vpn_l2tp_server(self): 428 """Remove l2tp vpn server on OpenWrt.""" 429 self.config.discard("setup_vpn_l2tp_server") 430 self.restore_firewall_rules_for_l2tp() 431 self.service_manager.need_restart(SERVICE_IPSEC) 432 self.service_manager.need_restart(SERVICE_XL2TPD) 433 self.service_manager.need_restart(SERVICE_FIREWALL) 434 self.commit_changes() 435 self.package_remove(L2TP_PACKAGE) 436 if hasattr(self, "l2tp"): 437 delattr(self, "l2tp") 438 439 def setup_strongswan(self, dns="8.8.8.8"): 440 """Setup strongswan config.""" 441 config = [ 442 "charon {", 443 " load_modular = yes", 444 " plugins {", 445 " include strongswan.d/charon/*.conf", 446 " }", 447 " dns1=%s" % dns, 448 "}" 449 ] 450 self.create_config_file("\n".join(config), "/etc/strongswan.conf") 451 452 def setup_ipsec(self): 453 """Setup ipsec config.""" 454 def load_config(data): 455 for i in data.keys(): 456 config.append(i) 457 for j in data[i].keys(): 458 config.append("\t %s=%s" % (j, data[i][j])) 459 config.append("") 460 461 config = [] 462 load_config(network_const.IPSEC_CONF) 463 load_config(network_const.IPSEC_L2TP_PSK) 464 load_config(network_const.IPSEC_L2TP_RSA) 465 self.create_config_file("\n".join(config), "/etc/ipsec.conf") 466 467 ipsec_secret = [] 468 ipsec_secret.append(r": PSK \"%s\"" % self.l2tp.psk_secret) 469 ipsec_secret.append(r": RSA \"%s\"" % "serverKey.der") 470 self.create_config_file("\n".join(ipsec_secret), "/etc/ipsec.secrets") 471 472 def setup_xl2tpd(self, ip_range=20): 473 """Setup xl2tpd config.""" 474 net_id, host_id = self.l2tp.address.rsplit(".", 1) 475 xl2tpd_conf = network_const.XL2TPD_CONF_GLOBAL 476 xl2tpd_conf.append("auth file = %s" % PPP_CHAP_SECRET_PATH) 477 xl2tpd_conf.extend(network_const.XL2TPD_CONF_INS) 478 xl2tpd_conf.append("ip range = %s.%s-%s.%s" % 479 (net_id, host_id, net_id, 480 str(int(host_id)+ip_range))) 481 xl2tpd_conf.append("local ip = %s" % self.l2tp.address) 482 xl2tpd_conf.append("name = %s" % self.l2tp.name) 483 xl2tpd_conf.append("pppoptfile = %s" % XL2TPD_OPTION_CONFIG_PATH) 484 485 self.create_config_file("\n".join(xl2tpd_conf), XL2TPD_CONFIG_PATH) 486 xl2tpd_option = network_const.XL2TPD_OPTION 487 xl2tpd_option.append("name %s" % self.l2tp.name) 488 self.create_config_file("\n".join(xl2tpd_option), 489 XL2TPD_OPTION_CONFIG_PATH) 490 491 def setup_ppp_secret(self): 492 self.replace_config_option( 493 r"\S+ %s \S+ \*" % self.l2tp.name, 494 "%s %s %s *" % (self.l2tp.username, 495 self.l2tp.name, 496 self.l2tp.password), 497 PPP_CHAP_SECRET_PATH) 498 499 def generate_vpn_cert_keys(self, country, org): 500 """Generate cert and keys for vpn server.""" 501 rsa = "--type rsa" 502 lifetime = "--lifetime 365" 503 size = "--size 4096" 504 505 self.ssh.run("ipsec pki --gen %s %s --outform der > caKey.der" % 506 (rsa, size)) 507 self.ssh.run("ipsec pki --self --ca %s --in caKey.der %s --dn " 508 "\"C=%s, O=%s, CN=%s\" --outform der > caCert.der" % 509 (lifetime, rsa, country, org, self.l2tp.hostname)) 510 self.ssh.run("ipsec pki --gen %s %s --outform der > serverKey.der" % 511 (size, rsa)) 512 self.ssh.run("ipsec pki --pub --in serverKey.der %s | ipsec pki " 513 "--issue %s --cacert caCert.der --cakey caKey.der " 514 "--dn \"C=%s, O=%s, CN=%s\" --san %s --flag serverAuth" 515 " --flag ikeIntermediate --outform der > serverCert.der" % 516 (rsa, lifetime, country, org, self.l2tp.hostname, LOCALHOST)) 517 self.ssh.run("ipsec pki --gen %s %s --outform der > clientKey.der" % 518 (size, rsa)) 519 self.ssh.run("ipsec pki --pub --in clientKey.der %s | ipsec pki " 520 "--issue %s --cacert caCert.der --cakey caKey.der " 521 "--dn \"C=%s, O=%s, CN=%s@%s\" --outform der > " 522 "clientCert.der" % (rsa, lifetime, country, org, 523 self.l2tp.username, self.l2tp.hostname)) 524 525 self.ssh.run( 526 "openssl rsa -inform DER -in clientKey.der" 527 " -out clientKey.pem -outform PEM" 528 ) 529 self.ssh.run( 530 "openssl x509 -inform DER -in clientCert.der" 531 " -out clientCert.pem -outform PEM" 532 ) 533 self.ssh.run( 534 "openssl x509 -inform DER -in caCert.der" 535 " -out caCert.pem -outform PEM" 536 ) 537 self.ssh.run( 538 "openssl pkcs12 -in clientCert.pem -inkey clientKey.pem" 539 " -certfile caCert.pem -export -out clientPkcs.p12 -passout pass:" 540 ) 541 542 self.ssh.run("mv caCert.pem /etc/ipsec.d/cacerts/") 543 self.ssh.run("mv *Cert* /etc/ipsec.d/certs/") 544 self.ssh.run("mv *Key* /etc/ipsec.d/private/") 545 if not self.path_exists("/www/downloads/"): 546 self.ssh.run("mkdir /www/downloads/") 547 self.ssh.run("mv clientPkcs.p12 /www/downloads/") 548 self.ssh.run("chmod 664 /www/downloads/clientPkcs.p12") 549 550 def update_firewall_rules_list(self): 551 """Update rule list in /etc/config/firewall.""" 552 new_rules_list = [] 553 for i in range(self.count("firewall", "rule")): 554 rule = self.ssh.run("uci get firewall.@rule[%s].name" % i).stdout 555 new_rules_list.append(rule) 556 self.firewall_rules_list = new_rules_list 557 558 def setup_firewall_rules_for_pptp(self): 559 """Setup firewall for vpn pptp server.""" 560 self.update_firewall_rules_list() 561 if "pptpd" not in self.firewall_rules_list: 562 self.ssh.run("uci add firewall rule") 563 self.ssh.run("uci set firewall.@rule[-1].name='pptpd'") 564 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 565 self.ssh.run("uci set firewall.@rule[-1].proto='tcp'") 566 self.ssh.run("uci set firewall.@rule[-1].dest_port='1723'") 567 self.ssh.run("uci set firewall.@rule[-1].family='ipv4'") 568 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 569 570 if "GRP" not in self.firewall_rules_list: 571 self.ssh.run("uci add firewall rule") 572 self.ssh.run("uci set firewall.@rule[-1].name='GRP'") 573 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 574 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 575 self.ssh.run("uci set firewall.@rule[-1].proto='47'") 576 577 iptable_rules = network_const.FIREWALL_RULES_FOR_PPTP 578 self.add_custom_firewall_rules(iptable_rules) 579 self.service_manager.need_restart(SERVICE_FIREWALL) 580 581 def restore_firewall_rules_for_pptp(self): 582 """Restore firewall for vpn pptp server.""" 583 self.update_firewall_rules_list() 584 if "pptpd" in self.firewall_rules_list: 585 self.ssh.run("uci del firewall.@rule[%s]" 586 % self.firewall_rules_list.index("pptpd")) 587 self.update_firewall_rules_list() 588 if "GRP" in self.firewall_rules_list: 589 self.ssh.run("uci del firewall.@rule[%s]" 590 % self.firewall_rules_list.index("GRP")) 591 self.remove_custom_firewall_rules() 592 self.service_manager.need_restart(SERVICE_FIREWALL) 593 594 def setup_firewall_rules_for_l2tp(self): 595 """Setup firewall for vpn l2tp server.""" 596 self.update_firewall_rules_list() 597 if "ipsec esp" not in self.firewall_rules_list: 598 self.ssh.run("uci add firewall rule") 599 self.ssh.run("uci set firewall.@rule[-1].name='ipsec esp'") 600 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 601 self.ssh.run("uci set firewall.@rule[-1].proto='esp'") 602 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 603 604 if "ipsec nat-t" not in self.firewall_rules_list: 605 self.ssh.run("uci add firewall rule") 606 self.ssh.run("uci set firewall.@rule[-1].name='ipsec nat-t'") 607 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 608 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 609 self.ssh.run("uci set firewall.@rule[-1].proto='udp'") 610 self.ssh.run("uci set firewall.@rule[-1].dest_port='4500'") 611 612 if "auth header" not in self.firewall_rules_list: 613 self.ssh.run("uci add firewall rule") 614 self.ssh.run("uci set firewall.@rule[-1].name='auth header'") 615 self.ssh.run("uci set firewall.@rule[-1].target='ACCEPT'") 616 self.ssh.run("uci set firewall.@rule[-1].src='wan'") 617 self.ssh.run("uci set firewall.@rule[-1].proto='ah'") 618 619 net_id = self.l2tp.address.rsplit(".", 1)[0] 620 iptable_rules = network_const.FIREWALL_RULES_FOR_L2TP 621 iptable_rules.append("iptables -A FORWARD -s %s.0/24" 622 " -j ACCEPT" % net_id) 623 iptable_rules.append("iptables -t nat -A POSTROUTING" 624 " -s %s.0/24 -o eth0.2 -j MASQUERADE" % net_id) 625 626 self.add_custom_firewall_rules(iptable_rules) 627 self.service_manager.need_restart(SERVICE_FIREWALL) 628 629 def restore_firewall_rules_for_l2tp(self): 630 """Restore firewall for vpn l2tp server.""" 631 self.update_firewall_rules_list() 632 if "ipsec esp" in self.firewall_rules_list: 633 self.ssh.run("uci del firewall.@rule[%s]" 634 % self.firewall_rules_list.index("ipsec esp")) 635 self.update_firewall_rules_list() 636 if "ipsec nat-t" in self.firewall_rules_list: 637 self.ssh.run("uci del firewall.@rule[%s]" 638 % self.firewall_rules_list.index("ipsec nat-t")) 639 self.update_firewall_rules_list() 640 if "auth header" in self.firewall_rules_list: 641 self.ssh.run("uci del firewall.@rule[%s]" 642 % self.firewall_rules_list.index("auth header")) 643 self.remove_custom_firewall_rules() 644 self.service_manager.need_restart(SERVICE_FIREWALL) 645 646 def add_custom_firewall_rules(self, rules): 647 """Backup current custom rules and replace with arguments. 648 649 Args: 650 rules: A list of iptable rules to apply. 651 """ 652 backup_file_path = FIREWALL_CUSTOM_OPTION_PATH+".backup" 653 if not self.file_exists(backup_file_path): 654 self.ssh.run("mv %s %s" % (FIREWALL_CUSTOM_OPTION_PATH, 655 backup_file_path)) 656 for rule in rules: 657 self.ssh.run("echo %s >> %s" % (rule, FIREWALL_CUSTOM_OPTION_PATH)) 658 659 def remove_custom_firewall_rules(self): 660 """Clean up and recover custom firewall rules.""" 661 backup_file_path = FIREWALL_CUSTOM_OPTION_PATH+".backup" 662 if self.file_exists(backup_file_path): 663 self.ssh.run("mv %s %s" % (backup_file_path, 664 FIREWALL_CUSTOM_OPTION_PATH)) 665 else: 666 self.log.debug("Did not find %s" % backup_file_path) 667 self.ssh.run("echo "" > %s" % FIREWALL_CUSTOM_OPTION_PATH) 668 669 def disable_pptp_service(self): 670 """Disable pptp service.""" 671 self.package_remove(PPTP_PACKAGE) 672 673 def enable_ipv6(self): 674 """Enable ipv6 on OpenWrt.""" 675 self.ssh.run("uci set network.lan.ipv6=1") 676 self.ssh.run("uci set network.wan.ipv6=1") 677 self.service_manager.enable("odhcpd") 678 self.service_manager.reload(SERVICE_NETWORK) 679 self.config.discard("disable_ipv6") 680 self.commit_changes() 681 682 def disable_ipv6(self): 683 """Disable ipv6 on OpenWrt.""" 684 self.config.add("disable_ipv6") 685 self.ssh.run("uci set network.lan.ipv6=0") 686 self.ssh.run("uci set network.wan.ipv6=0") 687 self.service_manager.disable("odhcpd") 688 self.service_manager.reload(SERVICE_NETWORK) 689 self.commit_changes() 690 691 692class ServiceManager(object): 693 """Class for service on OpenWrt. 694 695 Attributes: 696 ssh: ssh object for the AP. 697 _need_restart: Record service need to restart. 698 """ 699 700 def __init__(self, ssh): 701 self.ssh = ssh 702 self._need_restart = set() 703 704 def enable(self, service_name): 705 """Enable service auto start.""" 706 self.ssh.run("/etc/init.d/%s enable" % service_name) 707 708 def disable(self, service_name): 709 """Disable service auto start.""" 710 self.ssh.run("/etc/init.d/%s disable" % service_name) 711 712 def restart(self, service_name): 713 """Restart the service.""" 714 self.ssh.run("/etc/init.d/%s restart" % service_name) 715 716 def reload(self, service_name): 717 """Restart the service.""" 718 self.ssh.run("/etc/init.d/%s reload" % service_name) 719 720 def restart_services(self): 721 """Restart all services need to restart.""" 722 for service in self._need_restart: 723 self.restart(service) 724 self._need_restart = set() 725 726 def stop(self, service_name): 727 """Stop the service.""" 728 self.ssh.run("/etc/init.d/%s stop" % service_name) 729 730 def need_restart(self, service_name): 731 self._need_restart.add(service_name) 732