Exemplo n.º 1
0
def update_config_files():
    root.verify_root_access("Root access needed to write files in " +
                            "'" + __basefilepath__ + "files/" + "'")
    try:
        subprocess.check_call(
            ["sudo", "wget", "https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip", "-P", __basefilepath__])
    except subprocess.CalledProcessError:
        print(
            Fore.RED + "Exception occured while wgetting zip, is the internet working? \
is nordcdn.com blocked by your ISP or Country?, If so use Privoxy \
[https://github.com/jotyGill/openpyn-nordvpn/issues/109]" + Style.RESET_ALL)
        sys.exit()
    try:
        subprocess.check_call(
            ["sudo", "unzip", "-u", "-o", __basefilepath__ + "ovpn", "-d", __basefilepath__ + "files/"],
            stderr=subprocess.DEVNULL)
        subprocess.check_call(
            ["sudo", "rm", __basefilepath__ + "ovpn.zip"])
    except subprocess.CalledProcessError:
        try:
            subprocess.check_call(
                ["sudo", "rm", "-rf", __basefilepath__ + "files/ovpn_udp"])
            subprocess.check_call(
                ["sudo", "rm", "-rf", __basefilepath__ + "files/ovpn_tcp"])
            subprocess.check_call(
                ["sudo", "unzip", __basefilepath__ + "ovpn", "-d", __basefilepath__ + "files/"])
            subprocess.check_call(
                ["sudo", "rm", __basefilepath__ + "ovpn.zip"])
        except subprocess.CalledProcessError:
            print(Fore.RED + "Exception occured while unzipping ovpn.zip, is unzip installed?" +
                  Style.RESET_ALL)
            sys.exit()
Exemplo n.º 2
0
def apply_fw_rules(interfaces_details, vpn_server_ip):
    root.verify_root_access("Root access needed to modify 'iptables' rules")

    # Empty the INPUT and OUTPUT chain of any current rules
    subprocess.run(["sudo", "iptables", "-F", "OUTPUT"])
    subprocess.run(["sudo", "iptables", "-F", "INPUT"])

    # Allow all traffic out over the vpn tunnel
    subprocess.run("sudo iptables -A OUTPUT -o tun+ -j ACCEPT", shell=True)
    # accept traffic that comes through tun that you connect to
    subprocess.run(
        "sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -i tun+ -j ACCEPT",
        shell=True)
    for interface in interfaces_details:

        # if interface is active with an IP in it, don't send DNS requests to it
        if len(interface) == 3 and "tun" not in interface[0]:
            subprocess.run([
                "sudo", "iptables", "-A", "OUTPUT", "-o", interface[0], "-p",
                "udp", "--destination-port", "53", "-j", "DROP"
            ])
            # subprocess.run(
            #     ["sudo", "iptables", "-A", "OUTPUT", "-o", interface[0], "-p",
            #         "tcp", "--destination-port", "53", "-j", "DROP"])
            if interface[0] != "lo":
                # allow access to vpn_server_ip
                subprocess.run([
                    "sudo", "iptables", "-A", "OUTPUT", "-o", interface[0],
                    "-d", vpn_server_ip, "-j", "ACCEPT"
                ])
                # talk to the vpnServer ip to connect to it
                subprocess.run([
                    "sudo", "iptables", "-A", "INPUT", "-m", "conntrack",
                    "--ctstate", "ESTABLISHED,RELATED", "-i", interface[0],
                    "-s", vpn_server_ip, "-j", "ACCEPT"
                ])

                # allow access to internal ip range
                # print("internal ip with range", interface[2])
                subprocess.run([
                    "sudo", "iptables", "-A", "OUTPUT", "-o", interface[0],
                    "-d", interface[2], "-j", "ACCEPT"
                ])
                subprocess.run([
                    "sudo", "iptables", "-A", "INPUT", "-m", "conntrack",
                    "--ctstate", "ESTABLISHED,RELATED", "-i", interface[0],
                    "-s", interface[2], "-j", "ACCEPT"
                ])

    # Allow loopback traffic
    subprocess.run("sudo iptables -A INPUT -i lo -j ACCEPT", shell=True)
    subprocess.run("sudo iptables -A OUTPUT -o lo -j ACCEPT", shell=True)

    # best practice, stops spoofing
    subprocess.run("sudo iptables -A INPUT -s 127.0.0.0/8 -j DROP", shell=True)

    # Default action if no other rules match
    subprocess.run("sudo iptables -P OUTPUT DROP", shell=True)
    subprocess.run("sudo iptables -P INPUT DROP", shell=True)
    return
Exemplo n.º 3
0
def kill_openpyn_process() -> None:
    try:
        root.verify_root_access("Root access needed to kill openpyn process")
        subprocess.call(["sudo", "killall", "openpyn"])
    except subprocess.CalledProcessError:
        # when Exception, the openvpn_processes issued non 0 result, "not found"
        pass
    return
Exemplo n.º 4
0
def kill_management_client():
    # kill the management client if it is for some reason still alive
    try:
        root.verify_root_access("Root access needed to kill 'openpyn-management' process")
        subprocess.check_output(["sudo", "killall", "openpyn-management"],
                                stderr=subprocess.DEVNULL)
    except subprocess.CalledProcessError:
        # when Exception, the openvpn_processes issued non 0 result, "not found"
        pass
    return
Exemplo n.º 5
0
def kill_vpn_processes():
    try:
        print("Killing any running openvpn processes")
        openvpn_processes = subprocess.check_output(["pgrep", "openvpn"])
        # When it returns "0", proceed
        root.verify_root_access("Root access needed to kill openvpn process")
        subprocess.run(["sudo", "killall", "openvpn"])
    except subprocess.CalledProcessError as ce:
        # when Exception, the openvpn_processes issued non 0 result, "not found"
        print("No openvpn process found")
        return
Exemplo n.º 6
0
def kill_vpn_processes() -> None:
    try:
        subprocess.check_output(["pgrep", "openvpn"])
        # When it returns "0", proceed
        root.verify_root_access("Root access needed to kill openvpn process")
        subprocess.call(["sudo", "killall", "openvpn"])
        logger.notice("Killing the running openvpn process")
        time.sleep(1)
    except subprocess.CalledProcessError:
        # when Exception, the openvpn_processes issued non 0 result, "not found"
        pass
    return
Exemplo n.º 7
0
def kill_management_client():
    # kill the management client if it is for some reason still alive
    try:
        openvpn_processes = subprocess.check_output(
            ["pgrep", "openpyn-management"])
        # When it returns "0", proceed
        root.verify_root_access(
            "Root access needed to kill 'openpyn-management' process")
        subprocess.call(["sudo", "killall", "openpyn-management"])
    except subprocess.CalledProcessError as ce:
        # when Exception, the openvpn_processes issued non 0 result, "not found"
        pass
    return
