#!/bin/bash

# Màu cho output
GREEN='\e[32m'
YELLOW='\e[33m'
BLUE='\e[34m'
RED='\e[31m'
NC='\e[0m' # No Color

step() {
    echo -e "${BLUE}[>]${NC} ${YELLOW}$1${NC}"
    sleep 0.3
}

success() {
    echo -e "${GREEN}[✓] $1${NC}"
}

error() {
    echo -e "${RED}[✗] $1${NC}"
}

title() {
    echo -e "\n${BLUE}========== $1 ==========${NC}\n"
}

detect_firewall() {
    if command -v ufw &>/dev/null && systemctl is-active ufw &>/dev/null; then
        FIREWALL="ufw"
    elif command -v firewall-cmd &>/dev/null && systemctl is-active firewalld &>/dev/null; then
        FIREWALL="firewalld"
    elif command -v iptables &>/dev/null; then
        FIREWALL="iptables"
    else
        error "No supported firewall tool found (iptables, ufw, firewalld)."
        exit 1
    fi
    success "Detected firewall: $FIREWALL"
}

get_user_ports() {
    echo -e "${YELLOW}Enter TCP ports to open (e.g., 22 80 443):${NC}"
    read -rp "> " TCP_PORTS
    echo -e "${YELLOW}Enter UDP ports to open (e.g., 53 123):${NC}"
    read -rp "> " UDP_PORTS
}

setup_iptables_rules() {
    title "Applying iptables security rules"

    iptables -F
    iptables -X

    step "Set default policies"
    iptables -P INPUT DROP
    iptables -P FORWARD DROP
    iptables -P OUTPUT ACCEPT

    step "Allow loopback interface"
    iptables -A INPUT -i lo -j ACCEPT

    step "Accept established and related connections"
    iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

    step "Block spoofed IP ranges with logging"
    for ip in 224.0.0.0/3 169.254.0.0/16 172.16.0.0/12 0.0.0.0/8; do
        iptables -A INPUT -s "$ip" -j LOG --log-prefix "DROP_SPOOFED_IP " --log-level 4
        iptables -A INPUT -s "$ip" -j DROP
        sleep 0.1
    done
    iptables -A INPUT -s 127.0.0.0/8 ! -i lo -j LOG --log-prefix "DROP_SPOOFED_IP_LOCAL " --log-level 4
    iptables -A INPUT -s 127.0.0.0/8 ! -i lo -j DROP

    iptables -A INPUT -d 0.0.0.0/8 -j LOG --log-prefix "DROP_SPOOFED_IP_DEST " --log-level 4
    iptables -A INPUT -d 0.0.0.0/8 -j DROP

    step "Drop ICMP timestamp requests/replies with logging"
    iptables -A INPUT -p icmp --icmp-type timestamp-request -j LOG --log-prefix "DROP_ICMP_TIMESTAMP " --log-level 4
    iptables -A INPUT -p icmp --icmp-type timestamp-request -j DROP
    iptables -A INPUT -p icmp --icmp-type timestamp-reply -j LOG --log-prefix "DROP_ICMP_TIMESTAMP " --log-level 4
    iptables -A INPUT -p icmp --icmp-type timestamp-reply -j DROP

    step "Create SYN flood protection chain"
    iptables -N SYN_FLOOD
    iptables -A SYN_FLOOD -m limit --limit 1/s --limit-burst 4 -j RETURN
    iptables -A SYN_FLOOD -j LOG --log-prefix "DROP_SYN_FLOOD " --log-level 4
    iptables -A SYN_FLOOD -j DROP
    iptables -A INPUT -p tcp --syn -j SYN_FLOOD

    step "Drop invalid packets with logging"
    iptables -A INPUT -m state --state INVALID -j LOG --log-prefix "DROP_INVALID_PKT " --log-level 4
    iptables -A INPUT -m state --state INVALID -j DROP

    step "Limit ICMP requests"
    iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT
    iptables -A INPUT -p icmp -j LOG --log-prefix "DROP_ICMP_FLOOD " --log-level 4
    iptables -A INPUT -p icmp -j DROP

    step "Limit UDP traffic to prevent flood"
    iptables -A INPUT -p udp -m limit --limit 50/s --limit-burst 100 -j ACCEPT
    iptables -A INPUT -p udp -j LOG --log-prefix "DROP_UDP_FLOOD " --log-level 4
    iptables -A INPUT -p udp -j DROP

    step "Limit TCP SYN traffic to prevent SYN flood"
    iptables -A INPUT -p tcp --syn -m limit --limit 50/s --limit-burst 100 -j ACCEPT
    iptables -A INPUT -p tcp --syn -j LOG --log-prefix "DROP_TCP_SYN_FLOOD " --log-level 4
    iptables -A INPUT -p tcp --syn -j DROP

    if [ -n "$TCP_PORTS" ]; then
        for port in $TCP_PORTS; do
            step "Allow TCP port $port"
            iptables -A INPUT -p tcp --dport "$port" -j ACCEPT
        done
    fi

    if [ -n "$UDP_PORTS" ]; then
        for port in $UDP_PORTS; do
            step "Allow UDP port $port"
            iptables -A INPUT -p udp --dport "$port" -j ACCEPT
        done
    fi

    step "Log other dropped packets (final catch-all)"
    iptables -A INPUT -j LOG --log-prefix "DROP_INPUT_FINAL " --log-level 4

    success "iptables rules applied"
}

