def __init__(self, nsp_name: str, ipdb: IPDB):
        """
        Creats a namespace for a specific vlan_iface

        :param nsp_name:
        :param vlan_iface_name:
        :param ipdb: IPDB is a transactional database, containing records, representing network stack objects.
                    Any change in the database is not reflected immidiately in OS, but waits until commit() is called.
        """
        Logger().debug("Create Namespace ...", 2)
        self.nsp_name = nsp_name
        self.id = id
        self.vlan_iface_name = ""
        self.vlan_iface_ip = "0.0.0.0"
        self.ipdb = ipdb
        self.ipdb_netns = None
        try:
            self.ipdb_netns = IPDB(nl=NetNS(nsp_name))
            netns.setns(nsp_name)
            self.ipdb_netns.interfaces['lo'].up().commit()
            Logger().debug("[+] Namespace(" + nsp_name + ") successfully created", 3)
            # self.encapsulate_interface()
        except Exception as e:
            Logger().debug("[-] Couldn't create Namespace(" + nsp_name + ")", 3)
            for tb in traceback.format_tb(sys.exc_info()[2]):
                Logger().error(tb, 3)
            Logger().error(str(e), 3)
            self.remove()
Example #2
0
    def __init__(self, ipdb: IPDB, nsp_name: str):
        """
        Creats a namespace for a specific vlan_iface

        :param nsp_name:
        :param ipdb: IPDB is a transactional database, containing records, representing network stack objects.
                    Any change in the database is not reflected immidiately in OS, but waits until commit() is called.
        """
        logging.debug("%sCreate Namespace ...", LoggerSetup.get_log_deep(2))
        self.ipdb = ipdb if ipdb else IPDB()
        self.ipdb_netns = None
        self.nsp_name = nsp_name
        try:
            self.ipdb_netns = IPDB(nl=NetNS(nsp_name))
            self.ipdb_netns.interfaces['lo'].up().commit()
            logging.debug(
                "%s[+] Namespace(" + nsp_name + ") successfully created",
                LoggerSetup.get_log_deep(3))
            # self.encapsulate_interface()
        except Exception as e:
            logging.debug("%s[-] Couldn't create Namespace(" + nsp_name + ")",
                          LoggerSetup.get_log_deep(3))
            for tb in traceback.format_tb(sys.exc_info()[2]):
                logging.error("%s" + tb, LoggerSetup.get_log_deep(3))
            logging.error("%s" + str(e), LoggerSetup.get_log_deep(3))
            self.remove()
Example #3
0
    def start(self) -> None:
        """Start host

        Raises:
            HostUpException: If host is already running.
        """
        if self.__ns is not None:
            raise HostUpException()
        try:
            self.__ns = NetNS(self.name)
        except FileExistsError:
            raise HostUpException()
        self.__files = _setup_etc(self.name)
        self.__ipdb = pyroute2.ipdb.main.IPDB(nl=self.__ns)
        self.__ipdb.interfaces["lo"].up().commit()
        if self.__manager is not None:
            self.__manager.register(self)