Exemplo n.º 8
0
def update_config_files():
    root.verify_root_access(
        "Root access needed to write files in '/usr/share/openpyn/files'")
    try:
        subprocess.check_call(
            "sudo wget -N https://nordvpn.com/api/files/zip -P /usr/share/openpyn/"
            .split())
        subprocess.check_call(
            "sudo unzip -u -o /usr/share/openpyn/zip -d /usr/share/openpyn/files/"
            .split())
        subprocess.check_call("sudo rm /usr/share/openpyn/zip".split())
    except subprocess.CalledProcessError:
        print("Exception occured while wgetting zip")
Exemplo n.º 9
0
def update_config_files():
    root.verify_root_access("Root access needed to write files in " + "'" +
                            __basefilepath__ + "files/" + "'")
    try:
        subprocess.check_call([
            "sudo", "wget",
            "https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip",
            "-P", __basefilepath__
        ])
        subprocess.check_call([
            "sudo", "unzip", "-u", "-o", __basefilepath__ + "ovpn", "-d",
            __basefilepath__ + "files/"
        ])
        subprocess.check_call(["sudo", "rm", __basefilepath__ + "ovpn.zip"])
    except subprocess.CalledProcessError:
        print("Exception occured while wgetting zip")
Exemplo n.º 10
0
def clear_fw_rules() -> None:
    root.verify_root_access("Root access needed to modify 'iptables' rules")
    logger.info("Flushing iptables INPUT and OUTPUT chains AND Applying default Rules")
    subprocess.call(["sudo", "iptables", "-F", "OUTPUT"])
    # allow all outgoing traffic
    subprocess.call("sudo iptables -P OUTPUT ACCEPT".split())

    subprocess.call(["sudo", "iptables", "-F", "INPUT"])
    subprocess.call(["sudo", "iptables", "-A", "INPUT", "-i", "lo", "-j", "ACCEPT"])
    subprocess.call(["sudo", "iptables", "-A", "OUTPUT", "-o", "lo", "-j", "ACCEPT"])
    subprocess.call(
        "sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT".split())
    # allow ICMP traffic
    subprocess.call("sudo iptables -A INPUT -p icmp --icmp-type any -j ACCEPT".split())
    # best practice, stops spoofing
    subprocess.call("sudo iptables -A INPUT -s 127.0.0.0/8 -j DROP".split())
    # drop anything else incoming
    subprocess.call("sudo iptables -P INPUT DROP".split())
    return
Exemplo n.º 11
0
def clear_fw_rules():
    root.verify_root_access("Root access needed to modify 'iptables' rules")
    print(
        "Flushing iptables INPUT and OUTPUT chains AND Applying default Rules")
    subprocess.run(["sudo", "iptables", "-F", "OUTPUT"])
    # allow all outgoing traffic
    subprocess.run("sudo iptables -P OUTPUT ACCEPT", shell=True)

    subprocess.run(["sudo", "iptables", "-F", "INPUT"])
    subprocess.run(
        ["sudo", "iptables", "-A", "INPUT", "-i", "lo", "-j", "ACCEPT"])
    subprocess.run(
        ["sudo", "iptables", "-A", "OUTPUT", "-o", "lo", "-j", "ACCEPT"])
    subprocess.run(
        "sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT",
        shell=True)
    # best practice, stops spoofing
    subprocess.run("sudo iptables -A INPUT -s 127.0.0.0/8 -j DROP", shell=True)
    # drop anything else incoming
    subprocess.run("sudo iptables -P INPUT DROP", shell=True)
    return
Exemplo n.º 12
0
def clear_fw_rules() -> None:
    root.verify_root_access("Root access needed to modify 'iptables' rules")
    logger.info(
        "Flushing iptables INPUT and OUTPUT chains AND Applying default Rules")

    subprocess.call(["sudo", "-u", sudo_user, "iptables", "-F", "OUTPUT"])

    # allow all outgoing traffic
    subprocess.call(
        ["sudo", "-u", sudo_user, "iptables", "-P", "OUTPUT", "ACCEPT"])

    subprocess.call(["sudo", "-u", sudo_user, "iptables", "-F", "INPUT"])
    subprocess.call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-i", "lo", "-j",
        "ACCEPT"
    ])
    subprocess.call([
        "sudo", "-u", sudo_user, "iptables", "-A", "OUTPUT", "-o", "lo", "-j",
        "ACCEPT"
    ])
    subprocess.call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-m", "conntrack",
        "--ctstate", "ESTABLISHED,RELATED", "-j", "ACCEPT"
    ])

    # allow ICMP traffic
    subprocess.call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-p", "icmp",
        "--icmp-type", "any", "-j", "ACCEPT"
    ])

    # best practice, stops spoofing
    subprocess.call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-s",
        "127.0.0.0/8", "-j", "DROP"
    ])

    # drop anything else incoming
    subprocess.call(
        ["sudo", "-u", sudo_user, "iptables", "-P", "INPUT", "DROP"])
