def test_validation_failures(monkeypatch):
    """
    .
    """

    def fake_validation_errors(self) -> List[str]:
        """
        .
        """
        return ["error"] if self.number == 10 else ["failure", "issue"]

    monkeypatch.setattr(Rule, "validation_errors", fake_validation_errors)
    monkeypatch.setattr(Firewall, "validation_errors", lambda self: ["an error"])

    firewall = Firewall(
        "firewall",
        "in",
        "network",
        ".",
        rules=[Rule(10, "firewall", "."), Rule(20, "firewall", ".")],
    )
    assert firewall.validation_failures() == [
        "an error",
        "error",
        "failure",
        "issue",
    ], "Validation failures are correct"
def test_validate(monkeypatch):
    """
    .
    """

    # pylint: disable=unused-argument
    @counter_wrapper
    def fake_validate(self):
        """
        .
        """
        return True

    monkeypatch.setattr(Rule, "validate", fake_validate)

    firewall = Firewall(
        "firewall",
        "in",
        "network",
        ".",
        rules=[Rule(1, "firewall", "."), Rule(2, "firewall", ".")],
    )
    assert firewall.validate(), "Firewall is valid"
    assert fake_validate.counter == 2, "Validation called for each rule"

    monkeypatch.setattr(Rule, "validate", lambda self: False)
    assert not firewall.validate(), "Rule validation fails"
Exemple #3
0
def test_is_consistent(monkeypatch):
    """
    .
    """

    # pylint: disable=unused-argument
    @counter_wrapper
    def fake_host_consistent(self):
        """
        .
        """
        return True

    monkeypatch.setattr(Host, "is_consistent", fake_host_consistent)

    host1 = Host("test", None, ".", address="11.0.0.1", mac="ab:cd:ef")
    host2 = Host("test2", None, ".", address="10.0.0.1", mac="ab:cd:ef")
    host3 = Host("test3", None, ".", address="11.0.0.1", mac="ab:cd:12")
    host4 = Host("test4", None, ".", address="10.0.0.2", mac="12:34:56")

    firewall1 = Firewall("firewall", "in", "network", ".")
    firewall2 = Firewall("firewall2", "out", "network", ".")

    network_properties = {
        "firewalls": [firewall1, firewall2],
        "hosts": [host1, host2, host3, host4],
        "default-router": "192.168.0.1",
        "start": "10.10.0.100",
        "stop": "10.10.0.255",
        "interface-name": "eth0",
    }
    network = Network("network", None, ".", "10.0.0.0/24",
                      **network_properties)

    assert not network.is_consistent(), "Network is not consistent"
    assert network.validation_errors() == [
        "Default router not in Network network",
        "DHCP start address not in Network network",
        "DHCP stop address not in Network network",
        "Host test not in Network network",
        "Host test3 not in Network network",
        "Host test shares an address with: Host test3",
        "Host test shares its mac with: Host test2",
    ], "Validation errors set"

    assert fake_host_consistent.counter == 4, "Four hosts' consistency checked"

    network_properties = {
        "firewalls": [firewall1, firewall2],
        "hosts": [host2, host4],
        "default-router": "10.0.0.1",
        "start": "10.0.0.100",
        "stop": "10.0.0.255",
        "interface-name": "eth0",
    }
    network = Network("network", None, ".", "10.0.0.0/24",
                      **network_properties)
    assert network.is_consistent(), "Network should be consistent"
    assert not network.validation_errors(), "No validation errors present"