Example #4
0
class Host(InterfaceContainer):
    """Host in a network container.

    This is a host in a networked container.

    Args:
        name: Name for the host, which is the name for the network namespace.

    Attributes:
        name: Name of the host, which is also the name of the network namespace.
    """
    def __init__(self, name: str, manager: Manager = None) -> None:
        self.__ns = None
        self.__ipdb = None
        self.__manager = manager
        self.__files = {}
        self.__hostnames = []
        super().__init__(name)

    def add_hostname(self, name: str) -> None:
        self.__hostnames.append(name)

    @property
    def running(self) -> bool:
        """True if host is running"""
        return self.__ns is not None

    @property
    def ipdb(self) -> pyroute2.ipdb.main.IPDB:
        """Return host IPDB"""
        if not self.running:
            raise HostDownException()
        return self.__ipdb

    def start(self) -> None:
        """Start host

        Raises:
            HostUpException: If host is already running.
        """
        if self.__ns is not None:
            raise HostUpException()
        try:
            self.__ns = NetNS(self.name)
        except FileExistsError:
            raise HostUpException()
        self.__files = _setup_etc(self.name)
        self.__ipdb = pyroute2.ipdb.main.IPDB(nl=self.__ns)
        self.__ipdb.interfaces["lo"].up().commit()
        if self.__manager is not None:
            self.__manager.register(self)

    def Popen(self, *args, **kwargs):  #pylint: disable=invalid-name
        """Popen inside the host"""

        mounts = tuple(
            (bytes(src), bytes(dst)) for src, dst in self.__files.values())

        def change_ns():
            """Setup the namespace"""
            # This is borrowed from iproute2 and looks more sane than pyroute2
            # Let's move ourselves to the target network namespace
            try:
                # Change to network namespace
                setns(self.name, flags=0)

                # Unshare the mount namespace (preparation for following steps)
                # Unshare UTS namespace for hostname
                syscalls.unshare(syscalls.CLONE_NEWNS | syscalls.CLONE_NEWUTS)

                # Make our mounts slave (otherwise unshare doesn't help with shared mounts)
                syscalls.mount(b"none", b"/", None,
                               syscalls.MS_REC | syscalls.MS_SLAVE, None)

                # Mount sysfs that belongs to this network namespace
                syscalls.umount2(b"/sys", syscalls.MNT_DETACH)
                syscalls.mount(b"none", b"/sys", b"sysfs", 0, None)

                # Set the hostname
                socket.sethostname(self.name)

                # fake hosts files etc
                for src, dst in mounts:
                    syscalls.mount(src, dst, b"none", syscalls.MS_BIND, None)
            except Exception as err:
                print(err)
                raise

        return subprocess.Popen(*args, preexec_fn=change_ns, **kwargs)

    def stop(self) -> None:
        """Stop host

        Raises:
            HostDownException: If host is already stopped.
        """
        if self.__ns is None:
            raise HostDownException()
        self.__ipdb.release()
        self.__ipdb = None
        self.__ns.close()
        self.__ns.remove()
        _remove_etc(self.name)
        self.__ns = None
        if self.__manager is not None:
            self.__manager.unregister(self)

    def set_hosts(self, hosts):
        with self.__files["hosts"][0].open('wb') as hostfile:
            hostfile.write(DEFAULT_HOSTS)
            for host, address, hostnames in hosts:
                hostfile.write("{}\t{}\t{}\n".format(
                    address, host, " ".join(hostnames)).encode())

    def get_hostnames(self):
        return [(self.name, address.ip, self.__hostnames)
                for interface in self.interfaces.values()
                for address in interface.addresses]

    def _find_gateway(self, addrtype):
        # search the network for any router and use it as default gateway
        for intf in self.interfaces.values():
            if not isinstance(intf, VirtualInterface):
                continue
            addresses = list(
                filter(lambda x: isinstance(x, addrtype), intf.addresses))
            intf_list = set([intf])
            visited = set([intf])
            while intf_list:
                peer, peerintf = intf_list.pop().peer()
                if peer.router:
                    gateway = _compatible_address(addresses,
                                                  peerintf.addresses)
                    if gateway:
                        self.ipdb.routes.add({
                            'dst': 'default',
                            'gateway': str(gateway)
                        }).commit()
                        return
                if peer.switch:
                    new_intfs = set(
                        filter(
                            lambda x: x not in visited and isinstance(
                                x, VirtualInterface),
                            peer.interfaces.values()))
                    intf_list.extend(new_intfs)
                    visited.extend(new_intfs)

    def find_routes(self):
        if {
                'dst': 'default',
                'family': socket.AF_INET
        } not in self.ipdb.routes:
            self._find_gateway(ipaddress.IPv4Interface)
        if {
                'dst': 'default',
                'family': socket.AF_INET6
        } not in self.ipdb.routes:
            self._find_gateway(ipaddress.IPv6Interface)