Exemplo n.º 13
0
def run(init: bool, server: str, country_code: str, country: str, area: str, tcp: bool, daemon: bool,
        max_load: int, top_servers: int, pings: str, kill: bool, kill_flush: bool, update: bool, list_servers: bool,
        force_fw_rules: bool, p2p: bool, dedicated: bool, double_vpn: bool, tor_over_vpn: bool, anti_ddos: bool,
        netflix: bool, test: bool, internally_allowed: List, skip_dns_patch: bool, silent: bool, nvram: str,
        openvpn_options: str, location: float) -> bool:

    if init:
        initialise(log_folder)

    fieldstyles = {
        'asctime': {'color': 'green'},
        'hostname': {'color': 'magenta'},
        'levelname': {'color': 'black', 'bold': True},
        'name': {'color': 'blue'},
        'programname': {'color': 'cyan'},
    }
    levelstyles = {
        'spam': {'color': 'green', 'faint': True},
        'debug': {'color': 'green', 'bold': True},
        'verbose': {'color': 'blue', 'bold': True},
        'info': {},
        'notice': {'color': 'magenta', 'bold': True},
        'warning': {'color': 'yellow', 'bold': True},
        'success': {'color': 'green', 'bold': True},
        'error': {'color': 'red', 'bold': True},
        'critical': {'color': 'white', 'background': 'red', 'bold': True}
    }

    logger.addHandler(logging.StreamHandler())

    # if log folder doesnt exist, exit, "--init" creates it
    if not os.path.exists(log_folder):
        logger.error(
            "Please initialise first by running 'sudo openpyn --init', then start using 'openpyn' without sudo")
        return 1

    # Add another rotating handler to log to .log files
    # fix permissions if needed
    for attempt in range(2):
        try:
            file_handler = logging.handlers.TimedRotatingFileHandler(
                log_folder + '/openpyn.log', when='W0', interval=4)
            file_handler_formatter = logging.Formatter(log_format)
            file_handler.setFormatter(file_handler_formatter)
            logger.addHandler(file_handler)
        except PermissionError:
            root.verify_root_access(
                "Root access needed to set permissions of {}/openpyn.log".format(log_folder))
            subprocess.run("sudo chmod 777 {}/openpyn.log".format(log_folder).split())
            subprocess.run("sudo chmod 777 {}/openpyn-notifications.log".format(log_folder).split())
        else:
            break

    # In this case only log messages originating from this logger will show up on the terminal.
    coloredlogs.install(level="verbose", logger=logger, fmt=log_format,
                        level_styles=levelstyles, field_styles=fieldstyles)

    stats = True
    if sys.__stdin__.isatty():
        logger.debug("Interactive")
    else:
        logger.addHandler(logging.StreamHandler(sys.stdout))
        logger.setLevel(logging.WARNING)
        logger.debug("Non-Interactive")
        stats = False

    port = "udp"
    if tcp:
        port = "tcp"

    detected_os = sys.platform
    if detected_os == "linux":
        if subprocess.check_output(["/bin/uname", "-o"]).decode(sys.stdout.encoding).strip() == "ASUSWRT-Merlin":
            force_fw_rules = False
            silent = True
            skip_dns_patch = True
            if openvpn_options:
                openvpn_options += " " + "--syslog openpyn"
            else:
                openvpn_options = "--syslog openpyn"
            logger.debug(openvpn_options)
        elif os.path.exists("/etc/openwrt_release"):
            force_fw_rules = False
            silent = True
            skip_dns_patch = True
            nvram = None
        else:
            nvram = None
    elif detected_os == "win32":
        logger.error("Are you even a l33t mate? Try GNU/Linux")
        return 1

    # check if dependencies are installed
    if shutil.which("openvpn") is None or shutil.which("wget") is None or shutil.which("unzip") is None:
        # In case of Debian Sid where "openvpn" is only in root's PATH, don't error out
        try:
            root_access = root.verify_root_access(
                "Sudo credentials required to check if 'openvpn' is available in root's PATH")
            if root_access is False:
                root.obtain_root_access()
            subprocess.check_output(["sudo", "which", "wget"])
            subprocess.check_output(["sudo", "which", "unzip"])
            # subprocess.check_output(["sudo", "which", "openvpn"])
        except subprocess.CalledProcessError:
            logger.error("Please Install 'openvpn' 'wget' 'unzip' first")
            return 1

    elif daemon:
        if detected_os != "linux":
            logger.error("Daemon mode is only available in GNU/Linux distros")
            return 1

        if not root.verify_running_as_root():
            logger.error("Please run '--daemon' or '-d' mode with sudo")
            return 1
        openpyn_options = ""

        # if only positional argument used
        if country_code is None and server is None:
            country_code = country      # consider the positional arg e.g "us" same as "-c us"
        # if either "-c" or positional arg f.e "au" is present

        if country_code:
            if len(country_code) > 2:   # full country name
                # get the country_code from the full name
                country_code = api.get_country_code(full_name=country_code)
            country_code = country_code.lower()
            openpyn_options += country_code

        elif server:
            openpyn_options += " --server " + server

        if area:
            openpyn_options += " --area " + area
        if tcp:
            openpyn_options += " --tcp"
        if max_load:
            openpyn_options += " --max-load " + str(max_load)
        if top_servers:
            openpyn_options += " --top-servers " + str(top_servers)
        if pings:
            openpyn_options += " --pings " + str(pings)
        if force_fw_rules:
            openpyn_options += " --force-fw-rules"
        if p2p:
            openpyn_options += " --p2p"
        if dedicated:
            openpyn_options += " --dedicated"
        if double_vpn:
            openpyn_options += " --double"
        if tor_over_vpn:
            openpyn_options += " --tor"
        if anti_ddos:
            openpyn_options += " --anti-ddos"
        if netflix:
            openpyn_options += " --netflix"
        if test:
            openpyn_options += " --test"
        if internally_allowed:
            open_ports = ""
            for port_number in internally_allowed:
                open_ports += " " + port_number
            openpyn_options += " --allow" + open_ports
        if skip_dns_patch:
            openpyn_options += " --skip-dns-patch"
        if nvram:
            openpyn_options += " --nvram " + str(nvram)
        if openvpn_options:
            openpyn_options += " --openvpn-options '" + openvpn_options + "'"
        # logger.debug(openpyn_options)
        if subprocess.check_output(["/bin/uname", "-o"]).decode(sys.stdout.encoding).strip() == "ASUSWRT-Merlin":
            initd.update_service(openpyn_options, run=True)
        elif os.path.exists("/etc/openwrt_release"):
            initd.update_service(openpyn_options, run=True)
        else:
            systemd.update_service(openpyn_options, run=True)
        return 0

    elif kill:
        logger.warning("Killing the running processes")
        kill_management_client()
        kill_vpn_processes()  # don't touch iptable rules
        kill_openpyn_process()

    elif kill_flush:
        firewall.clear_fw_rules()      # also clear iptable rules
        # if --allow present, allow those ports internally
        logger.info("Re-enabling ipv6")
        firewall.manage_ipv6(disable=False)
        if internally_allowed:
            network_interfaces = get_network_interfaces()
            firewall.internally_allow_ports(network_interfaces, internally_allowed)
        kill_management_client()
        kill_vpn_processes()
        kill_openpyn_process()

    elif update:
        update_config_files()

    # a hack to list all countries and their codes when no arg supplied with "-l"
    elif list_servers != 'nope':      # means "-l" supplied
        if list_servers is None:      # no arg given with "-l"
            if p2p or dedicated or double_vpn or tor_over_vpn or anti_ddos or netflix:
                # show the special servers in all countries
                display_servers(
                    list_servers="all", port=port, area=area, p2p=p2p, dedicated=dedicated,
                    double_vpn=double_vpn, tor_over_vpn=tor_over_vpn, anti_ddos=anti_ddos,
                    netflix=netflix, location=location)
            else:
                api.list_all_countries()
        # if a country code is supplied give details about that country only.
        else:
            # if full name of the country supplied get country_code
            if len(list_servers) > 2:
                list_servers = api.get_country_code(full_name=list_servers)
            display_servers(
                list_servers=list_servers, port=port, area=area, p2p=p2p, dedicated=dedicated,
                double_vpn=double_vpn, tor_over_vpn=tor_over_vpn, anti_ddos=anti_ddos,
                netflix=netflix, location=location)

    # only clear/touch FW Rules if "-f" used
    elif force_fw_rules:
        firewall.clear_fw_rules()

    # check if OpenVPN config files exist if not download them.
    check_config_files()

    # if only positional argument used
    if country_code is None and server is None:
        country_code = country      # consider the positional arg e.g "us" same as "-c us"
    # if either "-c" or positional arg f.e "au" is present
    if country_code:
        # ask for and store credentials if not present, skip if "--test"
        if not test:
            if credentials.check_credentials() is False:
                credentials.save_credentials()

        if len(country_code) > 2:   # full country name
            # get the country_code from the full name
            country_code = api.get_country_code(full_name=country_code)
        country_code = country_code.lower()

        # keep trying to connect to new servers
        for tries in range(3):  # pylint: disable=W0612
            better_servers_list = find_better_servers(
                country_code, area, max_load, top_servers, tcp, p2p,
                dedicated, double_vpn, tor_over_vpn, anti_ddos, netflix, location, stats)
            pinged_servers_list = ping_servers(better_servers_list, pings, stats)
            chosen_servers = choose_best_servers(pinged_servers_list, stats)

            # connect to chosen_servers, if one fails go to next
            for aserver in chosen_servers:
                if stats:
                    print(Style.BRIGHT + Fore.BLUE + "Out of the Best Available Servers, Chose",
                          (Fore.GREEN + aserver + Fore.BLUE) + "\n")
                # if "-f" used apply firewall rules
                if force_fw_rules:
                    network_interfaces = get_network_interfaces()
                    vpn_server_ip = get_vpn_server_ip(aserver, port)
                    firewall.apply_fw_rules(network_interfaces, vpn_server_ip, skip_dns_patch)
                    if internally_allowed:
                        firewall.internally_allow_ports(network_interfaces, internally_allowed)
                if nvram:
                    # TODO return 0 on success else 1 in asus.run()
                    asus.run(aserver, country_code, nvram, "All", "adaptive", "Strict", tcp, test)
                    logger.success("SAVED SERVER " + aserver + " ON PORT " + port + " TO NVRAM")
                return(connect(aserver, port, silent, test, skip_dns_patch, openvpn_options))
    elif server:
        # ask for and store credentials if not present, skip if "--test"
        if not test:
            if credentials.check_credentials() is False:
                credentials.save_credentials()

        server = server.lower()
        # if "-f" used apply firewall rules
        if force_fw_rules:
            network_interfaces = get_network_interfaces()
            vpn_server_ip = get_vpn_server_ip(server, port)
            firewall.apply_fw_rules(network_interfaces, vpn_server_ip, skip_dns_patch)
            if internally_allowed:
                firewall.internally_allow_ports(network_interfaces, internally_allowed)
        if nvram:
            asus.run(server, country_code, nvram, "All", "adaptive", "Strict", tcp, test)
            logger.success("SAVED SERVER " + server + " ON PORT " + port + " TO NVRAM")
            return 0
        for i in range(20):  # pylint: disable=W0612
            return(connect(server, port, silent, test, skip_dns_patch, openvpn_options))
    else:
        logger.info('To see usage options type: "openpyn -h" or "openpyn --help"')
    return 0        # if everything went ok