setup_json_logging() {
    title "Configuring JSON logging for dropped packets"

    cat > /etc/rsyslog.d/30-iptables-json.conf <<'EOF'
template(name="json-template" type="list") {
  constant(value="{")
  constant(value="\"@timestamp\":\"")     property(name="timereported" dateFormat="rfc3339")
  constant(value="\",\"message\":\"")     property(name="msg" format="json")
  constant(value="\",\"host\":\"")        property(name="hostname")
  constant(value="\"}\n")
}

if ($msg contains "IPTABLES_DROP") then {
  action(type="omfile" file="/var/log/iptables_drop.json" template="json-template")
  stop
}
EOF

    systemctl restart rsyslog
    success "Log configured at /var/log/iptables_drop.json"
}

setup_ufw_rules() {
    title "Configuring UFW firewall"
    ufw --force reset
    ufw default deny incoming
    ufw default allow outgoing

    for port in $TCP_PORTS; do
        step "Allow TCP port $port"
        ufw allow "$port"/tcp
    done
    for port in $UDP_PORTS; do
        step "Allow UDP port $port"
        ufw allow "$port"/udp
    done

    ufw enable
    success "UFW rules applied"
}

setup_firewalld_rules() {
    title "Configuring firewalld"

    systemctl unmask firewalld
    systemctl enable firewalld --now

    firewall-cmd --permanent --set-default-zone=public
    firewall-cmd --permanent --remove-service=dhcpv6-client

    for port in $TCP_PORTS; do
        step "Allow TCP port $port"
        firewall-cmd --permanent --add-port="$port"/tcp
    done
    for port in $UDP_PORTS; do
        step "Allow UDP port $port"
        firewall-cmd --permanent --add-port="$port"/udp
    done

    firewall-cmd --reload
    success "Firewalld rules applied"
}

clear
echo -e "${GREEN}Linux Secure Firewall Script${NC} - by thuan.livestream@gmail.com"
echo "-----------------------------------------"

detect_firewall
get_user_ports

case $FIREWALL in
    iptables)
        setup_iptables_rules
        setup_json_logging
        ;;
    ufw)
        setup_ufw_rules
        ;;
    firewalld)
        setup_firewalld_rules
        ;;
esac

echo -e "\n${GREEN}[✓] Firewall hardening complete.${NC}"

