💡 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:
- Lê todos os arquivos
.ccd
de configuração de clientes OpenVPN. - Identifica:
- O IP da rede de origem (
iroute
) - Os destinos permitidos (
push "route"
)
- O IP da rede de origem (
- Gera uma regra
iptables
para cada par origem/destino, liberando portas TCP definidas em uma variável. - 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 combc
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
- Salve o script com o nome
gerar_regras.sh
. - 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.
Comments are closed