Exemple #4
0
def test_validate(monkeypatch):
    """
    .
    """

    # pylint: disable=unused-argument
    @counter_wrapper
    def fake_validate(self):
        """
        .
        """
        return True

    monkeypatch.setattr(file_paths, "get_folders_with_config",
                        lambda folder: [])
    monkeypatch.setattr(Firewall, "validate", fake_validate)
    monkeypatch.setattr(Host, "validate", fake_validate)
    network = Network(
        "network", None, ".", "1.1.1.1/24", **{
            "interface-name": "eth0",
            "firewalls": [Firewall("firewall", "local", "network", ".")],
            "hosts": [Host("host", None, ".", "192.168.0.1")],
        })

    assert network.validate(), "Network is valid"
    assert fake_validate.counter == 4, "Called for all three firewalls and host"
    def __init__(self,
                 name: str,
                 nat: NAT,
                 config_path: str,
                 cidr: str = None,
                 **kwargs):
        super().__init__(NETWORK_TYPES, ["name", "cidr", "firewalls", "hosts"])
        self.name = name
        self.nat = nat
        self.cidr = cidr
        self.config_path = config_path
        self.interface_name = kwargs["interface-name"]
        self._add_keyword_attributes(kwargs)

        self.firewalls_by_direction = {}
        if "firewalls" not in kwargs:
            self._load_firewalls()

        for firewall in self.firewalls:
            if hasattr(firewall, "direction"):
                self.firewalls_by_direction[firewall.direction] = firewall

        # Add placeholder for any missing firewalls
        firewall_properties = {"default-action": "accept"}
        for firewall_direction in ["in", "out", "local"]:
            if firewall_direction not in self.firewalls_by_direction:
                new_firewall = Firewall(
                    self.name + "-" + firewall_direction.upper(),
                    firewall_direction, self.name, self.config_path,
                    **firewall_properties)
                self.firewalls.append(new_firewall)
                self.firewalls_by_direction[firewall_direction] = new_firewall

        if "hosts" not in kwargs:
            self._load_hosts()
 def _load_firewalls(self) -> None:
     """
     Load firewalls for this network
     """
     self.firewalls = [
         Firewall(firewall_path.split(path.sep)[-2],
                  network_name=self.name,
                  config_path=self.config_path,
                  **(file_paths.load_yaml_from_file(firewall_path)))
         for firewall_path in file_paths.get_folders_with_config([
             self.config_path,
             file_paths.NETWORK_FOLDER,
             self.name,
             file_paths.FIREWALL_FOLDER,
         ])
     ]
def test_rules():
    """
    .
    """
    firewall = Firewall("firewall", "in", "network", ".")
    firewall.add_rule(
        {"number": "10", "action": "reject", "protocol": "tcp", "config_path": "."}
    )
    firewall.add_rule({"action": "reject", "protocol": "udp", "config_path": "."})
    assert [rule.number for rule in firewall.rules] == [
        "10",
        20,
    ], "Rule numbers returned"
def test_commands(monkeypatch):
    """
    .
    """

    # pylint: disable=unused-argument
    @counter_wrapper
    def rule_commands(self) -> List[str]:
        commands = []
        if rule_commands.counter == 1:
            commands = ["rule1-command1", "rule1-command2"]
        else:
            commands = ["rule2-command1", "rule2-command2", "rule2-command3"]

        return commands

    monkeypatch.setattr(Rule, "commands", rule_commands)

    firewall_properties = {
        "default-action": "drop",
        "description": "A in-firewall description",
        "rules": [Rule(10, "firewall1", "."), Rule(20, "firewall1", ".")],
    }
    firewall = Firewall("firewall1", "in", "network1", ".", **firewall_properties)
    ordered_commands, command_list = firewall.commands()
    assert command_list == [
        "firewall name firewall1 default-action drop",
        "firewall name firewall1 description 'A in-firewall description'",
        "rule1-command1",
        "rule1-command2",
        "rule2-command1",
        "rule2-command2",
        "rule2-command3",
    ], "Commands generated correctly"

    assert ordered_commands == [
        [
            "firewall name firewall1 default-action drop",
            "firewall name firewall1 description 'A in-firewall description'",
        ],
        ["rule1-command1", "rule1-command2"],
        ["rule2-command1", "rule2-command2", "rule2-command3"],
    ], "Ordered commands correct"

    firewall = Firewall("firewall1", "in", "network1", ".", description="Description")
    ordered_commands, command_list = firewall.commands()
    assert command_list == [
        "firewall name firewall1 default-action accept",
        "firewall name firewall1 description 'Description'",
    ], "Description command is quoted"
