Ejemplo n.º 1
0
    def tear_down(self):
        if not self.up:
            logger.warning("wireguard interface already disabled: {}",
                self.interface)
            return

        logger.debug("disabling wireguard interface: {}", self.interface)
        
        # Disable interface with "ip link set down dev..."
        exec_command([
            "ip", "link", "set", "down", "dev", self.interface],
            root=True,
            fail_msg="failed to disable interface: {}".format(self.interface),
            exception=WireGuardError)
        
        exec_command([
            "ip", "address", "flush", "dev", self.interface],
            root=True,
            fail_msg="failed to reset addresses on interface: {}".format(self.interface),
            exception=WireGuardError)
        
        logger.activity("wireguard interface disabled: {}", self.interface)

        # Mark interface as down
        self.up = False
Ejemplo n.º 2
0
def systemd_resolved_disable():
    if systemd_resolved_running():
        exec_command(["systemctl", "disable", "--now", "systemd-resolved"],
                     root=True,
                     fail_msg="failed to disable systemd-resolved")
        return True
    return False
Ejemplo n.º 3
0
def ipv4_disable_output_nat(nic, ignore_errors=False):
    exec_command([
        "iptables", "-t", "nat", "-D", "POSTROUTING", "-o",
        str(nic), "-j", "MASQUERADE"
    ],
                 root=True,
                 noexcept=ignore_errors,
                 quiet=ignore_errors)
Ejemplo n.º 4
0
def ipv4_del_route_to_network(net_addr, net_nic, net_gw):
    exec_command([
        "ip", "route", "del",
        str(net_addr), "via",
        str(net_gw), "dev",
        str(net_nic)
    ],
                 fail_msg="failed to remove route: {}({}) <--> {}".format(
                     str(net_gw), str(net_nic), str(net_addr)))
Ejemplo n.º 5
0
def _encode_file_png(file_in, file_out):
    file_out = pathlib.Path(file_out)
    file_out.parent.mkdir(parents=True, exist_ok=True)
    exec_command([
        "sh", "-c", " ".join(
            ["qrencode", "-t", "png", "-o",
             str(file_out), "<",
             str(file_in)])
    ],
                 fail_msg="failed to encode PNG qr code")
Ejemplo n.º 6
0
def ipv4_disable_source_nat(nic, src_network):
    logger.debug("disabling source NAT on {} for {}", nic, src_network)
    exec_command(["iptables", "-D", "INPUT", "-i",
                  str(nic), "-j", "ACCEPT"],
                 root=True)
    exec_command([
        "iptables", "-t", "nat", "-D", "POSTROUTING", "-s",
        str(src_network), "-o",
        str(nic), "-j", "MASQUERADE"
    ],
                 root=True)
    logger.activity("[disabled] source NAT on {} for {} ", nic, src_network)
Ejemplo n.º 7
0
    def _run_test(self):
        result = exec_command(["ip", "-o", "route"])

        def check_route(r):
            for n in self.interfaces:
                if f"dev {n}" in r:
                    return True
            return False

        def mkroute(r):
            subnet = ipaddress.ip_network(r.split(" ")[0])
            nic = r.split(" ")[2]
            gw = ipaddress.ip_address("0.0.0.0")
            peer = ""
            return LocalRoute(subnet=subnet, nic=nic, gw=gw, peer=peer)

        results = frozenset(result.stdout.decode("utf-8").split("\n")[:-1])
        results = filter(check_route, results)
        # Filter by finding peer in cell_cfg.backbone and checking
        # that route isn't for a backbone network
        routes = [mkroute(r) for r in results]
        if routes:
            logger.trace("found routes for {}: {}", self.interfaces, routes)
            self.router.listener.on_route_monitor_result(self.router, routes)
        else:
            logger.warning("no backbone routes detected for {}",
                           self.interfaces)
Ejemplo n.º 8
0
def systemd_resolved_running():
    res = exec_command(["killall", "-0", "systemd-resolved"],
                       root=True,
                       noexcept=True,
                       quiet=True,
                       fail_msg="failed to check systemd-resolved status")
    return res.returncode == 0
