#!/bin/bash

set -e

# ============================================================
# CONFIGURAÇÃO DE REDE / GATEWAY - DEBIAN 13
#
# Funções:
# - Detecta interfaces de rede
# - Recria /etc/network/interfaces
# - DHCP / IP estático / Não configurar
# - Configura /etc/resolv.conf
# - Configura gateway IPv4
# - Ativa ip_forward permanentemente
# - Configura nftables
# - Configura masquerade permanente
#
# Compatível com:
# curl -fsSL URL | bash
# ============================================================


# ============================================================
# FUNÇÕES
# ============================================================

read_tty() {
    local prompt="$1"
    local varname="$2"

    read -rp "$prompt" "$varname" < /dev/tty
}


valid_ipv4() {
    local ip="$1"
    local IFS=.
    local -a octets

    read -ra octets <<< "$ip"

    [ "${#octets[@]}" -eq 4 ] || return 1

    for octet in "${octets[@]}"; do
        [[ "$octet" =~ ^[0-9]+$ ]] || return 1
        [ "$octet" -ge 0 ] 2>/dev/null || return 1
        [ "$octet" -le 255 ] 2>/dev/null || return 1
    done

    return 0
}


yes_answer() {
    case "$1" in
        s|S|sim|SIM|Sim|y|Y|yes|YES|Yes)
            return 0
            ;;
        *)
            return 1
            ;;
    esac
}


# ============================================================
# ROOT
# ============================================================

if [ "$EUID" -ne 0 ]; then
    echo
    echo "ERRO: execute este script como root."
    echo
    exit 1
fi


# ============================================================
# CABEÇALHO
# ============================================================

clear 2>/dev/null || true

echo
echo "============================================================"
echo " CONFIGURAÇÃO DE REDE / GATEWAY - DEBIAN 13"
echo "============================================================"
echo


# ============================================================
# DETECTA INTERFACES
# ============================================================

mapfile -t INTERFACES < <(
    find /sys/class/net \
        -mindepth 1 \
        -maxdepth 1 \
        -printf '%f\n' |
        grep -v '^lo$' |
        grep -Ev '^(docker|br-|veth|virbr|tun|tap)' |
        sort
)


if [ "${#INTERFACES[@]}" -eq 0 ]; then
    echo "ERRO: nenhuma interface de rede encontrada."
    exit 1
fi


echo "Interfaces encontradas:"
echo

for IFACE in "${INTERFACES[@]}"; do

    MAC="desconhecido"
    STATE="desconhecido"

    if [ -f "/sys/class/net/$IFACE/address" ]; then
        MAC=$(cat "/sys/class/net/$IFACE/address")
    fi

    if [ -f "/sys/class/net/$IFACE/operstate" ]; then
        STATE=$(cat "/sys/class/net/$IFACE/operstate")
    fi

    echo "Interface : $IFACE"
    echo "MAC       : $MAC"
    echo "Estado    : $STATE"
    echo

done


# ============================================================
# CONFIRMAÇÃO
# ============================================================

echo "ATENÇÃO:"
echo
echo "Os seguintes arquivos poderão ser alterados:"
echo
echo "  /etc/network/interfaces"
echo "  /etc/resolv.conf"
echo "  /etc/sysctl.d/99-ip-forward.conf"
echo "  /etc/nftables.conf"
echo

read_tty "Deseja continuar? [S/n]: " CONFIRM


case "$CONFIRM" in
    n|N|nao|não|NAO|NÃO)
        echo
        echo "Operação cancelada."
        exit 0
        ;;
esac


# ============================================================
# BACKUP
# ============================================================

BACKUP_DIR="/root/network-backup-$(date +%Y%m%d-%H%M%S)"

mkdir -p "$BACKUP_DIR"


for FILE in \
    /etc/network/interfaces \
    /etc/resolv.conf \
    /etc/nftables.conf \
    /etc/sysctl.d/99-ip-forward.conf

do

    if [ -e "$FILE" ]; then

        cp -a "$FILE" "$BACKUP_DIR/$(basename "$FILE")"

    fi

done


echo
echo "Backup criado em:"
echo
echo "  $BACKUP_DIR"
echo


