예제 #1
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()
예제 #2
0
    def test_timeout(self):
        print("Test Dhclient: timeout")
        router = self._create_router()
        # Set VLAN that doesn't exist, so no response occur.
        router._vlan_iface_id = 99
        router._vlan_iface_name = "vlan99"
        ipdb = IPDB()

        try:
            print("Get link-interface ...")
            # Get the real link interface
            link_iface = ipdb.interfaces["eth0"]
            # Create a Vlan
            print("Create VLAN ...")
            with ipdb.create(kind="vlan",
                             ifname=router.vlan_iface_name,
                             link=link_iface,
                             vlan_id=router.vlan_iface_id).commit() as iface:
                print("Update IP with Dhclient ...")
                Dhclient.update_ip(router.vlan_iface_name, timeout=10)
                iface.mtu = 1400
        except TimeoutError:
            print("[+] Test was successful")
        except Exception as e:
            print("Error: " + str(e))
            raise e
        finally:
            print("Delete VLAN ...")
            ipdb.interfaces[router.vlan_iface_name].remove().commit()
            ipdb.release()
    def test_normal_functionality(self):
        print("Test Dhclient: update_ip")
        router = self._create_router()
        ipdb = IPDB()

        try:
            print("Get link-interface ...")
            # Get the real link interface
            link_iface = ipdb.interfaces["eth0"]
            # Create a Vlan
            print("Create VLAN ...")
            with ipdb.create(kind="vlan", ifname=router.vlan_iface_name, link=link_iface,
                             vlan_id=router.vlan_iface_id).commit() as iface:
                print("Update IP with Dhclient ...")
                Dhclient.update_ip(router.vlan_iface_name)
                iface.mtu = 1400
            # Because the IPDB need some time to update the given IP
            sleep(10)
            process = Popen(["ping", "-c", "1", "-I", router.vlan_iface_name, router.ip], stdout=PIPE, stderr=PIPE)
            stdout, sterr = process.communicate()
            if not(sterr.decode('utf-8') == "" and "Unreachable" not in stdout.decode('utf-8')):
                raise Exception(str(sterr.decode('utf-8')))
            print("[+] Test was successful")
        except Exception as e:
            print("Error: " + str(e))
            raise e
        finally:
            print("Delete VLAN ...")
            ipdb.interfaces[router.vlan_iface_name].remove().commit()
            ipdb.release()
    def test_create_namespace(self):
        router = self._create_router()

        # Create VLAN
        ipdb = IPDB()
        vlan = Vlan(ipdb, router, "eth0")
        assert isinstance(vlan, Vlan)
        vlan.create_interface()

        # Create Namespace
        namespace = Namespace(ipdb, router.namespace_name)
        assert isinstance(namespace, Namespace)

        # encapsulate VLAN
        namespace.encapsulate_interface(vlan.vlan_iface_name)

        # Test if the namespace now exists
        process = Popen(["ip", "netns"], stdout=PIPE, stderr=PIPE)
        stdout, sterr = process.communicate()
        assert sterr.decode('utf-8') == ""
        assert namespace.nsp_name in stdout.decode('utf-8')

        # Remove the Namespace
        vlan.delete_interface(close_ipdb=True)
        namespace.remove()
        ipdb.release()
        process = Popen(["ip", "netns"], stdout=PIPE, stderr=PIPE)
        stdout, sterr = process.communicate()
        assert stdout.decode('utf-8') == ""
    def test_timeout(self):
        print("Test Dhclient: timeout")
        router = self._create_router()
        # Set VLAN that doesn't exist, so no response occur.
        router._vlan_iface_id = 99
        router._vlan_iface_name = "vlan99"
        ipdb = IPDB()

        try:
            print("Get link-interface ...")
            # Get the real link interface
            link_iface = ipdb.interfaces["eth0"]
            # Create a Vlan
            print("Create VLAN ...")
            with ipdb.create(kind="vlan", ifname=router.vlan_iface_name, link=link_iface,
                             vlan_id=router.vlan_iface_id).commit() as iface:
                print("Update IP with Dhclient ...")
                Dhclient.update_ip(router.vlan_iface_name, timeout=10)
                iface.mtu = 1400
        except TimeoutError:
            print("[+] Test was successful")
        except Exception as e:
            print("Error: " + str(e))
            raise e
        finally:
            print("Delete VLAN ...")
            ipdb.interfaces[router.vlan_iface_name].remove().commit()
            ipdb.release()
예제 #6
0
    def test_create_namespace(self):
        router = self._create_router()

        # Create VLAN
        ipdb = IPDB()
        vlan = Vlan(ipdb, router, "eth0")
        assert isinstance(vlan, Vlan)
        vlan.create_interface()

        # Create Namespace
        namespace = Namespace(ipdb, router.namespace_name)
        assert isinstance(namespace, Namespace)

        # encapsulate VLAN
        namespace.encapsulate_interface(vlan.vlan_iface_name)

        # Test if the namespace now exists
        process = Popen(["ip", "netns"], stdout=PIPE, stderr=PIPE)
        stdout, sterr = process.communicate()
        assert sterr.decode('utf-8') == ""
        assert namespace.nsp_name in stdout.decode('utf-8')

        # Remove the Namespace
        vlan.delete_interface(close_ipdb=True)
        namespace.remove()
        ipdb.release()
        process = Popen(["ip", "netns"], stdout=PIPE, stderr=PIPE)
        stdout, sterr = process.communicate()
        assert stdout.decode('utf-8') == ""