Exemplo n.º 14
0
def apply_fw_rules(interfaces_details: List, vpn_server_ip: str,
                   skip_dns_patch: bool) -> None:
    root.verify_root_access("Root access needed to modify 'iptables' rules")

    # Empty the INPUT and OUTPUT chain of any current rules
    subprocess.check_call(["sudo", "iptables", "-F", "OUTPUT"])
    subprocess.check_call(["sudo", "iptables", "-F", "INPUT"])

    apply_dns_rules()
    logger.notice("Temporarily disabling ipv6 to prevent leakage")
    manage_ipv6(disable=True)

    # Allow all traffic out over the vpn tunnel
    # except for DNS, which is handled by systemd-resolved script
    # NOTE: that def helped with leaky DNS queries, nothing in wireshark too
    # weird that ping ya.ru was showing "operation not permitted"
    subprocess.check_call([
        "sudo",
        "iptables",
        "-A",
        "OUTPUT",
        "-o",
        "tun+",
        # "-p", "all", "-d", "0.0.0.0/0", "!", "--dport", "53",
        "-p",
        "all",
        "-d",
        "0.0.0.0/0",
        "-j",
        "ACCEPT"
    ])
    # accept traffic that comes through tun that you connect to
    subprocess.check_call(
        "sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED\
         -i tun+ -j ACCEPT".split())

    for interface in interfaces_details:
        if len(interface) != 3:
            continue  # TODO what does that mean?
        iname = interface[0]

        if len(iname) == 0:
            print("WARNING: empty {}".format(interface))
            continue

        # allow access to vpn_server_ip
        subprocess.check_call([
            "sudo", "iptables", "-A", "OUTPUT", "-o", iname, "-d",
            vpn_server_ip, "-j", "ACCEPT"
        ])
        # talk to the vpnServer ip to connect to it
        subprocess.check_call([
            "sudo", "iptables", "-A", "INPUT", "-m", "conntrack", "--ctstate",
            "ESTABLISHED,RELATED", "-i", iname, "-s", vpn_server_ip, "-j",
            "ACCEPT"
        ])

        # allow access to internal ip range
        # print("internal ip with range", interface[2])
        subprocess.check_call([
            "sudo", "iptables", "-A", "OUTPUT", "-o", iname, "-d",
            interface[2], "-j", "ACCEPT"
        ])
        subprocess.check_call([
            "sudo", "iptables", "-A", "INPUT", "-m", "conntrack", "--ctstate",
            "ESTABLISHED,RELATED", "-i", iname, "-s", interface[2], "-j",
            "ACCEPT"
        ])

    # Allow loopback traffic
    subprocess.check_call("sudo iptables -A INPUT -i lo -j ACCEPT".split())
    subprocess.check_call("sudo iptables -A OUTPUT -o lo -j ACCEPT".split())

    # best practice, stops spoofing
    subprocess.check_call(
        "sudo iptables -A INPUT -s 127.0.0.0/8 -j DROP".split())

    # Default action if no other rules match
    subprocess.check_call("sudo iptables -P OUTPUT DROP".split())
    subprocess.check_call("sudo iptables -P INPUT DROP".split())
    return
Exemplo n.º 15
0
def apply_dns_rules():
    root.verify_root_access("Root access needed to modify 'iptables' rules")
    for ndns in NORDVPN_DNS:
        do_dns("lo", ndns, "ACCEPT")
        do_dns("tun+", ndns, "ACCEPT")