Ejemplo n.º 9
0
 def peers(self):
     result = exec_command(
         ["wg", "show", str(self.interface), "peers"],
         root=True,
         fail_msg="failed to get current peers for interface: {}".format(self.interface),
         exception=WireGuardError)
     peers = list(filter(lambda v: len(v) > 0, result.stdout.decode("utf-8").split("\n")))
     return peers
Ejemplo n.º 10
0
 def _list_peers(self):
     result = exec_command(["wg", "show", str(self.interface), "peers"],
         quiet=True,
         root=True,
         fail_msg="failed to get peers for interface: {}".format(self.interface),
         exception=WireGuardError)
     peers = set(decode_output(result.stdout))
     logger.trace("current peers [{}]: {}", self.interface, peers)
     return peers
Ejemplo n.º 11
0
def build_connextddspy(nddshome, dst_dir, arch, keep=False):
    # Create a temporary directory for storing build files
    tmp_dir = tempfile.mkdtemp(prefix=f"connextdds-py-{nddshome.name}-",
                               suffix="-context")
    tmp_dir = pathlib.Path(tmp_dir)
    nddsarch = UvnDefaults["dds"]["connext"]["arch"].get(container_arch)
    if not nddsarch:
        raise ValueError(f"unsupported architecture: {arch}")
    try:
        # Clone connextdds-py repository
        repo_url = UvnDefaults["dds"]["connext"]["py"]["git"]
        repo_dir = tmp_dir / "connextdds-py"
        exec_command(
            ["git", "clone", repo_url, repo_dir],
            fail_msg="failed to clone git repository: {}".format(repo_url))

        # Run configure.py
        logger.warning(
            "building connextdds-py wheel (this might take some time)")
        cpu_count = multiprocessing.cpu_count()
        exec_command(
            ["python", "configure.py", "-j",
             str(cpu_count), nddsarch],
            cwd=repo_dir,
            fail_msg="failed to clone git repository: {}".format(repo_url))

        # Copy wheel to destination directory:
        py_vers = "{}{}".format(sys.version_info.major, sys.version_info.minor)
        whl_name = self.name = UvnDefaults["docker"]["context"][
            "connextdds_wheel_fmt"].format(py_vers, py_vers, arch)
        whl_path = repo_dir / whl_name
        shutil.copy2(str(whl_path), str(dst_dir))

    except Exception as e:
        logger.exception(e)
        logger.error("failed to build wheel for connextdds-py: {}", arch)
        raise (e)
    finally:
        if not keep:
            shutil.rmtree(str(tmp_dir))
        else:
            logger.warning("[tmp] not deleted: {}", tmp_dir)

    return whl_path
Ejemplo n.º 12
0
 def run(self):
     logger.activity("[{}] starting up...", self._daemon)
     try:
         self._sem_started.release()
         exec_command(["killall", "-9", self._daemon],
                      fail_msg=f"failed to kill {self._daemon}",
                      quiet=True,
                      noexcept=True)
         exec_command([
             self._daemon, "-f", self._config, "-i", self._pid, "-z",
             self._socket
         ],
                      fail_msg=f"failed to run {self._daemon}")
     except Exception as e:
         logger.exception(e)
         logger.error("error in {} thread", self._daemon)
         raise e
     finally:
         logger.activity("[{}] stopped", self._daemon)
Ejemplo n.º 13
0
def ipv4_list_routes(oneline=False, resolve=True, split=True):
    if not oneline:
        cmd = ["ip", "route"]
    else:
        cmd = ["ip", "-o", "route"]
    result = exec_command(cmd, fail_msg="failed to list routes")
    results = result.stdout.decode("utf-8")
    if split:
        results = frozenset(results.split("\n")[:-1])
    return results
Ejemplo n.º 14
0
    def delete(self):
        if not self.created:
            logger.warning("wireguard interface not deleted: {}",
                self.interface)
            return

        logger.debug("deleting wireguard interface: {}", self.interface)
        
        # Remove interface with "ip link delete dev..."
        exec_command([
            "ip", "link", "delete", "dev", self.interface],
            root=True,
            fail_msg="failed to add interface: {}".format(self.interface),
            exception=WireGuardError)
        
        logger.debug("deleted wireguard interface: {}", self.interface)

        # Mark interface as up
        self.created = False
