ok

Mini Shell

Direktori : /opt/imunify360/venv/lib/python3.11/site-packages/im360/internals/core/firewall/
Upload File :
Current File : //opt/imunify360/venv/lib/python3.11/site-packages/im360/internals/core/firewall/__init__.py

import os
from functools import lru_cache
from typing import AbstractSet, Tuple

from defence360agent.utils import subprocess
from defence360agent.utils.common import LooseVersion
from im360.contracts.config import Firewall, UnifiedAccessLogger
from im360.utils.validate import IP, IPVersion

from .iptables import Iptables

#: Firewall rule definition represented as iptables command-line args
RuleDef = Tuple[str, ...]  # TypeAlias 3.10+


@lru_cache(maxsize=1)
def iptables_version():
    cmd = ["iptables", "-V"]
    out = subprocess.check_output(cmd, stderr=subprocess.PIPE)
    _, vstring = out.decode().split("v")
    return vstring.strip()


@lru_cache()
def is_nat_available(ip_version: IPVersion):
    """ip6tables nat table correctly works only with
    kernel version >= 3.8 and
    iptables version >= 1.4.18

    https://sector7g.be/posts/ipv6-nat-pre-routing-with-iptables
    """
    if ip_version == IP.V4:
        return True
    else:
        return iptables_version() >= LooseVersion("1.4.18")


async def get_firewall(ip_version: IPVersion):
    return Iptables(version=iptables_version(), ip_version=ip_version)


@lru_cache(maxsize=1)
def firewall_logging_enabled():
    return not os.path.exists(Firewall.LOGGING_DISABLE_FLAG)