# ============================================================
# VARIÁVEIS
# ============================================================

CONFIGURED_INTERFACES=()

DNS_SERVERS=()
DNS_SEARCH=""

STATIC_INTERFACE_FOUND=0


# ============================================================
# RECRIA /etc/network/interfaces
# ============================================================

cat > /etc/network/interfaces <<'EOF'
# ============================================================
# Configuração de rede
# Gerada automaticamente
# ============================================================

auto lo
iface lo inet loopback

EOF


# ============================================================
# CONFIGURA INTERFACES
# ============================================================

for IFACE in "${INTERFACES[@]}"; do

    MAC="desconhecido"

    if [ -f "/sys/class/net/$IFACE/address" ]; then
        MAC=$(cat "/sys/class/net/$IFACE/address")
    fi


    echo
    echo "============================================================"
    echo " INTERFACE: $IFACE"
    echo " MAC:       $MAC"
    echo "============================================================"
    echo
    echo "1) DHCP"
    echo "2) IP estático"
    echo "3) Não configurar"
    echo


    while true; do

        read_tty "Escolha [1/2/3]: " OPTION


        case "$OPTION" in

            # ====================================================
            # DHCP
            # ====================================================

            1)

                cat >> /etc/network/interfaces <<EOF

# ------------------------------------------------------------
# Interface $IFACE - DHCP
# ------------------------------------------------------------

auto $IFACE
allow-hotplug $IFACE
iface $IFACE inet dhcp

EOF

                CONFIGURED_INTERFACES+=("$IFACE")

                echo
                echo "$IFACE configurada como DHCP."

                break
                ;;


            # ====================================================
            # ESTÁTICO
            # ====================================================

            2)

                STATIC_INTERFACE_FOUND=1

                echo
                echo "Configuração estática de $IFACE"
                echo


                # ------------------------------------------------
                # IP
                # ------------------------------------------------

                while true; do

                    read_tty "Endereço IPv4: " IPADDR

                    if valid_ipv4 "$IPADDR"; then
                        break
                    fi

                    echo "Endereço IPv4 inválido."

                done


                # ------------------------------------------------
                # PREFIXO
                # ------------------------------------------------

                while true; do

                    read_tty "Prefixo da rede [ex.: 24]: " PREFIX

                    if [[ "$PREFIX" =~ ^[0-9]+$ ]] &&
                       [ "$PREFIX" -ge 0 ] &&
                       [ "$PREFIX" -le 32 ]; then

                        break

                    fi

                    echo "Prefixo inválido. Informe um valor entre 0 e 32."

                done


                # ------------------------------------------------
                # GATEWAY
                # ------------------------------------------------

                while true; do

                    read_tty "Gateway [ENTER para nenhum]: " GATEWAY

                    if [ -z "$GATEWAY" ]; then
                        break
                    fi

                    if valid_ipv4 "$GATEWAY"; then
                        break
                    fi

                    echo "Gateway inválido."

                done


                # ------------------------------------------------
                # DNS
                # ------------------------------------------------

                while true; do

                    read_tty "DNS [ex.: 8.8.8.8 1.1.1.1] [ENTER para nenhum]: " DNS

                    if [ -z "$DNS" ]; then
                        break
                    fi

                    DNS_VALID=1

                    for DNS_IP in $DNS; do

                        if ! valid_ipv4 "$DNS_IP"; then
                            DNS_VALID=0
                            break
                        fi

                    done


                    if [ "$DNS_VALID" -eq 1 ]; then
                        break
                    fi

                    echo "Um ou mais servidores DNS são inválidos."

                done


                # ------------------------------------------------
                # DNS SEARCH
                # ------------------------------------------------

                read_tty "Domínio de pesquisa DNS [ENTER para nenhum]: " CURRENT_DNS_SEARCH


                # ------------------------------------------------
                # GRAVA INTERFACE
                # ------------------------------------------------

                cat >> /etc/network/interfaces <<EOF

# ------------------------------------------------------------
# Interface $IFACE - ESTÁTICA
# ------------------------------------------------------------

