#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

# Example output from agent:
# <<<iptables>>>
# -A INPUT -j RH-Firewall-1-INPUT
# -A FORWARD -j RH-Firewall-1-INPUT
# -A OUTPUT -d 10.139.7.11/32 -j REJECT --reject-with icmp-port-unreachable
# -A RH-Firewall-1-INPUT -i lo -j ACCEPT
# -A RH-Firewall-1-INPUT -p icmp -m icmp --icmp-type any -j ACCEPT
# -A RH-Firewall-1-INPUT -p esp -j ACCEPT
# -A RH-Firewall-1-INPUT -p ah -j ACCEPT
# -A RH-Firewall-1-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 4000 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 29543 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 29043 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 30001 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 30000 -j ACCEPT
# -A RH-Firewall-1-INPUT -d 224.0.0.251/32 -p udp -m udp --dport 5353 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 58002 -j ACCEPT
# -A RH-Firewall-1-INPUT -p udp -m udp --dport 58001 -j ACCEPT
# -A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 631 -j ACCEPT
# -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 6556 -j ACCEPT
# -A RH-Firewall-1-INPUT -p udp -m udp --dport 6556 -j ACCEPT
# -A RH-Firewall-1-INPUT -s 89.254.0.0/16 -p tcp -m state --state NEW -m tcp --dport 252 -j ACCEPT
# -A RH-Firewall-1-INPUT -s 89.254.0.0/16 -p tcp -m state --state NEW -m tcp --dport 7070 -j ACCEPT
# -A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited
# COMMIT

import difflib
import hashlib


def iptables_hash(config):
    return hashlib.sha256(config.encode("utf-8")).hexdigest()


def parse_iptables(info):
    config_lines = [" ".join(sublist) for sublist in info]
    config = "\n".join(config_lines)
    return config


def inventory_iptables(parsed):
    return [(None, {"config_hash": iptables_hash(parsed)})]


def check_iptables(_no_item, params, parsed):
    item_state = get_item_state("iptables.config")

    if not item_state:
        set_item_state("iptables.config", {"config": parsed, "hash": iptables_hash(parsed)})
        raise MKCounterWrapped(
            "Initial configuration has been saved. The next check interval will contain a valid state."
        )

    initial_config_hash = params["config_hash"]
    new_config_hash = iptables_hash(parsed)

    if initial_config_hash == new_config_hash:
        if initial_config_hash != item_state.get("hash"):
            set_item_state("iptables.config", {"config": parsed, "hash": new_config_hash})
            return 0, "accepted new filters after service rediscovery / reboot"
        return 0, "no changes in filters table detected"

    reference_config = item_state["config"].splitlines()
    actual_config = parsed.splitlines()
    diff = difflib.context_diff(
        reference_config, actual_config, fromfile="before", tofile="after", lineterm=""
    )
    diff_output = "\n".join(diff)

    return 2, "\r\n".join(["changes in filters table detected", diff_output])


check_info["iptables"] = {
    "parse_function": parse_iptables,
    "check_function": check_iptables,
    "inventory_function": inventory_iptables,
    "service_description": "Iptables",
}
