[OpenVPN] Regras Iptables dos arquivos ccd com Shell Script

💡 Introdução

Quando se utiliza o OpenVPN com diretivas ccd (Client Config Directory), é comum definir redes estáticas para cada cliente, com opções como iroute, ifconfig-push e push "route ...". Isso facilita a gestão de roteamento, mas torna complexa a configuração dinâmica de regras de firewall — especialmente quando precisamos controlar o acesso desses clientes a destinos específicos, como aplicações web.

Neste artigo, você aprenderá como automatizar a geração de regras de iptables, com base nos arquivos presentes no diretório /etc/openvpn/ccd/, utilizando um shell script simples e eficiente.


📜 Objetivo do Script

Este script Bash realiza as seguintes funções:

  1. Lê todos os arquivos .ccd de configuração de clientes OpenVPN.
  2. Identifica:
    • O IP da rede de origem (iroute)
    • Os destinos permitidos (push "route")
  3. Gera uma regra iptables para cada par origem/destino, liberando portas TCP definidas em uma variável.
  4. Exporta as regras formatadas para um arquivo iptables-export.txt.

✅ Requisitos do Script

Para que o script funcione corretamente, é necessário instalar os seguintes pacotes:

  • ipcalc: usado para converter máscara de rede para notação CIDR (ex: 255.255.255.0/24);
  • bc: utilizado para cálculos binários (caso o script use a versão com bc para conversão de máscara).

Você pode instalar ambos com:

apt install ipcalc bc -y

🔧 O Script

#!/bin/bash

# Diretório com arquivos CCD
CCD_DIR="/etc/openvpn/ccd"

# Chain do iptables
IPTABLES_CHAIN="f2b-openvpn"

# Portas a liberar (modifique conforme necessário)
PORTS=("80" "443" "3000")

# Arquivo de saída
OUTPUT_FILE="iptables-export.txt"

# Função para converter máscara para CIDR (ex: 255.255.255.0 -> 24)
mask_to_cidr() {
    local mask=$1
    local IFS=.
    local -a octets=($mask)
    local bin maskbits=0

    for octet in "${octets[@]}"; do
        # converte para binário e conta bits 1
        bin=$(printf "%08d" "$(bc <<< "obase=2; $octet")")
        maskbits=$((maskbits + $(grep -o "1" <<< "$bin" | wc -l)))
    done

    echo "$maskbits"
}

# Limpa o arquivo de saída
> "$OUTPUT_FILE"