auto $IFACE
allow-hotplug $IFACE
iface $IFACE inet static
    address $IPADDR/$PREFIX
EOF


                if [ -n "$GATEWAY" ]; then
                    echo "    gateway $GATEWAY" >> /etc/network/interfaces
                fi


                if [ -n "$DNS" ]; then
                    echo "    dns-nameservers $DNS" >> /etc/network/interfaces

                    for DNS_IP in $DNS; do
                        DNS_SERVERS+=("$DNS_IP")
                    done
                fi


                if [ -n "$CURRENT_DNS_SEARCH" ]; then

                    echo "    dns-search $CURRENT_DNS_SEARCH" \
                        >> /etc/network/interfaces

                    DNS_SEARCH="$CURRENT_DNS_SEARCH"

                fi


                CONFIGURED_INTERFACES+=("$IFACE")


                echo
                echo "$IFACE configurada com IP estático."

                break
                ;;


            # ====================================================
            # NÃO CONFIGURAR
            # ====================================================

            3)

                echo
                echo "$IFACE não será configurada."

                break
                ;;


            *)

                echo
                echo "Opção inválida. Escolha 1, 2 ou 3."
                ;;

        esac

    done

done


chmod 644 /etc/network/interfaces


# ============================================================
# CONFIGURA /etc/resolv.conf
# ============================================================

if [ "${#DNS_SERVERS[@]}" -gt 0 ]; then

    echo
    echo "Configurando /etc/resolv.conf..."


    cat > /etc/resolv.conf <<'EOF'
# ============================================================
# Configuração DNS
# Gerada automaticamente
# ============================================================

EOF


    if [ -n "$DNS_SEARCH" ]; then

        echo "search $DNS_SEARCH" >> /etc/resolv.conf

    fi


    # Remove duplicatas
    mapfile -t UNIQUE_DNS < <(
        printf "%s\n" "${DNS_SERVERS[@]}" |
        awk '!seen[$0]++'
    )


    for DNS_IP in "${UNIQUE_DNS[@]}"; do

        echo "nameserver $DNS_IP" >> /etc/resolv.conf

    done


    chmod 644 /etc/resolv.conf

fi


# ============================================================
# GATEWAY
# ============================================================

echo
echo "============================================================"
echo " CONFIGURAÇÃO DE GATEWAY"
echo "============================================================"
echo

read_tty "Esta máquina será gateway para outras máquinas/redes? [s/N]: " IS_GATEWAY


if yes_answer "$IS_GATEWAY"; then


    # ========================================================
    # NFTABLES
    # ========================================================

    if ! command -v nft >/dev/null 2>&1; then

        echo
        echo "ERRO: nftables não está instalado."
        echo
        echo "Instale com:"
        echo
        echo "  apt update"
        echo "  apt install nftables"
        echo

        exit 1

    fi


    if [ "${#CONFIGURED_INTERFACES[@]}" -lt 2 ]; then

        echo
        echo "ATENÇÃO:"
        echo
        echo "Foram configuradas menos de duas interfaces."
        echo "Um gateway normalmente utiliza pelo menos uma WAN e uma LAN."
        echo

    fi


    # ========================================================
    # SELECIONA WAN
    # ========================================================

    echo
    echo "Selecione a interface que possui saída para a Internet:"
    echo


    INDEX=1

    for IFACE in "${CONFIGURED_INTERFACES[@]}"; do

        echo "$INDEX) $IFACE"

        INDEX=$((INDEX + 1))

    done


    echo


    while true; do

        read_tty "Interface de saída: " WAN_OPTION


        if [[ "$WAN_OPTION" =~ ^[0-9]+$ ]] &&
           [ "$WAN_OPTION" -ge 1 ] &&
           [ "$WAN_OPTION" -le "${#CONFIGURED_INTERFACES[@]}" ]; then

            WAN_INTERFACE="${CONFIGURED_INTERFACES[$((WAN_OPTION - 1))]}"

            break

        fi


        echo "Opção inválida."

    done


    echo
    echo "Interface WAN selecionada:"
    echo
    echo "  $WAN_INTERFACE"
    echo


    # ========================================================
    # INTERFACES LAN
    # ========================================================

    LAN_INTERFACES=()

    for IFACE in "${CONFIGURED_INTERFACES[@]}"; do

        if [ "$IFACE" != "$WAN_INTERFACE" ]; then

            LAN_INTERFACES+=("$IFACE")

        fi

    done


    # ========================================================
    # IP FORWARD
    # ========================================================

    echo "Ativando IPv4 forwarding..."


    cat > /etc/sysctl.d/99-ip-forward.conf <<'EOF'