def test_firewall_calls_methods(monkeypatch):
    """
    .
    """

    # pylint: disable=unused-argument
    @counter_wrapper
    def fake_set_attrs(self, attrs: dict):
        """
        .
        """

    monkeypatch.setattr(Firewall, "_add_keyword_attributes", fake_set_attrs)
    firewall = Firewall("firewall", "in", "network", ".")

    assert firewall.name == "firewall", "Name set"
    assert fake_set_attrs.counter == 1, "Set attrs called"

    assert str(firewall) == "Firewall firewall", "Name returned"
    assert getattr(firewall, "auto-increment") == 10, "Auto increment set to default"
def test_get_next_number():
    """
    .
    """
    properties = {
        "rules": [Rule(11, "firewall", "."), Rule(100, "firewall", ".")],
        "auto-increment": 100,
    }
    firewall = Firewall("firewall", "in", "network", ".", **properties)
    assert getattr(firewall, "auto-increment") == 100, "Auto increment overridden"
    assert firewall.next_rule_number() == 200, "Next rule number correct"

    firewall.add_rule({"number": 200, "config_path": "."})
    assert (
        firewall.next_rule_number() == 300
    ), "Next rule number updated after adding rule"
def test_load_rules(monkeypatch):
    """
    .
    """
    monkeypatch.setattr(
        file_paths,
        "get_config_files",
        lambda path: [
            "networks/network1/firewalls/firewall1/config.yaml",
            "networks/network1/firewalls/firewall1/10.yaml",
            "networks/network1/firewalls/firewall1/20.yaml",
            "networks/network1/firewalls/firewall1/30.yaml",
        ],
    )
    monkeypatch.setattr(file_paths, "load_yaml_from_file", lambda path: {})

    firewall = Firewall("firewall", "in", "network", ".")
    assert len(firewall.rules) == 3, "Three rules loaded"
    assert [rule.number for rule in firewall.rules] == [
        "10",
        "20",
        "30",
    ], "Rule numbers correct"
Exemple #12
0
def test_validation_failures(monkeypatch):
    """
    .
    """
    monkeypatch.setattr(file_paths, "get_folders_with_config",
                        lambda folder: [])

    network = Network(
        "network", None, ".", "1.1.1.1/24", **{
            "interface-name":
            "eth0",
            "firewalls": [Firewall("firewall", "in", "network", ".")],
            "hosts": [
                Host("host", None, ".", "192.168.0.1"),
                Host("host2", None, ".", "192.168.0.1"),
            ],
        })
    assert network.validation_failures() == [], "No failures added yet"

    monkeypatch.setattr(Firewall, "validation_failures",
                        lambda self: ["abc", "def"])
    monkeypatch.setattr(Host, "validation_errors", lambda self: ["ghi"])
    network.add_validation_error("failure")

    assert network.validation_failures() == [
        "failure",
        # Firewall failures repeated three times, one for each
        "abc",
        "def",
        "abc",
        "def",
        "abc",
        "def",
        "ghi",
        "ghi",
    ], "Failures returned for network and all children"