Ejemplo n.º 15
0
 def _update_allowed_ips(self, peer, allowed_ips):
     logger.trace("updating allowed ips for peer {} on {}: {}",
         peer, self.interface, list(map(str, allowed_ips)))
     # sort ips for tidyness in `wg show`'s output
     allowed_ips_str = sorted(map(str,allowed_ips))
     exec_command([
         "wg", "set", self.interface,
             "peer", peer, "allowed-ips", ",".join(allowed_ips_str)],
         root=True,
         fail_msg=f"failed to get set allowed-ips on interface: {self.interface}",
         exception=WireGuardError)
     allowed_ips_set = self._list_allowed_ips_peer(peer)
     if allowed_ips ^ allowed_ips_set:
         logger.warning("[unexpected allowed][{}] {}",
             self.interface, peer)
         logger.warning("[set][{}] {}: {}",
             self.interface, peer, allowed_ips)
         logger.warning("[found][{}] {}: {}",
             self.interface, peer, allowed_ips_set)
Ejemplo n.º 16
0
 def _list_handshakes(self):
     result = exec_command(["wg", "show", str(self.interface), "latest-handshakes"],
         quiet=True,
         root=True,
         fail_msg="failed to get latest handshakes for interface: {}".format(self.interface),
         exception=WireGuardError)
     handshakes = {}
     for line in decode_output(result.stdout):
         l_split = list(filter(len, line.split()))
         handshakes[l_split[0]] = Timestamp.unix(l_split[1])
     logger.trace("current handshakes [{}]: {}", self.interface, handshakes)
     return handshakes
Ejemplo n.º 17
0
 def _tracepath_test(self, peer_count, peer_i, p_name, p_rec):
     ts_check = Timestamp.now()
     result = exec_command(
         ["tracepath", "-c", str(self._ping_count), str(p_rec["address"])],
         fail_msg="failed to ping peer: {} [{}]".format(p_name, p_rec["address"]),
         # don't throw an exception on error
         noexcept=True,
         # don't print any error message
         quiet=True)
     peer_ok = result.returncode == 0
     if not peer_ok:
         unavail_peers.add(p_name)
     self._update_and_notify(peer_i, peer_count, p_name, peer_ok, ts_check)
Ejemplo n.º 18
0
    def exec(cmd_id):
        cmd_id_p = cmd_id.split(".")
        cmds = Vtysh.commands
        for p in cmd_id_p:
            cmds = cmds[p]

        cmd = ["vtysh", "-E"]
        for c in cmds:
            cmd.extend(["-c", str(c)])
        result = exec_command(cmd,
                              fail_msg="failed to perform vtysh command",
                              root=True)
        return result.stdout.decode("utf-8")
Ejemplo n.º 19
0
 def _list_allowed_ips(self):
     result = exec_command(["wg", "show", str(self.interface), "allowed-ips"],
         quiet=True,
         root=True,
         fail_msg="failed to get endpoints for interface: {}".format(self.interface),
         exception=WireGuardError)
     allowed_ips = {}
     for line in decode_output(result.stdout):
         l_split = list(filter(len, line.split()))
         ips = set(map(ipaddress.ip_network,
                 filter(lambda s: s != "(none)",
                     filter(len, l_split[1:]))))
         allowed_ips[l_split[0]] = ips
     logger.trace("current allowed IPs [{}]: {}", self.interface, allowed_ips)
     return allowed_ips
Ejemplo n.º 20
0
 def _list_transfer(self):
     result = exec_command(["wg", "show", str(self.interface), "transfer"],
         quiet=True,
         root=True,
         fail_msg="failed to get transfer stats for interface: {}".format(self.interface),
         exception=WireGuardError)
     transfers = {}
     for line in decode_output(result.stdout):
         l_split = list(filter(len, line.split()))
         transfers[l_split[0]] = {
             "recv": int(l_split[1]),
             "send": int(l_split[2])
         }
     logger.trace("current transfer stats [{}]: {}", self.interface, transfers)
     return transfers