# ============================================================
# IPv4 Forwarding
# ============================================================

net.ipv4.ip_forward = 1
EOF


    sysctl -w net.ipv4.ip_forward=1 >/dev/null


    # ========================================================
    # NFTABLES
    # ========================================================

    echo "Criando configuração do nftables..."


    cat > /etc/nftables.conf <<EOF
#!/usr/sbin/nft -f

# ============================================================
# NFTABLES - GATEWAY IPV4
# Gerado automaticamente
# ============================================================

flush ruleset


# ============================================================
# FILTER
# ============================================================

table inet filter {

    chain input {

        type filter hook input priority filter;
        policy accept;

    }


    chain forward {

        type filter hook forward priority filter;
        policy drop;

        # Tráfego já estabelecido
        ct state established,related accept

EOF


    # ========================================================
    # REGRAS LAN -> WAN
    # ========================================================

    for LAN_INTERFACE in "${LAN_INTERFACES[@]}"; do

        echo "        iifname \"$LAN_INTERFACE\" oifname \"$WAN_INTERFACE\" accept" \
            >> /etc/nftables.conf

    done


    cat >> /etc/nftables.conf <<EOF

    }

}


# ============================================================
# NAT
# ============================================================

table ip nat {

    chain postrouting {

        type nat hook postrouting priority srcnat;
        policy accept;

        oifname "$WAN_INTERFACE" masquerade

    }

}
EOF


    # ========================================================
    # VALIDA NFTABLES
    # ========================================================

    echo
    echo "Validando regras do nftables..."


    if ! nft -c -f /etc/nftables.conf; then

        echo
        echo "ERRO: configuração inválida do nftables."
        echo
        echo "Backup disponível em:"
        echo
        echo "  $BACKUP_DIR"
        echo

        exit 1

    fi


    # ========================================================
    # ATIVA
    # ========================================================

    echo
    echo "Ativando nftables..."


    systemctl enable nftables >/dev/null 2>&1 || true


    nft -f /etc/nftables.conf


    systemctl restart nftables


fi


# ============================================================
# RESULTADO FINAL
# ============================================================

echo
echo "============================================================"
echo " CONFIGURAÇÃO FINAL"
echo "============================================================"
echo


echo "Arquivo de interfaces:"
echo
echo "------------------------------------------------------------"
cat /etc/network/interfaces
echo "------------------------------------------------------------"


echo
echo "DNS:"
echo
echo "------------------------------------------------------------"
cat /etc/resolv.conf
echo "------------------------------------------------------------"


if yes_answer "$IS_GATEWAY"; then

    echo
    echo "Gateway:"
    echo
    echo "WAN           : $WAN_INTERFACE"

    if [ "${#LAN_INTERFACES[@]}" -gt 0 ]; then

        echo "LAN           : ${LAN_INTERFACES[*]}"

    fi

    echo "IPv4 Forward  : $(sysctl -n net.ipv4.ip_forward)"
    echo "Masquerade    : ativado"
    echo

    echo "------------------------------------------------------------"
    echo "NFTABLES"
    echo "------------------------------------------------------------"

    nft list ruleset

    echo "------------------------------------------------------------"

fi


# ============================================================
# SINCRONIZA
# ============================================================

sync


# ============================================================
# FINALIZA
# ============================================================

echo
echo "============================================================"
echo " CONFIGURAÇÃO CONCLUÍDA"
echo "============================================================"
echo
echo "Backup:"
echo
echo "  $BACKUP_DIR"
echo
echo "A configuração foi gravada."
echo
echo "Recomenda-se reiniciar a máquina:"
echo
echo "  reboot"
echo