Exemple #13
0
def test_host_firewall_consistency(monkeypatch):
    """
    .
    """
    monkeypatch.setattr(secondary_configs, "get_port_groups", lambda config_path: [])
    monkeypatch.setattr(Host, "add_firewall_rules", lambda self: None)

    network = Network(
        "network", None, ".", "192.168.0.0/24", **{"interface-name": "eth0"}
    )

    attrs = {
        "address-groups": ["an-address"],
        "connections": [
            {
                "allow": True,
                "rule": 10,
                "source": {"address": "an-address"},
                "destination": {"port": 80},
            },
            {
                "allow": False,
                "rule": 10,
                "source": {"address": "12.10.12.12", "port": 8080},
            },
            {
                "allow": False,
                "rule": 20,
                "source": {"address": "an-address"},
                "destination": {"port": 443},
            },
            {
                "allow": False,
                "rule": 20,
                "source": {"address": "an-address"},
                "destination": {"port": 4443},
            },
        ],
    }
    host = Host("host", network, ".", "12.10.12.12", **attrs)
    assert not host.is_consistent(), "Duplicate rules inconsistent"
    assert host.validation_errors() == [
        "Host host has duplicate firewall rules: 10, 20"
    ], "Duplicate rules errors set"

    firewall_in = Firewall(
        "firewall-in",
        "in",
        "network",
        ".",
        rules=[Rule(10, "firewall-in", "."), Rule(30, "firewall-in", ".")],
    )
    firewall_out = Firewall(
        "firewall-out",
        "out",
        "network",
        ".",
        rules=[Rule(20, "firewall-out", "."), Rule(40, "firewall-out", ".")],
    )
    network = Network(
        "network",
        None,
        ".",
        "192.168.0.0/24",
        **{"interface-name": "eth0", "firewalls": [firewall_in, firewall_out],}
    )
    attrs = {
        "address-groups": ["an-address"],
        "connections": [
            {
                "allow": True,
                "rule": 10,
                "source": {"address": "an-address"},
                "destination": {"port": 80},
            },
            {
                "allow": False,
                "rule": 20,
                "source": {"address": "an-address"},
                "destination": {"port": 443},
            },
        ],
    }
    host = Host("host", network, ".", "192.168.0.1", **attrs)
    assert not host.is_consistent(), "Rules conflicting with firewall is inconsistent"
    assert host.validation_errors() == [
        "Host host has conflicting connection rule with Firewall firewall-in, "
        "rule number 10",
        "Host host has conflicting connection rule with Firewall firewall-out, "
        "rule number 20",
    ], "Firewall rule conflict errors set"
Exemple #14
0
 def from_config(*args, **kwargs):
     interface_name = {
         "interface-name": "eth0",
         "start": "10.10.0.100",
         "stop": "10.10.0.254",
     }
     if from_config.counter % 2:
         return root_parser.RootNode(
             GlobalSettings(),
             [],
             ExternalAddresses([]),
             [
                 Network(
                     "network1",
                     NAT(".", []),
                     ".",
                     "10.10.0.0/24",
                     firewalls=[
                         Firewall("n1f1", "in", "network1", ".", rules=[]),
                         Firewall("n1f2", "out", "network1", ".", rules=[]),
                     ],
                     hosts=[],
                     **interface_name),
                 Network(
                     "network2",
                     NAT(".", []),
                     ".",
                     "10.11.0.0/24",
                     firewalls=[
                         Firewall("n2f1", "in", "network2", ".", rules=[]),
                         Firewall("n2f2", "out", "network2", ".", rules=[]),
                     ],
                     hosts=[],
                     **interface_name),
                 Network("network3",
                         NAT(".", []),
                         ".",
                         "10.12.0.0/24",
                         firewalls=[
                             Firewall(
                                 "n3f1", "in", "network3", ".", rules=[]),
                         ],
                         hosts=[],
                         **interface_name),
             ],
             NAT(".", []),
         )
     else:
         return root_parser.RootNode(
             GlobalSettings(),
             [],
             ExternalAddresses([]),
             [
                 Network(
                     "network4",
                     NAT(".", []),
                     ".",
                     "10.13.0.0/24",
                     firewalls=[
                         Firewall("n4f1", "in", "network4", ".", rules=[]),
                         Firewall("n4f2", "out", "network4", ".", rules=[]),
                     ],
                     hosts=[],
                     **interface_name),
                 Network(
                     "network2",
                     NAT(".", []),
                     ".",
                     "10.11.0.0/24",
                     firewalls=[
                         Firewall("n2f1", "in", "network2", ".", rules=[]),
                         Firewall("n2f2", "out", "network2", ".", rules=[]),
                     ],
                     hosts=[],
                     **interface_name),
                 Network(
                     "network3",
                     NAT(".", []),
                     ".",
                     "10.12.0.0/24",
                     firewalls=[
                         Firewall("n3f1", "in", "network3", ".", rules=[]),
                         Firewall("n3f2", "in", "network3", ".", rules=[]),
                     ],
                     hosts=[],
                     **interface_name),
             ],
             NAT(".", []),
         )