Ejemplo n.º 21
0
    def create(self):
        if self.created:
            logger.warning("wireguard interface already created: {}",
                self.interface)
            return

        logger.debug("creating wireguard interface: {}", self.interface)
        
        # Check if interface already exists with "ip link show..."
        result = exec_command([
            "ip", "link", "show", self.interface],
            root=True,
            noexcept=True,
            quiet=True)
        intf_exists = result.returncode == 0
        
        if intf_exists:
            # Delete interface with "ip link delete dev..."
            logger.debug("deleting existing wireguard interface: {}", self.interface)
            exec_command([
                "ip", "link", "delete", "dev", self.interface],
                root=True,
                fail_msg="failed to delete interface: {}".format(self.interface),
                exception=WireGuardError)

        # Add interface with "ip link add dev..."
        exec_command([
            "ip", "link", "add", "dev", self.interface, "type", "wireguard"],
            root=True,
            fail_msg="failed to add interface: {}".format(self.interface),
            exception=WireGuardError)
        
        logger.debug("created wireguard interface: {}", self.interface)

        # Mark interface as up
        self.created = True
Ejemplo n.º 22
0
def ipv4_enable_forward(nic):
    exec_command(["iptables", "-A", "FORWARD", "-i",
                  str(nic), "-j", "ACCEPT"],
                 root=True)
    exec_command(["iptables", "-A", "FORWARD", "-o",
                  str(nic), "-j", "ACCEPT"],
                 root=True)
    exec_command(["iptables", "-A", "INPUT", "-i",
                  str(nic), "-j", "ACCEPT"],
                 root=True)
Ejemplo n.º 23
0
 def run(self):
     # try:
     logger.debug("starting routing service")
     result = exec_command(
         [
             self._bin, "-verbosity",
             str(self._verbosity), "-cfgFile",
             str(self.cfg_file), "-cfgName", self.cfg_name
         ],
         # "|", "tee", "-a", str(self.log_file)],
         # shell=True,
         output=self.log_file,
         fail_msg=
         f"failed to run routing service. see {self.log_file} for more info",
         noexcept=True)
     logger.activity("routing service exited")
Ejemplo n.º 24
0
def ipv4_default_gateway():
    result = exec_command(["ip", "route"],
                          fail_msg="failed to get kernel routes")

    for line in decode_output(result.stdout):
        if not line.startswith("default via "):
            continue
        l_split = list(filter(len, line.split()))
        try:
            gw = ipaddress.ip_address(l_split[2])
        except Exception as e:
            logger.debug("failed to parse as gateway address: {}", l_split[2])
            continue
        return gw

    raise RuntimeError("failed to determine default gateway")
Ejemplo n.º 25
0
    def _clone_uno(tmp_dir, keep=False, dev=True):
        # Clone the "uno" git repository
        repo_dir = tmp_dir / UvnDefaults["docker"]["context"]["repo_dir"]
        repo_dir_clone = repo_dir.with_name("{}.tmp".format(repo_dir.name))

        repo_url = UvnDefaults["docker"]["context"]["repo_url_fmt"].format(
            UvnDefaults["docker"]["context"]["repo_proto"],
            os.environ.get(UvnDefaults["docker"]["env"]["oauth_token"]),
            UvnDefaults["docker"]["context"]["repo_url_base"])

        repo_branch = UvnDefaults["docker"]["context"]["repo_branch"]

        if not dev:
            logger.debug("clone git repo {} to {}", repo_url, repo_dir_clone)
            exec_command(
                ["git", "clone", "-b", repo_branch, repo_url, repo_dir_clone],
                fail_msg="failed to clone git repository: {}".format(repo_url))

            # Create an archived copy
            logger.debug("archive git repo to {}", repo_dir)
            repo_tar = repo_dir.with_name("{}.tar".format(repo_dir.name))
            exec_command(
                [
                    "git", "archive", repo_branch, "--format", "tar", "-o",
                    repo_tar
                ],
                cwd=repo_dir_clone,
                fail_msg="failed to archive git repository: {}".format(
                    repo_tar))

            repo_dir.mkdir(parents=True, exist_ok=True)
            exec_command(
                ["tar", "xvf", repo_tar, "-C", repo_dir],
                fail_msg="failed to extract repository: {}".format(repo_dir))
        else:
            # Copy uno from this current copy
            import libuno
            uno_path = pathlib.Path(libuno.__file__).parent.parent
            logger.debug("copying uno from {}", uno_path)
            shutil.copytree(str(uno_path),
                            str(repo_dir),
                            ignore=DockerController.filter_uvn_files)

        # Delete clone directory and tar file
        if not keep and not dev:
            repo_tar.unlink()
            shutil.rmtree(str(repo_dir_clone))
        return repo_dir