class FirewallRules:
    # The lower number the higher is the priority.
    # 0 is the highest priority
    # priority is used to create rules in correct order
    HIGHEST_PRIORITY = 0

    # Priority for remote-proxy rules
    REMOTE_PROXY_PRIORITY = 2

    # Priority for rule for whitelisted ips with full access
    FULL_ACCESS_PRIORITY = 4

    # Priority for blocked ports rules
    PORT_PROTO_PRIORITY = 6

    # priority for ipset with ip of current host
    HOST_IPS_PRIORITY = 6

    # Common whitelist
    WHITELIST_PRIORITY = 8

    # Black list (both country and user-defined)
    BLACKLIST_PRIORITY = 10

    # Static whitelist
    STATIC_WHITELIST_PRIORITY = 12

    # drop.sync
    DROP_SYNC_PRIORITY = 14

    # default priority for rules
    DEFAULT_PRIORITY = 20

    LOWEST_PRIORITY = 30

    ACCEPT = "ACCEPT"
    DROP = "DROP"
    RETURN = "RETURN"
    REJECT = "REJECT"
    REDIRECT = "REDIRECT"
    LOG = "LOG"

    FILTER, NAT, MANGLE = "filter", "nat", "mangle"

    IMUNIFY_INPUT_CHAIN = "INPUT_imunify360"
    IMUNIFY_OUTPUT_CHAIN = "OUTPUT_imunify360"
    COUNTRY_BLACKLIST_CHAIN = "imunify360_country_blacklist"
    COUNTRY_WHITELIST_CHAIN = "imunify360_country_whitelist"
    BP_INPUT_CHAIN = "INPUT_imunify360_bp"
    BP_OUTPUT_CHAIN = "OUTPUT_imunify360_bp"
    LOG_BLACKLIST_CHAIN = "imunify360_log_bl"
    LOG_BLACKLISTED_COUNTRY_CHAIN = "imunify360_log_bl_country"
    LOG_GRAYLIST_CHAIN = "imunify360_log_gl"
    LOG_BLOCK_PORT_CHAIN = "imunify360_log_port_block"
    WEBSHIELD_PORTS_INPUT_CHAIN = "imunify360_webshield_ports"

    DEFAULT_LOGLEVEL = "info"

    @classmethod
    def compose_rule(cls, *filters, action) -> RuleDef:
        return sum(filters, tuple()) + action

    @classmethod
    def compose_action(cls, action, **kwargs) -> RuleDef:
        args = ["-j", action]
        for k in sorted(kwargs.keys()):
            args.append("--" + k.replace("_", "-"))
            args.append(kwargs[k])
        return tuple(args)

    @classmethod
    def interface(cls, interface):
        assert interface, 'Network interface "%s" is not valid!' % interface
        return ("-i", interface)

    @classmethod
    def block_dst_port_list(cls, ports, policy=DROP) -> tuple:
        return (
            "-p",
            "tcp",
            "-m",
            "multiport",
            "--dport",
            ",".join(map(str, sorted(ports))),
            "-j",
            policy,
        )

    @classmethod
    def protected_by_webshield(cls, dst_port, target_port) -> tuple:
        return (
            "-p",
            "tcp",
            "-m",
            "multiport",
            "--dport",
            str(dst_port),
            "-j",
            "DNAT",
            "--to-destination",
            ":" + str(target_port),
        )

    @classmethod
    def open_all_for_src_net(cls, net: str) -> RuleDef:
        """Return a rule to open traffic with source IP address"""
        return ("-s", net, "-j", cls.ACCEPT)

    @classmethod
    def open_dst_ports_for_src_list(
        cls, listname: str, ports: AbstractSet[int], policy=ACCEPT
    ) -> RuleDef:
        """Return a rule to open traffic with TCP destination `ports` and
        source addresses in ipset `listname`."""
        return (
            "-m",
            "set",
            "--match-set",
            listname,
            "src",
            "-m",
            "multiport",
            "-p",
            "tcp",
            "--dport",
            ",".join([str(p) for p in sorted(ports)]),
            "-j",
            policy,
        )

    @staticmethod
    def redirect_to_captcha(
        listname: str, dest_port: int, target: int
    ) -> RuleDef:
        """Returns iptables command parameters to redirect traffic destined
        to tcp port `dest_port` to local port `target`"""
        return (
            "-m",
            "set",
            "--match-set",
            listname,
            "src",
            "-p",
            "tcp",
            "--dport",
            str(dest_port),
            "-j",
            "DNAT",
            "--to-destination",
            ":" + str(target),
        )

    @staticmethod
    def stop_redirection(listname: str) -> RuleDef:
        """Returns iptables command parameters to do not redirect traffic
        destined to webshield port"""
        return (
            "-m",
            "set",
            "--match-set",
            listname,
            "dst",
            "-p",
            "tcp",
            "-j",
            "RETURN",
        )

    @staticmethod
    def redirect_to_captcha_via_tproxy(
        listname: str, dest_port: int, target: int
    ) -> RuleDef:
        """Returns iptables command parameters to redirect traffic destined
        to tcp port `dest_port` to local port `target`, using TPROXY"""
        return (
            "-m",
            "set",
            "--match-set",
            listname,
            "src",
            "-p",
            "tcp",
            "--dport",
            str(dest_port),
            "-j",
            "TPROXY",
            "--tproxy-mark",
            "0x1/0x1",  # mark traffic for TPROXY
            "--on-port",
            str(target),
        )

    @staticmethod
    def traffic_not_from_tproxy(set_name: str, policy: str = DROP) -> RuleDef:
        return (
            "-m",
            "set",
            "--match-set",
            set_name,
            "src",
            "-m",
            "mark",
            "!",
            "--mark",
            "0x1/0x1",  # mark traffic for TPROXY
            "-j",
            policy,
        )

    @staticmethod
    def ipset(set_name):
        return ("-m", "set", "--match-set", set_name, "src")

    @staticmethod
    def ipset_rule(set_name, policy) -> RuleDef:
        """
        RuleDef for ipset

        :param policy: ACCEPT, RETURN or DROP
        :param set_name: ipset collection
        :return:
        """
        return FirewallRules.ipset(set_name) + FirewallRules.compose_action(
            policy
        )

    @staticmethod
    def port_rule(set_name, port, proto, policy=REJECT) -> RuleDef:
        return (
            "-m",
            "set",
            "!",
            "--match-set",
            set_name,
            "src",
            "-p",
            proto,
            "--dport",
            str(port),
            "-j",
            policy,
        )

    @classmethod
    def smtp_test_rule(cls) -> RuleDef:
        return (
            "-p",
            "tcp",
            "--dport",
            "9999",
            "-m",
            "owner",
            "--uid-owner",
            "0",
            "-j",
            cls.ACCEPT,
        )

    @staticmethod
    def nflog_group(ip_version: IPVersion):
        return str(UnifiedAccessLogger.NFLOG_GROUPS[ip_version])

    @staticmethod
    def nflog_action(group, prefix):
        return FirewallRules.compose_action(
            "NFLOG", nflog_group=group, nflog_prefix=prefix
        )

Zerion Mini Shell 1.0