Exemplo n.º 16
0
def connect(server,
            port,
            silent,
            test,
            skip_dns_patch,
            openvpn_options,
            server_provider="nordvpn"):
    detected_os = sys.platform
    if server_provider == "nordvpn":
        if port == "tcp":
            folder = "ovpn_tcp/"
        else:
            folder = "ovpn_udp/"

        vpn_config_file = __basefilepath__ + "files/" + folder + server +\
            ".nordvpn.com." + port + ".ovpn"
        # print("CONFIG FILE", vpn_config_file)
        if os.path.isfile(vpn_config_file) is False:
            print(
                Fore.RED + "VPN configuration file", vpn_config_file,
                "doesn't exist, don't worry running 'openpyn --update' for you :)"
                + Fore.BLUE)
            time.sleep(6)
            update_config_files()
    elif server_provider == "ipvanish":
        vpn_config_file = __basefilepath__ + "files/" + "ipvanish/" + server
        # print("ipvanish")

    if test:
        print(
            "Simulation end reached, openpyn would have connected to Server:" +
            Fore.GREEN, server, Fore.BLUE + "on port:" + Fore.GREEN, port,
            Fore.BLUE + "with 'silent' mode:" + Fore.GREEN, silent)
        print(Style.RESET_ALL)
        sys.exit(1)

    kill_vpn_processes()  # kill existing openvpn processes
    # kill_management_client()
    print(Fore.BLUE + "CONNECTING TO SERVER" + Fore.GREEN, server,
          Fore.BLUE + "ON PORT", Fore.GREEN + port + Fore.BLUE)

    root_access = root.verify_root_access(
        Fore.GREEN + "Sudo credentials required to run 'openvpn'" + Fore.BLUE)
    if root_access is False:
        root.obtain_root_access()

    if not silent:
        # notifications Don't work with 'sudo'
        if detected_os == "linux" and root.running_with_sudo():
            print(
                Fore.RED +
                "Desktop notifications don't work when using 'sudo', run without it, "
                + "when asked, provide the sudo credentials" + Fore.BLUE)
        else:
            subprocess.Popen("openpyn-management".split())

    if detected_os == "linux":
        resolvconf_exists = os.path.isfile("/sbin/resolvconf")
        # resolvconf_exists = False
    else:
        resolvconf_exists = False
        skip_dns_patch = True
    if not openvpn_options:
        openvpn_options = ""
    if resolvconf_exists is True and skip_dns_patch is False:  # Debian Based OS + do DNS patching
        # tunnel dns throught vpn by changing /etc/resolv.conf using
        # "update-resolv-conf.sh" to change the dns servers to NordVPN's.
        try:
            print(
                "Your OS'" + Fore.GREEN + detected_os + Fore.BLUE +
                "' Does have '/sbin/resolvconf'",
                "using it to update DNS Resolver Entries")
            print(Style.RESET_ALL)
            if silent:
                subprocess.run([
                    "sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                    "nointeract", "--config", vpn_config_file,
                    "--auth-user-pass", __basefilepath__ + "credentials",
                    "--script-security", "2", "--up", __basefilepath__ +
                    "scripts/update-resolv-conf.sh", "--down",
                    __basefilepath__ + "scripts/update-resolv-conf.sh"
                ] + openvpn_options.split(),
                               check=True)
            else:
                # print(openvpn_options)
                subprocess.run([
                    "sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                    "nointeract", "--config", vpn_config_file,
                    "--auth-user-pass", __basefilepath__ + "credentials",
                    "--script-security", "2", "--up", __basefilepath__ +
                    "scripts/update-resolv-conf.sh", "--down",
                    __basefilepath__ + "scripts/update-resolv-conf.sh",
                    "--management", "127.0.0.1", "7015", "--management-up-down"
                ] + openvpn_options.split(),
                               check=True)
        except subprocess.CalledProcessError as openvpn_err:
            # print(openvpn_err.output)
            if 'Error opening configuration file' in str(openvpn_err.output):
                print("Error opening configuration file", vpn_config_file,
                      "Make Sure it exists, run 'openpyn --update'")
                sys.exit()
        except KeyboardInterrupt:
            print('\nShutting down safely, please wait until process exits\n')
            sys.exit()
        except PermissionError:  # needed cause complains when killing sudo process
            sys.exit()

    else:  # If not Debian Based or skip_dns_patch
        # if skip_dns_patch, do not touch etc/resolv.conf
        if skip_dns_patch is False:
            print(
                "Your OS", Fore.GREEN + detected_os + Fore.BLUE,
                "Does not have" + Fore.GREEN + " '/sbin/resolvconf':\n" +
                Fore.BLUE + "Manually Applying Patch to Tunnel DNS Through" +
                "The VPN Tunnel By Modifying" + Fore.GREEN +
                "' /etc/resolv.conf'")
            print(Style.RESET_ALL)
            subprocess.call(
                ["sudo", __basefilepath__ + "scripts/manual-dns-patch.sh"])
        else:
            print(Fore.RED + "Not Modifying /etc/resolv.conf, DNS traffic",
                  "likely won't go through the encrypted tunnel")
            print(Style.RESET_ALL)
        try:  # pylint: disable=R1702
            if silent:
                if detected_os == "linux":
                    if subprocess.check_output(["/bin/uname", "-o"]).decode(
                            sys.stdout.encoding).strip() == "ASUSWRT-Merlin":
                        # make sure module is loaded
                        if os.popen(
                                "test ! -c /dev/net/tun && echo 0 || echo 1"
                        ).read()[0:-1] == '0':
                            subprocess.call("modprobe tun", shell=True)
                            if os.popen(
                                    "test ! -c /dev/net/tun && echo 0 || echo 1"
                            ).read()[0:-1] == '0':
                                print(
                                    Style.BRIGHT + Fore.RED +
                                    "Cannot open TUN/TAP dev /dev/net/tun: No such file or directory"
                                )
                                print(Style.RESET_ALL)
                                sys.exit(0)
                subprocess.run([
                    "sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                    "nointeract", "--config", vpn_config_file,
                    "--auth-user-pass", __basefilepath__ + "credentials"
                ] + openvpn_options.split(),
                               check=True)
            else:
                subprocess.run([
                    "sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                    "nointeract", "--config", vpn_config_file,
                    "--auth-user-pass", __basefilepath__ + "credentials",
                    "--management", "127.0.0.1", "7015", "--management-up-down"
                ] + openvpn_options.split(),
                               check=True)
        except subprocess.CalledProcessError as openvpn_err:
            # print(openvpn_err.output)
            if 'Error opening configuration file' in str(openvpn_err.output):
                print("Error opening configuration file", vpn_config_file,
                      "Make Sure it exists, run 'openpyn --update'")
                sys.exit()
        except KeyboardInterrupt:
            print('\nShutting down safely, please wait until process exits\n')
            sys.exit()
        except PermissionError:  # needed cause complains when killing sudo process
            sys.exit()