Ejemplo n.º 26
0
def ipv4_disable_forward(nic, ignore_errors=False):
    exec_command(["iptables", "-D", "FORWARD", "-i",
                  str(nic), "-j", "ACCEPT"],
                 root=True,
                 noexcept=ignore_errors,
                 quiet=ignore_errors)
    exec_command(["iptables", "-D", "FORWARD", "-o",
                  str(nic), "-j", "ACCEPT"],
                 root=True,
                 noexcept=ignore_errors,
                 quiet=ignore_errors)
    exec_command(["iptables", "-D", "INPUT", "-i",
                  str(nic), "-j", "ACCEPT"],
                 root=True,
                 noexcept=ignore_errors,
                 quiet=ignore_errors)
Ejemplo n.º 27
0
 def _list_endpoints(self):
     result = exec_command(["wg", "show", str(self.interface), "endpoints"],
         quiet=True,
         root=True,
         fail_msg="failed to get endpoints for interface: {}".format(self.interface),
         exception=WireGuardError)
     endpoints = {}
     for line in decode_output(result.stdout):
         l_split = list(filter(len, line.split()))
         endp_split = list(filter(len, l_split[1].split(":")))
         try:
             addr = ipaddress.ip_address(endp_split[0])
             port = int(endp_split[1])
         except Exception as e:
             addr = "<unknown>"
             port = "<unknown>"
         endpoints[l_split[0]] = {
             "address": addr,
             "port": port
         }
     logger.trace("current endpoints [{}]: {}", self.interface, endpoints)
     return endpoints
Ejemplo n.º 28
0
 def stop(self):
     logger.activity("signaling routing service to exit")
     exec_command(["killall", "-SIGTERM", "rtiroutingservice"],
                  fail_msg="failed to signal routing service",
                  noexcept=True)
     self.join()