예제 #7
0
    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()
예제 #8
0
 def __init__(self, link_iface_name: str):
     """
     :param link_iface_name: 'physical'-interface like 'eth0' to which the VLAN is connected to
     """
     self.ipdb = IPDB()
     self.link_iface_name = link_iface_name
     self.vlan_dict = dict()
     self.nsp_dict = dict()
예제 #9
0
    def __init__(self, link_iface_name: str):
        """
        Initialize the IPDB for the interfaces and creates a Bridge (virtual switch).

        :param link_iface_name: 'physical'-interface like 'eth0'
        """
        self.ipdb = IPDB()
        self.link_iface_name = link_iface_name
        self.vlan_dict = dict()
        self.veth_dict = dict()
        self.nsp_dict = dict()
예제 #10
0
    def __init__(self,
                 ipdb: IPDB,
                 veth_iface_name1: str,
                 veth_iface_name2: str,
                 veth_iface_ip1: str = None,
                 veth_iface_ip_mask1: int = None,
                 veth_iface_ip2: str = None,
                 veth_iface_ip_mask2: int = None):
        """
        Represents a 'veth'-interface.

        :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.
        :param veth_iface_name1: like veth00
        :param veth_iface_name2: like veth0
        :param veth_iface_ip1:
        :param veth_iface_ip_mask1:
        :param veth_iface_ip2:
        :param veth_iface_ip_mask2:
        """
        self.ipdb = ipdb if ipdb else IPDB()
        self.veth_iface_name1 = veth_iface_name1
        self.veth_iface_name2 = veth_iface_name2
        self.veth_iface_ip1 = veth_iface_ip1
        self.veth_iface_ip_mask1 = veth_iface_ip_mask1
        self.veth_iface_ip2 = veth_iface_ip2
        self.veth_iface_ip_mask2 = veth_iface_ip_mask2
예제 #11
0
    def test_create_vlan(self):
        print("Test if a VLAN can be created")
        router = self._create_router()

        # Create VLAN
        ipdb = IPDB()
        vlan = Vlan(ipdb, router, "eth0")
        vlan.create_interface()
        assert isinstance(vlan, Vlan)

        # Test if the VLAN now exists
        process = Popen(["ip", "link", "show", "dev", vlan.vlan_iface_name],
                        stdout=PIPE,
                        stderr=PIPE)
        stdout, sterr = process.communicate()
        assert sterr.decode('utf-8') == ""
        assert vlan.vlan_iface_name in stdout.decode('utf-8')

        # Remove the VLAN
        vlan.delete_interface(close_ipdb=True)
        process = Popen(["ip", "link", "show", "dev", vlan.vlan_iface_name],
                        stdout=PIPE,
                        stderr=PIPE)
        stdout, sterr = process.communicate()
        assert stdout.decode('utf-8') == ""
예제 #12
0
 def __init__(self, link_iface_name: str):
     """
     :param link_iface_name: 'physical'-interface like 'eth0' to which the VLAN is connected to
     """
     self.ipdb = IPDB()
     self.link_iface_name = link_iface_name
     self.vlan_dict = dict()
     self.nsp_dict = dict()
예제 #13
0
    def __init__(self, link_iface_name: str, vlan_iface_name: str, vlan_iface_id: int, vlan_iface_ip: str=None,
                 vlan_iface_ip_mask: int=None):
        """
        Creats a virtual interface on a existing interface (like eth0).
        It uses 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.

        :param link_iface_name: name of the existing interface (eth0, wlan0, ...)
        :param vlan_iface_name: name of the vlan
        :param vlan_iface_id: the id of the vlan
        :param vlan_iface_ip: ip of the virtual interface
        :param vlan_iface_ip_mask: network-mask of the virtual interface
        """
        self.link_iface_name = link_iface_name
        self.vlan_iface_name = vlan_iface_name
        self.vlan_iface_id = vlan_iface_id
        self.ipdb = IPDB()