Exemplo n.º 17
0
def connect(server,
            port,
            daemon,
            test,
            skip_dns_patch,
            server_provider="nordvpn"):
    if server_provider == "nordvpn":
        vpn_config_file = "/usr/share/openpyn/files/" + server + ".nordvpn.com."\
                + port + ".ovpn"
        # print("CONFIG FILE", vpn_config_file)

    elif server_provider == "ipvanish":
        vpn_config_file = "/usr/share/openpyn/files/ipvanish/" + server
        # print("ipvanish")

    if test:
        print(
            "Simulation end reached, openpyn would have connected to Server:" +
            Fore.GREEN, server, Fore.BLUE + " on port:" + Fore.GREEN, port,
            Fore.BLUE + " with 'daemon' mode:" + Fore.GREEN, daemon)
        sys.exit(1)

    kill_vpn_processes()  # kill existing openvpn processes
    # kill_management_client()
    print(Fore.BLUE + "CONNECTING TO SERVER" + Fore.GREEN, server,
          Fore.BLUE + "ON PORT", Fore.GREEN + port + Fore.BLUE)

    root_access = root.verify_root_access(
        Fore.GREEN + "Sudo credentials required to run 'openvpn'" + Fore.BLUE)
    if root_access is False:
        root.obtain_root_access()

    # notifications Don't work with 'sudo'
    if root.running_with_sudo():
        print(
            Fore.RED +
            "Desktop notifications don't work when using 'sudo', run without it, "
            + "when asked, provide the sudo credentials" + Fore.BLUE)
    else:
        subprocess.Popen("openpyn-management".split())

    resolvconf_exists = os.path.isfile("/sbin/resolvconf")
    # resolvconf_exists = False
    detected_os = platform.linux_distribution()[0]

    if resolvconf_exists is True and skip_dns_patch is False:  # Debian Based OS + do DNS patching
        # tunnel dns throught vpn by changing /etc/resolv.conf using
        # "update-resolv-conf.sh" to change the dns servers to NordVPN's.
        if daemon:
            subprocess.Popen([
                "sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                "nointeract", "--config", vpn_config_file, "--auth-user-pass",
                "/usr/share/openpyn/credentials", "--script-security", "2",
                "--up", "/usr/share/openpyn/update-resolv-conf.sh", "--down",
                "/usr/share/openpyn/update-resolv-conf.sh", "--daemon",
                "--management", "127.0.0.1", "7015", "--management-up-down"
            ])
            print("Started 'openvpn' in" + Fore.GREEN + "--daemon" +
                  Fore.BLUE + "mode")
        else:
            try:
                print(
                    "Your OS'" + Fore.GREEN + detected_os + Fore.BLUE +
                    "' Does have '/sbin/resolvconf'",
                    "using it to update DNS Resolver Entries")
                print(Style.RESET_ALL)
                subprocess.call(
                    "sudo openvpn --redirect-gateway --auth-retry nointeract" +
                    " --config " + vpn_config_file + " --auth-user-pass \
                    /usr/share/openpyn/credentials --script-security 2 --up \
                    /usr/share/openpyn/update-resolv-conf.sh --down \
                    /usr/share/openpyn/update-resolv-conf.sh \
                    --management 127.0.0.1 7015 --management-up-down",
                    shell=True)
            except (KeyboardInterrupt) as err:
                print(
                    '\nShutting down safely, please wait until process exits\n'
                )
                sys.exit()
            except PermissionError:  # needed cause complains when killing sudo process
                sys.exit()

    else:  # If not Debian Based or skip_dns_patch
        # if skip_dns_patch, do not touch etc/resolv.conf
        if skip_dns_patch is False:
            print(
                "Your OS", Fore.GREEN + detected_os + Fore.BLUE,
                "Does not have" + Fore.GREEN + " '/sbin/resolvconf':\n" +
                Fore.BLUE + "Manually Applying Patch to Tunnel DNS Through" +
                "The VPN Tunnel By Modifying" + Fore.GREEN +
                "' /etc/resolv.conf'")
            apply_dns_patch = subprocess.call(
                ["sudo", "/usr/share/openpyn/manual-dns-patch.sh"])
        else:
            print(Fore.RED + "Not Modifying /etc/resolv.conf, DNS traffic",
                  "likely won't go through the encrypted tunnel")
        print(Style.RESET_ALL)

        if daemon:
            subprocess.Popen([
                "sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                "nointeract", "--config", vpn_config_file, "--auth-user-pass",
                "/usr/share/openpyn/credentials", "--daemon", "--management",
                "127.0.0.1", "7015", "--management-up-down"
            ])
            print("Started 'openvpn' in --daemon mode")
        else:
            try:
                subprocess.call((
                    "sudo openvpn --redirect-gateway --auth-retry nointeract "
                    + "--config " + vpn_config_file + " --auth-user-pass " +
                    "/usr/share/openpyn/credentials --management 127.0.0.1 7015 "
                    + "--management-up-down").split())
            except (KeyboardInterrupt) as err:
                print(
                    '\nShutting down safely, please wait until process exits\n'
                )
                sys.exit()
            except PermissionError:  # needed cause complains when killing sudo process
                sys.exit()
Exemplo n.º 18
0
def apply_allowed_port_rules(interfaces_details: List,
                             allowed_ports_config: List) -> bool:

    if not validate_allowed_ports_json(allowed_ports_config):
        return False

    root.verify_root_access("Root access needed to pre load fire wall rules")

    DEFAULT_PORT_CONFIG = {
        "internal": True,
        "protocol": "tcp",
        "allowed_ip_range": None
    }

    # Merge default config with existing config
    allowed_ports_config = [{
        **DEFAULT_PORT_CONFIG,
        **port_config
    } for port_config in allowed_ports_config]

    ip_table_rules = []

    for port_config in allowed_ports_config:
        # Get perms for the connection type
        port_protocol_permiatations = []

        if port_config["protocol"] in ["tcp", "both"]:
            port_protocol_permiatations.append("tcp")

        if port_config["protocol"] in ["udp", "both"]:
            port_protocol_permiatations.append("udp")

        # Create the flags for the port range / port
        if "-" in str(port_config["port"]):
            port_range = port_config["port"].split("-")
            port_flag = "--match multiport --dports {0}:{1}".format(
                *port_range)
        else:
            port_flag = "--dport {0}".format(port_config["port"])

        for interface, port_type in itertools.product(
                interfaces_details, port_protocol_permiatations):
            # Skip any tunnel interfaces that might be invalid
            if len(interface) != 3 or "tun" in interface[0]:
                continue

            ip_flag = ""
            ip_ranges = []

            if port_config["internal"]:
                ip_ranges.append(interface[2])

            if port_config["allowed_ip_range"] is not None:
                if isinstance(port_config["allowed_ip_range"], list):
                    ip_ranges += port_config["allowed_ip_range"]
                else:
                    ip_ranges.append(port_config["allowed_ip_range"])

            if ip_ranges != []:
                ip_flag = " -s " + ",".join(ip_ranges)

            ip_table_rules.append(
                "sudo -u {user} iptables -A INPUT -p {port_type} {port_flag} -i {interface}{ip_flag} -j ACCEPT"
                .format(user=sudo_user,
                        port_type=port_type,
                        port_flag=port_flag,
                        interface=interface[0],
                        ip_flag=ip_flag))

    for rule in ip_table_rules:
        subprocess.call(rule.split(" "))

    return True