Ejemplo n.º 29
0
    def _initialize_runner_context(tmp_dir,
                                   basedir,
                                   dockerfile,
                                   container_arch,
                                   connext_helper,
                                   keep=False,
                                   copy_uno=False,
                                   copy_uvn=False,
                                   build_wheel=False,
                                   dev=False,
                                   connext=False):
        logger.activity("[context] initializing: {}", tmp_dir)
        context_data = []
        extra_args = {}

        if copy_uno and not dev:
            repo_dir = DockerController._clone_uno(tmp_dir, keep=keep, dev=dev)
            context_data.append(repo_dir.name)

        if copy_uvn:
            uvn_dir = DockerController._clone_uvn(tmp_dir, basedir, keep=keep)
            context_data.append(uvn_dir.name)

        # Retrieve a pre-built wheel file to install connextdds-py
        connextdds_wheel = None
        if not build_wheel:
            try:
                connextdds_wheel = StaticData.connextdds_wheel(container_arch)
            except Exception as e:
                logger.warning(
                    "no prebuilt connextdds-py wheel found for architecture {}"
                )
        if not connextdds_wheel or build_wheel:
            connextdds_wheel = connext_helper.py.build(container_arch)
        dds_whl_path = tmp_dir / connextdds_wheel.name
        connextdds_wheel.copy_to(dds_whl_path)
        context_data.append(dds_whl_path.name)
        extra_args["CONNEXTDDS_WHEEL"] = connextdds_wheel.name

        if connext:
            # Copy Connext DDS libraries and routing service
            dds_path = tmp_dir / UvnDefaults["dds"]["home"]
            connextdds_arc = UvnDefaults["dds"]["connext"]["arch"][
                container_arch]
            connext_helper.copy_to(dds_path, archs=[connextdds_arc])
            context_data.append(dds_path.name)

        # Instantiate Dockerfile
        dockerfile_path = tmp_dir / "Dockerfile"
        base_image = None
        if container_arch == "x86_64":
            if sys.version_info.minor == 6:
                base_image = "ubuntu:18.04"
            elif sys.version_info.minor == 8:
                base_image = "ubuntu:20.04"
        elif container_arch == "armv7l":
            if sys.version_info.minor == 7:
                base_image = "balenalib/raspberry-pi-debian:latest"
        else:
            raise ValueError(
                f"unsupported container architecture: {container_arch}")
        if not base_image:
            raise RuntimeError(
                f"Python 3.{sys.version_info.minor} not supported in {container_arch} uno containers yet"
            )
        dockerfile_tmplt = Dockerfile(base_image=base_image,
                                      dev=dev,
                                      ndds=False,
                                      rpi_extra=container_arch == "armv7l")
        render(dockerfile_tmplt, "Dockerfile", to_file=dockerfile_path)
        context_data.append("Dockerfile")

        # Instantiate entrypoint script
        entrypoint_path = tmp_dir / "entrypoint.sh"
        with entrypoint_path.open("w") as output:
            entrypoint_stream = StaticData.script("entrypoint.sh",
                                                  binary=False)
            shutil.copyfileobj(entrypoint_stream, output)
        context_data.append("entrypoint.sh")

        # Create a tar containing the custom build context
        context_tar = tmp_dir / UvnDefaults["docker"]["context"]["tar"]
        cmd_args = ["tar", "cvf", context_tar]
        cmd_args.extend(context_data)
        exec_command(
            cmd_args,
            cwd=tmp_dir,
            fail_msg="failed to archive build context: {}".format(context_tar))

        return context_tar, extra_args
Ejemplo n.º 30
0
    def bring_up(self):
        if self.up:
            logger.warning("wireguard interface already active: {}",
                self.interface)
            return

        logger.debug("activating wireguard interface: {} [{}]",
            self.interface, self.interface_address)

        # Disable interface with "ip link set down dev..."
        exec_command([
            "ip", "link", "set", "down", "dev", self.interface],
            root=True,
            fail_msg="failed to disable interface: {}".format(self.interface),
            exception=WireGuardError)
        
        exec_command([
            "ip", "address", "flush", "dev", self.interface],
            root=True,
            fail_msg="failed to reset addresses on interface: {}".format(self.interface),
            exception=WireGuardError)
        
        # Configure interface address with "ip address add dev..."
        exec_command([
            "ip", "address", "add", 
            "dev", self.interface,
            "{}/{}".format(self.interface_address, self.interface_address_mask)],
            root=True,
            fail_msg="failed to configure interface address: {} {}".format(
                        self.interface, self.interface_address),
            exception=WireGuardError)
        
        # Generate a temporary file with wg configuration
        tmp_file_fd, tmp_file_path = tempfile.mkstemp(
            prefix="{}-".format(self.interface),
            suffix="-wgconf")
        tmp_file_path = pathlib.Path(str(tmp_file_path))
        try:
            with tmp_file_path.open("w") as output:
                output.write(self.config)
                output.flush()
            
            # Set wireguard configuration with "wg setconf..."
            exec_command([
                "wg", "setconf", self.interface, str(tmp_file_path)],
                root=True,
                fail_msg="failed to configure wireguard: {}".format(self.interface),
                exception=WireGuardError)
        finally:
            os.close(tmp_file_fd)
            if not self.keep:
                tmp_file_path.unlink()
            else:
                logger.warning("[tmp] not deleted: {}", tmp_file_path)

        # Activate interface with "ip link set up dev..."
        exec_command([
            "ip", "link", "set", "up", "dev", self.interface],
            root=True,
            fail_msg="failed to activate wireguard: {}".format(self.interface),
            exception=WireGuardError)

        # Allow configure IP addresses
        for p in self._list_peers():
            for a in self.allowed_ips:
                self.allow_ips(p, a)

        logger.activity("wireguard interface active: {} [{}]",
            self.interface, self.interface_address)

        # Mark interface as up
        self.up = True