예제 #14
0
 def __init__(self, ipdb: IPDB, remote_system: RemoteSystem, link_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.
     :param link_iface_name: name of the existing interface (eth0, wlan0, ...)
     """
     self.ipdb = ipdb if ipdb else IPDB()
     self.remote_system = remote_system
     self.link_iface_name = link_iface_name
     self.vlan_iface_name = str(remote_system.vlan_iface_name)
     self.vlan_iface_id = int(remote_system.vlan_iface_id)
예제 #15
0
    def test_normal_functionality(self):
        print("Test Dhclient: update_ip")
        router = self._create_router()
        ipdb = IPDB()

        try:
            print("Get link-interface ...")
            # Get the real link interface
            link_iface = ipdb.interfaces["eth0"]
            # Create a Vlan
            print("Create VLAN ...")
            with ipdb.create(kind="vlan",
                             ifname=router.vlan_iface_name,
                             link=link_iface,
                             vlan_id=router.vlan_iface_id).commit() as iface:
                print("Update IP with Dhclient ...")
                Dhclient.update_ip(router.vlan_iface_name)
                iface.mtu = 1400
            # Because the IPDB need some time to update the given IP
            sleep(10)
            process = Popen(
                ["ping", "-c", "1", "-I", router.vlan_iface_name, router.ip],
                stdout=PIPE,
                stderr=PIPE)
            stdout, sterr = process.communicate()
            if not (sterr.decode('utf-8') == ""
                    and "Unreachable" not in stdout.decode('utf-8')):
                raise Exception(str(sterr.decode('utf-8')))
            print("[+] Test was successful")
        except Exception as e:
            print("Error: " + str(e))
            raise e
        finally:
            print("Delete VLAN ...")
            ipdb.interfaces[router.vlan_iface_name].remove().commit()
            ipdb.release()
예제 #16
0
    def __init__(self, link_iface_name: str, vlan_iface_name: str, vlan_iface_id: int, vlan_iface_ip: str=None,
                 vlan_iface_ip_mask: int=None):
        """
        Creats a virtual interface on a existing interface (like eth0).
        It uses 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.

        :param link_iface_name: name of the existing interface (eth0, wlan0, ...)
        :param vlan_iface_name: name of the vlan
        :param vlan_iface_id: the id of the vlan
        :param vlan_iface_ip: ip of the virtual interface
        :param vlan_iface_ip_mask: network-mask of the virtual interface
        """
        self.link_iface_name = link_iface_name
        self.vlan_iface_name = vlan_iface_name
        self.vlan_iface_id = vlan_iface_id
        self.ipdb = IPDB()
예제 #17
0
    def __init__(self,
                 ipdb: IPDB,
                 bridge_name: str = 'br0',
                 link_iface_name: str = 'eth0'):
        """
        Creates a 'bridge'-interface.

        :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.
        :param bridge_name: like 'br0'
        :param link_iface_name: like 'eth0'
        """
        self.ipdb = ipdb if ipdb else IPDB()
        self.bridge_name = bridge_name
        self.ipdb.create(kind='bridge', ifname=self.bridge_name).commit()
        # self.ipdb.interfaces[self.bridge_name].up()
        self.add_iface(link_iface_name)
        self.set_new_ip(dhcp=True)
예제 #18
0
 def __init__(self, ipdb: IPDB, nsp_name: str):
     """
     :param ipdb: IPDB is a transactional database, containing records, representing network stack objects.
                  Any change in the database is not reflected immediately in OS, but waits until commit() is called.
     :param nsp_name: Name of the Namespace
     """
     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.error("%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()
예제 #19
0
import logging
log = logging.getLogger(__name__)

__virtual_name__ = 'network_settings'

ATTRS = [
    'family', 'txqlen', 'ipdb_scope', 'index', 'operstate', 'group',
    'carrier_changes', 'ipaddr', 'neighbours', 'ifname', 'promiscuity',
    'linkmode', 'broadcast', 'address', 'num_tx_queues', 'ipdb_priority',
    'change', 'kind', 'qdisc', 'mtu', 'num_rx_queues', 'carrier', 'flags',
    'ifi_type', 'ports'
]

LAST_STATS = {}

IP = IPDB()


class Hashabledict(dict):
    '''
    Helper class that implements a hash function for a dictionary
    '''
    def __hash__(self):
        return hash(tuple(sorted(self.items())))


def __virtual__():
    if HAS_PYROUTE2:
        return __virtual_name__
    return False
예제 #20
0
class NVAssistent:
    """
    The NVAssistent (NamespaceVlanAssistent) provides the following Features:
        1. Creates a IPDB: stores the Network-Interfaces
        2. Creates VLANs and Namespaces
        3. Encapsulates the VLANs inside the Namespaces
        4. Delete VLANs and Namespaces

    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.

    If we want to use VLANs for Systems (with identical IPs) on the network, we need Namespaces. Each Namespace
    encapsulate one VLAN for the current process. The Namespace only contains the given VLAN and the 'lo'-interface.
    If we want to use a physical interface (like 'eth0') we have to create a bridge that connects the physical interface
    with Namespace by the 'veth'-interfaces.
    """ ""

    def __init__(self, link_iface_name: str):
        """
        :param link_iface_name: 'physical'-interface like 'eth0' to which the VLAN is connected to
        """
        self.ipdb = IPDB()
        self.link_iface_name = link_iface_name
        self.vlan_dict = dict()
        self.nsp_dict = dict()

    def create_namespace_vlan(self, remote_system: RemoteSystem):
        """
        Creats a Namespace and a VLAN. Encapsulate the VLAN inside the Namespace.

        :param remote_system: Router-Obj or Powerstrip-Obj with which we want to connect to.
        """
        if remote_system.namespace_name in self.nsp_dict.keys():
            logging.debug("%s[-] Namespace already exists",
                          LoggerSetup.get_log_deep(2))
            return

        vlan = Vlan(self.ipdb, remote_system, self.link_iface_name)
        vlan.create_interface()
        self.vlan_dict[vlan.vlan_iface_name] = vlan

        namespace = Namespace(self.ipdb, str(remote_system.namespace_name))
        namespace.encapsulate_interface(vlan.vlan_iface_name)
        self.nsp_dict[namespace.nsp_name] = namespace

    def get_ip_address(self, namespace_name: str,
                       vlan_iface_name: str) -> (str, int):
        """
        Returns the the first IP of the VLAN in the IPDB of the Namespace

        :param namespace_name: Namespace_name
        :param vlan_iface_name: VLAN_name
        :return: IP address (ip/mask)
        """
        ip_address = self.nsp_dict[namespace_name].ipdb_get_ip(
            ipdb=False, iface_name=vlan_iface_name).split("/")
        ip = ip_address[0]
        mask = int(ip_address[1])
        return ip, mask

    def delete_vlan(self, vlan_iface_name: str):
        """
        Removes the given VLAN.

        :param vlan_iface_name: VLAN_name
        """
        self.vlan_dict[vlan_iface_name].delete_interface()

    def delete_namespace(self, namespace_name: str):
        """
        Removes the given Namespace.

        :param namespace_name: Namespace_name
        """
        self.nsp_dict[namespace_name].remove()

    def close(self):
        """
        Deletes all VLANs and Namespaces and releases the IPDB.
        """
        for vlan in self.vlan_dict:
            self.delete_vlan(vlan)
        for nsp in self.nsp_dict:
            self.delete_namespace(nsp)
        self.ipdb.release()
예제 #21
0
class Vlan:

    def __init__(self, link_iface_name: str, vlan_iface_name: str, vlan_iface_id: int, vlan_iface_ip: str=None,
                 vlan_iface_ip_mask: int=None):
        """
        Creats a virtual interface on a existing interface (like eth0).
        It uses 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.

        :param link_iface_name: name of the existing interface (eth0, wlan0, ...)
        :param vlan_iface_name: name of the vlan
        :param vlan_iface_id: the id of the vlan
        :param vlan_iface_ip: ip of the virtual interface
        :param vlan_iface_ip_mask: network-mask of the virtual interface
        """
        self.link_iface_name = link_iface_name
        self.vlan_iface_name = vlan_iface_name
        self.vlan_iface_id = vlan_iface_id
        self.ipdb = IPDB()
        # self.create_interface(link_iface_name, vlan_iface_name, vlan_iface_id, vlan_iface_ip, vlan_iface_ip_mask)

    def create_interface(self, vlan_iface_ip: str=None, vlan_iface_ip_mask: int=None):
        """
         Creats a virtual interface on a existing interface (like eth0)

        :param vlan_iface_ip: ip of the virtual interface
        :param vlan_iface_ip_mask: network-mask of the virtual interface
        """
        Logger().debug("Create VLAN Interface ...", 2)
        try:
            link_iface = self.ipdb.interfaces[self.link_iface_name]
            with self.ipdb.create(kind="vlan", ifname=self.vlan_iface_name, link=link_iface,
                                  vlan_id=self.vlan_iface_id).commit() as i:
                if vlan_iface_ip:
                    i.add_ip(vlan_iface_ip, vlan_iface_ip_mask)
                i.mtu = 1400
            if not vlan_iface_ip:
                self._wait_for_ip_assignment()
                vlan_iface_ip = self._get_ipv4_from_dictionary(self.ipdb.interfaces[self.vlan_iface_name])
            Logger().debug("[+] " + self.vlan_iface_name + " created with: Link=" + self.link_iface_name +
                           ", VLAN_ID=" + str(self.vlan_iface_id) + ", IP=" + vlan_iface_ip, 3)
        except Exception as e:
            Logger().debug("[-] " + self.vlan_iface_name + " couldn't be created", 3)
            Logger().error(str(e), 3)

    def delete_interface(self):
        """
        Removes the virtual interface
        """
        Logger().debug("Delete VLAN Interface ...", 2)
        try:
            self.ipdb.interfaces[self.vlan_iface_name].remove().commit()
            self.ipdb.release()
            Logger().debug("[+] Interface(" + self.vlan_iface_name + ") successfully deleted", 3)
        except KeyError:
            Logger().debug("[+] Interface(" + self.vlan_iface_name + ") is already deleted", 3)
            return
        except Exception as e:
            Logger().debug("[-] Interface(" + self.vlan_iface_name +
                           ") couldn't be deleted. Try 'ip link delete <vlan_name>'", 3)
            Logger().error(str(e), 3)

    def _wait_for_ip_assignment(self):
        """
        Waits until the dhcp-client got an ip
        """
        Logger().debug("Wait for ip assignment via dhcp for VLAN Interface(" + self.vlan_iface_name + ") ...", 3)
        if not self.get_ip():
            os.system('dhclient ' + self.vlan_iface_name)
            while self.get_ip() is None:
                time.sleep(0.5)

    def get_ip(self) -> str:
        """
        Gets the ip of a specific interface
        :return: the ip of an interface without network-mask
        """
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sockfd = sock.fileno()
        ifreq = struct.pack('16sH14s', self.vlan_iface_name.encode('utf-8'), socket.AF_INET, b'\x00' * 14)
        try:
            res = fcntl.ioctl(sockfd, 0x8915, ifreq)
        except:
            return None
        ip = struct.unpack('16sH2x4s8x', res)[2]
        return socket.inet_ntoa(ip)

    def _get_ipv4_from_dictionary(self, iface) -> str:
        """
        Gets the ip and network-mask from the ipdb

        :param iface: the interface from ipdb
        :return: ip with network-mask
        """
        ipaddr_dictionary = iface.ipaddr
        for i in range(len(ipaddr_dictionary)):
            ip = ipaddr_dictionary[i]['address']
            mask = ipaddr_dictionary[i]['prefixlen']
            if re.match("((((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3})(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))", ip):
                return ip + "/" + str(mask)
        return None
예제 #22
0
class Namespace:
    """
    A Network-Namespace is logically another copy of the network stack,
    with its own routes, firewall rules, and network devices.

    By default a process inherits its Network-Namespace from its parent.
    Initially all the processes share the same default Network-Namespace
    from the init process.
    """""

    def __init__(self, ipdb: IPDB, nsp_name: str):
        """
        :param ipdb: IPDB is a transactional database, containing records, representing network stack objects.
                     Any change in the database is not reflected immediately in OS, but waits until commit() is called.
        :param nsp_name: Name of the Namespace
        """
        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.error("%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()

    def remove(self):
        """
        Removes the Namespace and all included Network-Interfaces.
        """
        logging.debug("%sDelete Namespace ...", LoggerSetup.get_log_deep(2))
        try:
            netns.remove(self.nsp_name)
            self.ipdb_netns.release()
            logging.debug("%s[+] Namespace(" + self.nsp_name + ") successfully deleted", LoggerSetup.get_log_deep(3))
        except Exception as e:
            if re.match("\[Errno 2\]*", str(e)):
                logging.debug("%s[+] Namespace(" + self.nsp_name + ") is already deleted", LoggerSetup.get_log_deep(3))
                return
            logging.error("%s[-] Namespace(" + self.nsp_name +
                          ") couldn't be deleted. Try 'ip netns delete <namespace_name>'", LoggerSetup.get_log_deep(3))
            logging.error("%s" + str(e), LoggerSetup.get_log_deep(3))

    def encapsulate_interface(self, iface_name: str):
        """
        Encapsulate the the given Network-Interface inside the Namespace.

        :param iface_name: Name of the selected Network-Interface
        """
        iface_ip = self.ipdb_get_ip(True, iface_name)
        try:
            with self.ipdb.interfaces[iface_name] as iface:
                iface.net_ns_fd = self.nsp_name
            # the interface automatically switched the database and is now inside ipdb_netns_dictionary[vlan_iface_name]
            with self.ipdb_netns.interfaces[iface_name] as iface:
                iface.add_ip(iface_ip)  # '192.168.1.11/24'
                iface.up()
            logging.debug("%s[+] Encapsulate Interface(" + iface_name + ")", LoggerSetup.get_log_deep(3))
        except Exception as e:
            logging.error("%s[-] Couldn't encapsulate the Interface(" + iface_name + ")", LoggerSetup.get_log_deep(3))
            logging.error("%s" + str(e), LoggerSetup.get_log_deep(3))

    def ipdb_get_ip(self, ipdb: bool, iface_name: str, not_this_ip: str = None):
        """
        Reads the 'first' IP from the IPDB or if intended from IPDN_NETNS.

        :param ipdb: If 'True' IPDB is used, 'False' IPDB_NETNS is used
        :param iface_name: Name of the selected Network-Interface
        :param not_this_ip: If we know the first IP and are searching for another
        :return: IP with the format ip/mask
        """
        if ipdb:
            iface = self.ipdb.interfaces[iface_name]
        else:
            iface = self.ipdb_netns.interfaces[iface_name]
        ipaddr_dictionary = iface.ipaddr
        for i in range(len(ipaddr_dictionary)):
            ip = ipaddr_dictionary[i]['address']
            mask = ipaddr_dictionary[i]['prefixlen']
            if re.match("((((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3})(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))", ip):
                if ip != not_this_ip:
                    return ip + "/" + str(mask)
        return ""
예제 #23
0
class NVAssistent:
    """
    1. Creates a IPDB: stores interfaces
    2. Creates a Bridge: connects multiple interfaces via a virtual switch
    3. Creates VLANs
    4. Creates Veths: connects a Namespace with the Bridge
    5. Creates Namespaces: encapsulte a given Interface

    If we want to use VLANs for Systems (with identical IPs) on the network, we need Namespaces. Each Namespace
    encapsulate one VLAN for the current process. The Namespace only contains the given VLAN and the 'lo'-interface.
    If we want to use a physical interface (like 'eth0') we have to create a bridge that connects the physical interface
    with Namespace by the 'veth'-interfaces.
    """""

    def __init__(self, link_iface_name: str):
        """
        Initialize the IPDB for the interfaces and creates a Bridge (virtual switch).

        :param link_iface_name: 'physical'-interface like 'eth0'
        """
        self.ipdb = IPDB()
        self.link_iface_name = link_iface_name
        self.vlan_dict = dict()
        self.veth_dict = dict()
        self.nsp_dict = dict()

    def create_namespace_vlan(self, remote_system: RemoteSystem):
        """
        Creats a Namespace and a VLAN. Encapsulate the VLAN inside the Namespace.

        :param remote_system: Router or powerstrip
        """
        if remote_system.namespace_name in self.nsp_dict.keys():
            logging.debug("%s[-] Namespace already exists", LoggerSetup.get_log_deep(2))
            return

        vlan = Vlan(self.ipdb, remote_system, self.link_iface_name)
        vlan.create_interface()
        self.vlan_dict[vlan.vlan_iface_name] = vlan

        namespace = Namespace(self.ipdb, str(remote_system.namespace_name))
        namespace.encapsulate_interface(vlan.vlan_iface_name)
        self.nsp_dict[namespace.nsp_name] = namespace

    def get_ip_address(self, namespace_name: str, vlan_iface_name: str) -> (str, int):
        """
        Returns the the first IP of the VLAN in the IPDB of the Namespace

        :param namespace_name: Namespace name
        :param vlan_iface_name: VLAN name
        :return: IP address (ip, mask)
        """
        ip_address = self.nsp_dict[namespace_name].ipdb_get_ip(ipdb=False, iface_name=vlan_iface_name).split("/")
        ip = ip_address[0]
        mask = int(ip_address[1])
        return ip, mask

    def delete_vlan(self, vlan_iface_name: str):
        self.vlan_dict[vlan_iface_name].delete_interface()

    def delete_veth(self, veth_iface_name: str):
        self.veth_dict[veth_iface_name].delete_interface()

    def delete_namespace(self, nsp_name: str):
        self.nsp_dict[nsp_name].remove()

    def close(self):
        """
        Deletes all VLANs, 'veth'-interfaces and Namespaces
        """
        for vlan in self.vlan_dict:
            self.delete_vlan(vlan)
        for veth in self.veth_dict:
            self.delete_veth(veth)
        for nsp in self.nsp_dict:
            self.delete_namespace(nsp)
        self.ipdb.release()
        logging.debug("%sKill dhclient ...", LoggerSetup.get_log_deep(2))
        os.system('pkill dhclient')
예제 #24
0
class Namespace:

    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()

    def remove(self):
        """
        Removes the virtual namespace and interface.
        """
        Logger().debug("Delete Namespace ...", 2)
        try:
            if self.ipdb_netns is None:
                netns.remove(self.nsp_name)
            else:
                self.ipdb_netns.interfaces[self.vlan_iface_name].nl.remove()
                self.ipdb_netns.release()
            Logger().debug("[+] Namespace(" + self.nsp_name + ") successfully deleted", 3)
        except Exception as e:
            if re.match("\[Errno 2\]*",str(e)):
                Logger().debug("[+] Namespace(" + self.nsp_name + ") is already deleted", 3)
                return
            Logger().debug("[-] Namespace(" + self.nsp_name +
                           ") couldn't be deleted. Try 'ip netns delete <namespace_name>'", 3)
            Logger().error(str(e), 3)

    def encapsulate_interface(self, vlan_iface_name: str):
        """
        Capture the assigned interface in a namespace.
        """
        self.vlan_iface_name = vlan_iface_name
        self.vlan_iface_ip = self._get_ipv4_from_dictionary(self.ipdb.interfaces[self.vlan_iface_name])
        try:
            with self.ipdb.interfaces[self.vlan_iface_name] as vlan:
                vlan.net_ns_fd = self.nsp_name
            # the interface automatically switched the database and is now inside ipdb_netns_dictionary[vlan_iface_name]
            with self.ipdb_netns.interfaces[self.vlan_iface_name] as vlan:
                vlan.add_ip(self.vlan_iface_ip)  # '192.168.1.11/24'
                vlan.up()
            Logger().debug("[+] Encapsulate Interface(" + self.vlan_iface_name + ")", 3)
        except Exception as e:
            Logger().debug("[-] Couldn't encapsulate the Interface(" + self.vlan_iface_name + ")", 3)
            Logger().error(str(e), 3)

    def get_ip_of_encapsulate_interface(self) -> str:
        """
        :return: The IP(without ip_mask) of the interface encapsulated in this namespace
        """
        return self.vlan_iface_ip.split('/')[0]

    def _get_ipv4_from_dictionary(self, iface) -> str:
        """
        Gets the ip and network-mask from the ipdb

        :param iface: the interface from ipdb
        :return: ip with network-mask
        """
        ipaddr_dictionary = iface.ipaddr
        for i in range(len(ipaddr_dictionary)):
            ip = ipaddr_dictionary[i]['address']
            mask = ipaddr_dictionary[i]['prefixlen']
            if re.match("((((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3})(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))", ip):
                return ip+"/"+str(mask)
예제 #25
0
class Namespace:
    """
    A Network-Namespace is logically another copy of the network stack,
    with its own routes, firewall rules, and network devices.

    By default a process inherits its Network-Namespace from its parent.
    Initially all the processes share the same default Network-Namespace
    from the init process.
    """ ""

    def __init__(self, ipdb: IPDB, nsp_name: str):
        """
        :param ipdb: IPDB is a transactional database, containing records, representing network stack objects.
                     Any change in the database is not reflected immediately in OS, but waits until commit() is called.
        :param nsp_name: Name of the Namespace
        """
        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.error("%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()

    def remove(self):
        """
        Removes the Namespace and all included Network-Interfaces.
        """
        logging.debug("%sDelete Namespace ...", LoggerSetup.get_log_deep(2))
        try:
            netns.remove(self.nsp_name)
            self.ipdb_netns.release()
            logging.debug(
                "%s[+] Namespace(" + self.nsp_name + ") successfully deleted",
                LoggerSetup.get_log_deep(3))
        except Exception as e:
            if re.match("\[Errno 2\]*", str(e)):
                logging.debug(
                    "%s[+] Namespace(" + self.nsp_name +
                    ") is already deleted", LoggerSetup.get_log_deep(3))
                return
            logging.error(
                "%s[-] Namespace(" + self.nsp_name +
                ") couldn't be deleted. Try 'ip netns delete <namespace_name>'",
                LoggerSetup.get_log_deep(3))
            logging.error("%s" + str(e), LoggerSetup.get_log_deep(3))

    def encapsulate_interface(self, iface_name: str):
        """
        Encapsulate the the given Network-Interface inside the Namespace.

        :param iface_name: Name of the selected Network-Interface
        """
        iface_ip = self.ipdb_get_ip(True, iface_name)
        try:
            with self.ipdb.interfaces[iface_name] as iface:
                iface.net_ns_fd = self.nsp_name
            # the interface automatically switched the database and is now inside ipdb_netns_dictionary[vlan_iface_name]
            with self.ipdb_netns.interfaces[iface_name] as iface:
                iface.add_ip(iface_ip)  # '192.168.1.11/24'
                iface.up()
            logging.debug("%s[+] Encapsulate Interface(" + iface_name + ")",
                          LoggerSetup.get_log_deep(3))
        except Exception as e:
            logging.error(
                "%s[-] Couldn't encapsulate the Interface(" + iface_name + ")",
                LoggerSetup.get_log_deep(3))
            logging.error("%s" + str(e), LoggerSetup.get_log_deep(3))

    def ipdb_get_ip(self,
                    ipdb: bool,
                    iface_name: str,
                    not_this_ip: str = None):
        """
        Reads the 'first' IP from the IPDB or if intended from IPDN_NETNS.

        :param ipdb: If 'True' IPDB is used, 'False' IPDB_NETNS is used
        :param iface_name: Name of the selected Network-Interface
        :param not_this_ip: If we know the first IP and are searching for another
        :return: IP with the format ip/mask
        """
        if ipdb:
            iface = self.ipdb.interfaces[iface_name]
        else:
            iface = self.ipdb_netns.interfaces[iface_name]
        ipaddr_dictionary = iface.ipaddr
        for i in range(len(ipaddr_dictionary)):
            ip = ipaddr_dictionary[i]['address']
            mask = ipaddr_dictionary[i]['prefixlen']
            if re.match(
                    "((((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3})(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))",
                    ip):
                if ip != not_this_ip:
                    return ip + "/" + str(mask)
        return ""
예제 #26
0
class Vlan:
    def __init__(self,
                 link_iface_name: str,
                 vlan_iface_name: str,
                 vlan_iface_id: int,
                 vlan_iface_ip: str = None,
                 vlan_iface_ip_mask: int = None):
        """
        Creats a virtual interface on a existing interface (like eth0).
        It uses 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.

        :param link_iface_name: name of the existing interface (eth0, wlan0, ...)
        :param vlan_iface_name: name of the vlan
        :param vlan_iface_id: the id of the vlan
        :param vlan_iface_ip: ip of the virtual interface
        :param vlan_iface_ip_mask: network-mask of the virtual interface
        """
        self.link_iface_name = link_iface_name
        self.vlan_iface_name = vlan_iface_name
        self.vlan_iface_id = vlan_iface_id
        self.ipdb = IPDB()
        # self.create_interface(link_iface_name, vlan_iface_name, vlan_iface_id, vlan_iface_ip, vlan_iface_ip_mask)

    def create_interface(self,
                         vlan_iface_ip: str = None,
                         vlan_iface_ip_mask: int = None):
        """
         Creats a virtual interface on a existing interface (like eth0)

        :param vlan_iface_ip: ip of the virtual interface
        :param vlan_iface_ip_mask: network-mask of the virtual interface
        """
        Logger().debug("Create VLAN Interface ...", 2)
        try:
            link_iface = self.ipdb.interfaces[self.link_iface_name]
            with self.ipdb.create(kind="vlan",
                                  ifname=self.vlan_iface_name,
                                  link=link_iface,
                                  vlan_id=self.vlan_iface_id).commit() as i:
                if vlan_iface_ip:
                    i.add_ip(vlan_iface_ip, vlan_iface_ip_mask)
                i.mtu = 1400
            if not vlan_iface_ip:
                self._wait_for_ip_assignment()
                vlan_iface_ip = self._get_ipv4_from_dictionary(
                    self.ipdb.interfaces[self.vlan_iface_name])
            Logger().debug(
                "[+] " + self.vlan_iface_name + " created with: Link=" +
                self.link_iface_name + ", VLAN_ID=" + str(self.vlan_iface_id) +
                ", IP=" + vlan_iface_ip, 3)
        except Exception as e:
            Logger().debug(
                "[-] " + self.vlan_iface_name + " couldn't be created", 3)
            Logger().error(str(e), 3)

    def delete_interface(self):
        """
        Removes the virtual interface
        """
        Logger().debug("Delete VLAN Interface ...", 2)
        try:
            self.ipdb.interfaces[self.vlan_iface_name].remove().commit()
            self.ipdb.release()
            Logger().debug(
                "[+] Interface(" + self.vlan_iface_name +
                ") successfully deleted", 3)
        except KeyError:
            Logger().debug(
                "[+] Interface(" + self.vlan_iface_name +
                ") is already deleted", 3)
            return
        except Exception as e:
            Logger().debug(
                "[-] Interface(" + self.vlan_iface_name +
                ") couldn't be deleted. Try 'ip link delete <vlan_name>'", 3)
            Logger().error(str(e), 3)

    def _wait_for_ip_assignment(self):
        """
        Waits until the dhcp-client got an ip
        """
        Logger().debug(
            "Wait for ip assignment via dhcp for VLAN Interface(" +
            self.vlan_iface_name + ") ...", 3)
        if not self.get_ip():
            os.system('dhclient ' + self.vlan_iface_name)
            while self.get_ip() is None:
                time.sleep(0.5)

    def get_ip(self) -> str:
        """
        Gets the ip of a specific interface
        :return: the ip of an interface without network-mask
        """
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sockfd = sock.fileno()
        ifreq = struct.pack('16sH14s', self.vlan_iface_name.encode('utf-8'),
                            socket.AF_INET, b'\x00' * 14)
        try:
            res = fcntl.ioctl(sockfd, 0x8915, ifreq)
        except:
            return None
        ip = struct.unpack('16sH2x4s8x', res)[2]
        return socket.inet_ntoa(ip)

    def _get_ipv4_from_dictionary(self, iface) -> str:
        """
        Gets the ip and network-mask from the ipdb

        :param iface: the interface from ipdb
        :return: ip with network-mask
        """
        ipaddr_dictionary = iface.ipaddr
        for i in range(len(ipaddr_dictionary)):
            ip = ipaddr_dictionary[i]['address']
            mask = ipaddr_dictionary[i]['prefixlen']
            if re.match(
                    "((((\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3})(\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]))",
                    ip):
                return ip + "/" + str(mask)
        return None
예제 #27
0
class NVAssistent:
    """
    The NVAssistent (NamespaceVlanAssistent) provides the following Features:
        1. Creates a IPDB: stores the Network-Interfaces
        2. Creates VLANs and Namespaces
        3. Encapsulates the VLANs inside the Namespaces
        4. Delete VLANs and Namespaces

    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.

    If we want to use VLANs for Systems (with identical IPs) on the network, we need Namespaces. Each Namespace
    encapsulate one VLAN for the current process. The Namespace only contains the given VLAN and the 'lo'-interface.
    If we want to use a physical interface (like 'eth0') we have to create a bridge that connects the physical interface
    with Namespace by the 'veth'-interfaces.
    """""

    def __init__(self, link_iface_name: str):
        """
        :param link_iface_name: 'physical'-interface like 'eth0' to which the VLAN is connected to
        """
        self.ipdb = IPDB()
        self.link_iface_name = link_iface_name
        self.vlan_dict = dict()
        self.nsp_dict = dict()

    def create_namespace_vlan(self, remote_system: RemoteSystem):
        """
        Creats a Namespace and a VLAN. Encapsulate the VLAN inside the Namespace.

        :param remote_system: Router-Obj or Powerstrip-Obj with which we want to connect to.
        """
        if remote_system.namespace_name in self.nsp_dict.keys():
            logging.debug("%s[-] Namespace already exists", LoggerSetup.get_log_deep(2))
            return

        vlan = Vlan(self.ipdb, remote_system, self.link_iface_name)
        vlan.create_interface()
        self.vlan_dict[vlan.vlan_iface_name] = vlan

        namespace = Namespace(self.ipdb, str(remote_system.namespace_name))
        namespace.encapsulate_interface(vlan.vlan_iface_name)
        self.nsp_dict[namespace.nsp_name] = namespace

    def get_ip_address(self, namespace_name: str, vlan_iface_name: str) -> (str, int):
        """
        Returns the the first IP of the VLAN in the IPDB of the Namespace

        :param namespace_name: Namespace_name
        :param vlan_iface_name: VLAN_name
        :return: IP address (ip/mask)
        """
        ip_address = self.nsp_dict[namespace_name].ipdb_get_ip(ipdb=False, iface_name=vlan_iface_name).split("/")
        ip = ip_address[0]
        mask = int(ip_address[1])
        return ip, mask

    def delete_vlan(self, vlan_iface_name: str):
        """
        Removes the given VLAN.

        :param vlan_iface_name: VLAN_name
        """
        self.vlan_dict[vlan_iface_name].delete_interface()

    def delete_namespace(self, namespace_name: str):
        """
        Removes the given Namespace.

        :param namespace_name: Namespace_name
        """
        self.nsp_dict[namespace_name].remove()

    def close(self):
        """
        Deletes all VLANs and Namespaces and releases the IPDB.
        """
        for vlan in self.vlan_dict:
            self.delete_vlan(vlan)
        for nsp in self.nsp_dict:
            self.delete_namespace(nsp)
        self.ipdb.release()