Exemplo n.º 19
0
def flush_input_output() -> None:
    root.verify_root_access("Root access needed to modify 'iptables' rules")
    logger.info("Flushing ALL INPUT and OUTPUT Rules")
    subprocess.call(["sudo", "-u", sudo_user, "iptables", "-F", "OUTPUT"])
    subprocess.call(["sudo", "-u", sudo_user, "iptables", "-F", "INPUT"])
Exemplo n.º 20
0
def connect(server, port, daemon, test):
    if test:
        print(
            "Simulation end reached, openpyn would have connected to Server:",
            server, "on port:", port, " with 'daemon' mode:", daemon)
        sys.exit(1)

    kill_vpn_processes()  # kill existing openvpn processes
    print("CONNECTING TO SERVER", server, " ON PORT", port)

    is_root = root.verify_root_access("Root access required to run 'openvpn'")
    if daemon is True and is_root is False:
        root.obtain_root_access()

    resolvconf_exists = os.path.isfile("/sbin/resolvconf")
    # resolvconf_exists = False
    detected_os = platform.linux_distribution()[0]

    if resolvconf_exists:  # Debian Based OS
        # tunnel dns throught vpn by changing /etc/resolv.conf using
        # "update-resolv-conf.sh" to change the dns servers to NordVPN's.
        if daemon:
            subprocess.Popen([
                "sudo", "openvpn", "--redirect-gateway", "--config",
                "/usr/share/openpyn/files/" + server + ".nordvpn.com." + port +
                ".ovpn", "--auth-user-pass", "/usr/share/openpyn/credentials",
                "--script-security", "2", "--up",
                "/usr/share/openpyn/update-resolv-conf.sh", "--down",
                "/usr/share/openpyn/update-resolv-conf.sh", "--daemon"
            ])
            print("Started 'openvpn' in --daemon mode")
        else:
            try:
                print(
                    "Your OS '" + detected_os +
                    "' Does have '/sbin/resolvconf'",
                    "using it to update DNS Resolver Entries")
                subprocess.run("sudo openvpn --redirect-gateway --config" +
                               " /usr/share/openpyn/files/" + server +
                               ".nordvpn.com." + port +
                               ".ovpn --auth-user-pass \
                    /usr/share/openpyn/credentials --script-security 2 --up \
                    /usr/share/openpyn/update-resolv-conf.sh --down \
                    /usr/share/openpyn/update-resolv-conf.sh",
                               shell=True)
            except (KeyboardInterrupt) as err:
                print(
                    '\nShutting down safely, please wait until process exits\n'
                )

    else:  # If not Debian Based
        print(
            "Your OS ", detected_os,
            "Does not have '/sbin/resolvconf': Manually Applying Patch" +
            " to Tunnel DNS Through The VPN Tunnel By Modifying '/etc/resolv.conf'"
        )
        apply_dns_patch = subprocess.run(
            ["sudo", "/usr/share/openpyn/manual-dns-patch.sh"])

        if daemon:
            subprocess.Popen([
                "sudo", "openvpn", "--redirect-gateway", "--config",
                "/usr/share/openpyn/files/" + server + ".nordvpn.com." + port +
                ".ovpn", "--auth-user-pass", "/usr/share/openpyn/credentials",
                "--daemon"
            ])
            print("Started 'openvpn' in --daemon mode")
        else:
            try:
                subprocess.run("sudo openvpn --redirect-gateway --config" +
                               " /usr/share/openpyn/files/" + server +
                               ".nordvpn.com." + port +
                               ".ovpn --auth-user-pass \
                    /usr/share/openpyn/credentials",
                               shell=True)
            except (KeyboardInterrupt) as err:
                print(
                    '\nShutting down safely, please wait until process exits\n'
                )