Exemple #15
0
def test_command_ordering(monkeypatch):
    """
    .
    """

    # pylint: disable=unused-argument
    @counter_wrapper
    def get_firewall_commands(self):
        """
        .
        """
        if get_firewall_commands.counter == 1:
            commands = (
                [["firewall1-command"], ["firewall1-command2"]],
                ["firewall1-command", "firewall1-command2"],
            )
        elif get_firewall_commands.counter == 2:
            commands = (
                [["firewall2-command", "firewall2-command2"],
                 ["firewall2-command3"]],
                [
                    "firewall2-command", "firewall2-command2",
                    "firewall2-command3"
                ],
            )
        else:
            commands = ([["firewall3-command"]], ["firewall3-command"])

        return commands

    monkeypatch.setattr(Firewall, "commands", get_firewall_commands)

    host_properties = {
        "mac": "abc",
        "address": "123",
        "address-groups": ["desktop", "windows"],
    }
    network_properties = {
        "domain-name":
        "test.domain",
        "default-router":
        "192.168.0.1",
        "lease":
        86400,
        "start":
        "192.168.0.100",
        "stop":
        "192.168.0.254",
        "interface-name":
        "eth0",
        "interface-description":
        "the interface",
        "hosts": [
            Host("host1", None, ".", **host_properties),
            Host("host2", None, ".", mac="def", address="234"),
        ],
        "firewalls": [
            Firewall("firewall1", "in", "network", "."),
            Firewall("firewall2", "out", "network", "."),
        ],
    }
    network = Network("network1", None, ".", "192.168.0.0/24",
                      **network_properties)
    ordered_commands, command_list = network.commands()

    base = "service dhcp-server shared-network-name network1 "
    subnet_base = base + "subnet 192.168.0.0/24 "
    mapping_base = subnet_base + "static-mapping "
    interface_base = "interfaces ethernet eth0 "

    assert command_list == [
        subnet_base + "domain-name test.domain",
        subnet_base + "default-router 192.168.0.1",
        subnet_base + "lease 86400",
        subnet_base + "start 192.168.0.100 stop 192.168.0.254",
        interface_base + "address 192.168.0.1/24",
        interface_base + "description 'the interface'",
        "firewall1-command",
        "firewall1-command2",
        interface_base + "firewall in name firewall1",
        "firewall2-command",
        "firewall2-command2",
        "firewall2-command3",
        interface_base + "firewall out name firewall2",
        "firewall3-command",
        interface_base + "firewall local name network1-LOCAL",
        mapping_base + "host1 ip-address 123",
        mapping_base + "host1 mac-address abc",
        mapping_base + "host2 ip-address 234",
        mapping_base + "host2 mac-address def",
    ], "Network commands correct"

    assert ordered_commands == [
        [
            subnet_base + "domain-name test.domain",
            subnet_base + "default-router 192.168.0.1",
            subnet_base + "lease 86400",
            subnet_base + "start 192.168.0.100 stop 192.168.0.254",
            interface_base + "address 192.168.0.1/24",
            interface_base + "description 'the interface'",
        ],
        [
            "firewall1-command",
            "firewall2-command",
            "firewall2-command2",
            "firewall3-command",
        ],
        ["firewall1-command2", "firewall2-command3"],
        [
            "interfaces ethernet eth0 firewall in name firewall1",
            "interfaces ethernet eth0 firewall out name firewall2",
            "interfaces ethernet eth0 firewall local name network1-LOCAL",
        ],
        [
            mapping_base + "host1 ip-address 123",
            mapping_base + "host1 mac-address abc",
            mapping_base + "host2 ip-address 234",
            mapping_base + "host2 mac-address def",
        ],
    ], "Ordered network commands correct"