# Loop pelos arquivos CCD
for ccd_file in "$CCD_DIR"/*; do
    origem=""
    destinos=()

    while read -r line; do
        if [[ "$line" =~ ^iroute[[:space:]]+([0-9.]+)[[:space:]]+([0-9.]+) ]]; then
            ip="${BASH_REMATCH[1]}"
            mask="${BASH_REMATCH[2]}"
            cidr=$(mask_to_cidr "$mask")
            origem="$ip/$cidr"
        elif [[ "$line" =~ ^push[[:space:]]+\"route[[:space:]]+([0-9.]+)[[:space:]]+([0-9.]+)\" ]]; then
            dst_ip="${BASH_REMATCH[1]}"
            dst_mask="${BASH_REMATCH[2]}"
            dst_cidr=$(mask_to_cidr "$dst_mask")
            destinos+=("$dst_ip/$dst_cidr")
        fi
    done < "$ccd_file"

    # Gera as regras
    if [[ -n "$origem" && "${#destinos[@]}" -gt 0 ]]; then
        for dst in "${destinos[@]}"; do
            for port in "${PORTS[@]}"; do
                echo "iptables -A $IPTABLES_CHAIN -s $origem -d $dst -p tcp --dport $port -j ACCEPT" >> "$OUTPUT_FILE"
            done
        done
    fi
done

echo "Arquivo de regras gerado com sucesso: $OUTPUT_FILE"

🔧 O Script sem dependências necessárias (Experimental):

#!/bin/bash

# Diretório com arquivos CCD
CCD_DIR="/etc/openvpn/ccd"

# Chain do iptables
IPTABLES_CHAIN="f2b-openvpn"

# Portas a liberar (modifique conforme necessário)
PORTS=("80" "443" "3000")

# Arquivo de saída
OUTPUT_FILE="iptables-export.txt"

# Função para converter máscara para CIDR (ex: 255.255.255.0 -> 24)
mask_to_cidr() {
    case "$1" in
        128.0.0.0) echo 1 ;;
        192.0.0.0) echo 2 ;;
        224.0.0.0) echo 3 ;;
        240.0.0.0) echo 4 ;;
        248.0.0.0) echo 5 ;;
        252.0.0.0) echo 6 ;;
        254.0.0.0) echo 7 ;;
        255.0.0.0) echo 8 ;;
        255.128.0.0) echo 9 ;;
        255.192.0.0) echo 10 ;;
        255.224.0.0) echo 11 ;;
        255.240.0.0) echo 12 ;;
        255.248.0.0) echo 13 ;;
        255.252.0.0) echo 14 ;;
        255.254.0.0) echo 15 ;;
        255.255.0.0) echo 16 ;;
        255.255.128.0) echo 17 ;;
        255.255.192.0) echo 18 ;;
        255.255.224.0) echo 19 ;;
        255.255.240.0) echo 20 ;;
        255.255.248.0) echo 21 ;;
        255.255.252.0) echo 22 ;;
        255.255.254.0) echo 23 ;;
        255.255.255.0) echo 24 ;;
        255.255.255.128) echo 25 ;;
        255.255.255.192) echo 26 ;;
        255.255.255.224) echo 27 ;;
        255.255.255.240) echo 28 ;;
        255.255.255.248) echo 29 ;;
        255.255.255.252) echo 30 ;;
        255.255.255.254) echo 31 ;;
        255.255.255.255) echo 32 ;;
        *) echo "0" ;; # fallback
    esac
}

# Limpa o arquivo de saída
> "$OUTPUT_FILE"

# Loop pelos arquivos CCD
for ccd_file in "$CCD_DIR"/*; do
    origem=""
    destinos=()

    while read -r line; do
        if [[ "$line" =~ ^iroute[[:space:]]+([0-9.]+)[[:space:]]+([0-9.]+) ]]; then
            ip="${BASH_REMATCH[1]}"
            mask="${BASH_REMATCH[2]}"
            cidr=$(mask_to_cidr "$mask")
            origem="$ip/$cidr"
        elif [[ "$line" =~ ^push[[:space:]]+\"route[[:space:]]+([0-9.]+)[[:space:]]+([0-9.]+)\" ]]; then
            dst_ip="${BASH_REMATCH[1]}"
            dst_mask="${BASH_REMATCH[2]}"
            dst_cidr=$(mask_to_cidr "$dst_mask")
            destinos+=("$dst_ip/$dst_cidr")
        fi
    done < "$ccd_file"

    # Gera as regras
    if [[ -n "$origem" && "${#destinos[@]}" -gt 0 ]]; then
        for dst in "${destinos[@]}"; do
            for port in "${PORTS[@]}"; do
                echo "iptables -A $IPTABLES_CHAIN -s $origem -d $dst -p tcp --dport $port -j ACCEPT" >> "$OUTPUT_FILE"
            done
        done
    fi
done

echo "Arquivo de regras gerado com sucesso: $OUTPUT_FILE"

📁 Exemplo de Entrada CCD

Arquivo /etc/openvpn/ccd/cliente1:

ifconfig-push 10.8.0.11 255.255.255.0
iroute 192.168.68.0 255.255.255.0
push "route 10.0.10.10 255.255.255.255"

Saída no iptables-export.txt:

iptables -A f2b-openvpn -s 192.168.68.0/24 -d 10.0.10.10/32 -p tcp –dport 80 -j ACCEPT

⚙️ Como usar

  1. Salve o script com o nome gerar_regras.sh.
  2. Dê permissão de execução:
chmod +x gerar_regras.sh
  • 3. Execute:
./gerar_regras.sh
  • 4. O resultado estará no arquivo iptables-export.txt.

🚀 Dicas adicionais

  • Altere o array PORTS para liberar múltiplas portas:
PORTS=("80" "443" "8080")

Para aplicar as regras diretamente, use eval ou redirecione a saída para um script .sh e execute com bash.

🧩 Conclusão

Esse script é uma maneira prática de manter seu ambiente OpenVPN seguro e dinâmico, garantindo que apenas os acessos esperados sejam permitidos no firewall. Ele evita falhas humanas e automatiza uma etapa crítica da operação de redes privadas.

Se você gerencia múltiplos túneis ou clientes VPN, esta solução pode economizar horas de trabalho e evitar erros manuais na criação de regras de segurança.

CATEGORIES:

Software Livre

Comments are closed