Exemplo n.º 21
0
def connect(server: str, port: str, silent: bool, test: bool, skip_dns_patch: bool,
            openvpn_options: str, server_provider="nordvpn") -> bool:
    detected_os = sys.platform
    if server_provider == "nordvpn":
        if port == "tcp":
            folder = "ovpn_tcp/"
        else:
            folder = "ovpn_udp/"

        vpn_config_file = __basefilepath__ + "files/" + folder + server +\
            ".nordvpn.com." + port + ".ovpn"
        # logger.debug("CONFIG FILE %s", vpn_config_file)
        if os.path.isfile(vpn_config_file) is False:
            logger.notice("VPN configuration file %s doesn't exist, \
don't worry running 'openpyn --update' for you :)", vpn_config_file)
            time.sleep(6)
            update_config_files()
    elif server_provider == "ipvanish":
        vpn_config_file = __basefilepath__ + "files/" + "ipvanish/" + server
        # logger.debug("ipvanish")

    if test:
        logger.success("Simulation end reached, \
openpyn would have connected to server: " + server + " on port: " + port + " with 'silent' mode: " + str(silent).lower())
        return 0

    kill_vpn_processes()   # kill existing OpenVPN processes
    kill_management_client()
    logger.success("CONNECTING TO SERVER " + server + " ON PORT " + port)

    root_access = root.verify_root_access("Sudo credentials required to run 'openvpn'")
    if root_access is False:
        root.obtain_root_access()

    if not silent:
        # notifications Don't work with 'sudo'
        if detected_os == "linux" and root.running_with_sudo():
            logger.warning("Desktop notifications don't work when using 'sudo', run without it, \
when asked, provide the sudo credentials")
            subprocess.Popen("openpyn-management".split())
        else:
            subprocess.Popen("openpyn-management --do-notify".split())
    use_systemd_resolved = False
    use_resolvconf = False
    if detected_os == "linux":
        if subprocess.check_output(["/bin/uname", "-o"]).decode(sys.stdout.encoding).strip() == "ASUSWRT-Merlin":
            skip_dns_patch = True
        elif os.path.exists("/etc/openwrt_release"):
            skip_dns_patch = True
        else:
            use_systemd_resolved = uses_systemd_resolved()
            use_resolvconf = os.path.isfile("/sbin/resolvconf")
    else:
        use_systemd_resolved = False
        use_resolvconf = False
        skip_dns_patch = True
    if not openvpn_options:
        openvpn_options = ""
    if (use_systemd_resolved or use_resolvconf) and skip_dns_patch is False:  # Debian Based OS + do DNS patching
        try:
            route_up_script = __basefilepath__ + "scripts/docker-shim.sh"
            if use_systemd_resolved:
                openvpn_options += " " + "--dhcp-option DOMAIN-ROUTE ."
                up_down_script = __basefilepath__ + "scripts/update-systemd-resolved.sh"
                logger.success("Your OS '%s' has systemd-resolve running, \
using it to update DNS Resolver Entries", detected_os)
            elif use_resolvconf:
                # tunnel DNS through VPN by changing /etc/resolv.conf using
                # "update-resolv-conf.sh" to change the DNS servers to NordVPN's.

                up_down_script = __basefilepath__ + "scripts/update-resolv-conf.sh"
                logger.success("Your OS '%s' Does have '/sbin/resolvconf', \
using it to update DNS Resolver Entries", detected_os)
            else:
                raise RuntimeError("Should not happen")

            def run_openvpn(*args):
                cmdline = [
                    "sudo", "openvpn",
                    "--redirect-gateway",
                    "--auth-retry", "nointeract",
                    "--config", vpn_config_file,
                    "--auth-user-pass", __basefilepath__ + "credentials",
                    "--script-security", "2",
                    "--route-up", route_up_script,
                    "--up", up_down_script,
                    "--down", up_down_script,
                    "--down-pre",
                    *args,
                ] + openvpn_options.split()
                subprocess.run(cmdline, check=True)

            if silent:
                run_openvpn()
            else:
                run_openvpn(
                    "--management", "127.0.0.1", "7015",
                    "--management-up-down",
                )
        except subprocess.CalledProcessError as openvpn_err:
            # logger.debug(openvpn_err.output)
            if "Error opening configuration file" in str(openvpn_err.output):
                logger.error(
                    "Error opening config file %s, make sure it exists, run 'openpyn --update'", vpn_config_file)
                return 1
        except KeyboardInterrupt:
            logger.info("Shutting down safely, please wait until process exits")
            return 0
        except PermissionError:     # needed cause complains when killing sudo process
            return 0

    else:       # If not Debian Based or skip_dns_patch
        # if skip_dns_patch, do not touch etc/resolv.conf
        if skip_dns_patch is False:
            logger.warning("Your OS '%s' Does not have '/sbin/resolvconf'", detected_os)
            logger.notice(
                "Manually applying patch to tunnel DNS through the VPN tunnel by modifying '/etc/resolv.conf'")
            subprocess.call(["sudo", __basefilepath__ + "scripts/manual-dns-patch.sh"])
        else:
            logger.warning(
                "Not modifying '/etc/resolv.conf', DNS traffic likely won't go through the encrypted tunnel")
        try:   # pylint: disable=R1702
            if silent:
                if detected_os == "linux":
                    if subprocess.check_output(["/bin/uname", "-o"]).decode(sys.stdout.encoding).strip() == "ASUSWRT-Merlin":
                        # make sure module is loaded
                        if os.popen("test ! -c /dev/net/tun && echo 0 || echo 1").read()[0:-1] == '0':
                            subprocess.call("modprobe tun", shell=True)
                            if os.popen("test ! -c /dev/net/tun && echo 0 || echo 1").read()[0:-1] == '0':
                                logger.error(
                                    "Cannot open TUN/TAP dev /dev/net/tun: No such file or directory")
                                return 1
                subprocess.run(
                    ["sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                     "nointeract", "--config", vpn_config_file, "--auth-user-pass",
                     __basefilepath__ + "credentials"]
                    + openvpn_options.split(), check=True)
            else:
                subprocess.run(
                    ["sudo", "openvpn", "--redirect-gateway", "--auth-retry",
                     "nointeract", "--config", vpn_config_file, "--auth-user-pass",
                     __basefilepath__ + "credentials",
                     "--management", "127.0.0.1", "7015", "--management-up-down"]
                    + openvpn_options.split(), check=True)
        except subprocess.CalledProcessError as openvpn_err:
            # logger.debug(openvpn_err.output)
            if 'Error opening configuration file' in str(openvpn_err.output):
                logger.error(
                    "Error opening config file %s, make sure it exists, run 'openpyn --update'", vpn_config_file)
                return 1
        except KeyboardInterrupt:
            logger.info('Shutting down safely, please wait until process exits')
            return 0
        except PermissionError:     # needed cause complains when killing sudo process
            return 0
Exemplo n.º 22
0
def apply_fw_rules(interfaces_details: List, vpn_server_ips: List,
                   skip_dns_patch: bool) -> None:
    root.verify_root_access("Root access needed to modify 'iptables' rules")

    apply_dns_rules()
    logger.notice("Temporarily disabling ipv6 to prevent leakage")
    manage_ipv6(disable=True)

    # allow all traffic out over the VPN tunnel
    # except for DNS, which is handled by systemd-resolved script
    # NOTE: that def helped with leaky DNS queries, nothing in Wireshark too
    # weird that ping ya.ru was showing "operation not permitted"
    subprocess.check_call([
        "sudo",
        "-u",
        sudo_user,
        "iptables",
        "-A",
        "OUTPUT",
        "-o",
        "tun+",
        # "-p", "all", "-d", "0.0.0.0/0", "!", "--dport", "53",
        "-p",
        "all",
        "-d",
        "0.0.0.0/0",
        "-j",
        "ACCEPT"
    ])

    # accept traffic that comes through tun that you connect to
    subprocess.check_call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-m", "conntrack",
        "--ctstate", "ESTABLISHED,RELATED", "-i", "tun+", "-j", "ACCEPT"
    ])

    for interface in interfaces_details:
        if len(interface) != 3:
            continue  # TODO what does that mean?
        iname = interface[0]

        if not iname:
            print("WARNING: empty {}".format(interface))
            continue

        # Allow currently chosen vpn_server_ips
        for vpn_server_ip in vpn_server_ips:
            # allow access to vpn_server_ip
            subprocess.check_call([
                "sudo", "-u", sudo_user, "iptables", "-A", "OUTPUT", "-o",
                iname, "-d", vpn_server_ip, "-j", "ACCEPT"
            ])

            # talk to the vpn_server_ip to connect to it
            subprocess.check_call([
                "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-m",
                "conntrack", "--ctstate", "ESTABLISHED,RELATED", "-i", iname,
                "-s", vpn_server_ip, "-j", "ACCEPT"
            ])

        # allow access to internal IP range
        # print("internal IP with range", interface[2])
        subprocess.check_call([
            "sudo", "-u", sudo_user, "iptables", "-A", "OUTPUT", "-o", iname,
            "-d", interface[2], "-j", "ACCEPT"
        ])

        subprocess.check_call([
            "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-m",
            "conntrack", "--ctstate", "ESTABLISHED,RELATED", "-i", iname, "-s",
            interface[2], "-j", "ACCEPT"
        ])

    # allow loopback traffic
    subprocess.check_call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-i", "lo", "-j",
        "ACCEPT"
    ])
    subprocess.check_call([
        "sudo", "-u", sudo_user, "iptables", "-A", "OUTPUT", "-o", "lo", "-j",
        "ACCEPT"
    ])

    # best practice, stops spoofing
    subprocess.check_call([
        "sudo", "-u", sudo_user, "iptables", "-A", "INPUT", "-s",
        "127.0.0.0/8", "-j", "DROP"
    ])

    # default action if no other rules match
    subprocess.check_call(
        ["sudo", "-u", sudo_user, "iptables", "-P", "OUTPUT", "DROP"])
    subprocess.check_call(
        ["sudo", "-u", sudo_user, "iptables", "-P", "INPUT", "DROP"])