243 lines
7.0 KiB
Bash
243 lines
7.0 KiB
Bash
#!/bin/bash
|
|
# Script Dinâmico de Configuração de Rede para Raspberry Pi
|
|
# Localização: /usr/local/bin/configure_network.sh
|
|
|
|
# --- Configurações ---
|
|
LOG_FILE="/var/log/network_config.log"
|
|
UDEV_RULES_FILE="/etc/udev/rules.d/81-mac-spoof.rules"
|
|
|
|
# --- Funções Auxiliares ---
|
|
|
|
# Função de Log
|
|
log() {
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S'): $1" | tee -a "$LOG_FILE"
|
|
}
|
|
|
|
# Função para perguntar confirmação ao utilizador
|
|
ask_confirmation() {
|
|
local message="$1"
|
|
local default="$2" # "y" or "n"
|
|
|
|
while true; do
|
|
if [ "$default" = "y" ]; then
|
|
read -p "$message [Y/n]: " choice < /dev/tty
|
|
else
|
|
read -p "$message [y/N]: " choice < /dev/tty
|
|
fi
|
|
|
|
# Default choice if user just presses Enter
|
|
if [ -z "$choice" ]; then
|
|
choice="$default"
|
|
fi
|
|
|
|
case "$choice" in
|
|
y|Y|yes|Yes|YES)
|
|
return 0
|
|
;;
|
|
n|N|no|No|NO)
|
|
return 1
|
|
;;
|
|
*)
|
|
echo "Por favor, responda sim ou não."
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Função para gerar MAC único baseado no Serial do CPU
|
|
generate_unique_mac() {
|
|
local serial
|
|
serial=$(awk '/Serial/ {print $3}' /proc/cpuinfo | tr -d ' ')
|
|
|
|
if [ -z "$serial" ]; then
|
|
printf '%02X:%02X:%02X:%02X:%02X:%02X' $((0x02 | (RANDOM % 256) & 0xFE)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256)) $((RANDOM % 256))
|
|
else
|
|
local hash
|
|
hash=$(echo -n "$serial-dm9601" | md5sum | cut -c1-10)
|
|
echo "02:${hash:0:2}:${hash:2:2}:${hash:4:2}:${hash:6:2}:${hash:8:2}"
|
|
fi
|
|
}
|
|
|
|
# Função para definir MAC imediatamente
|
|
set_mac() {
|
|
local interface="$1"
|
|
local mac="$2"
|
|
|
|
if ! ip link show "$interface" &> /dev/null; then
|
|
log "Interface $interface não encontrada em set_mac."
|
|
return 1
|
|
fi
|
|
|
|
log "A definir MAC $mac em $interface..."
|
|
if ip link set "$interface" down && \
|
|
ip link set dev "$interface" address "$mac" && \
|
|
ip link set "$interface" up; then
|
|
log "MAC alterado com sucesso na sessão atual."
|
|
return 0
|
|
else
|
|
log "Falha ao alterar MAC na sessão atual."
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Função para criar regra Udev
|
|
setup_udev_persistence() {
|
|
local interface="$1"
|
|
local target_mac="$2"
|
|
|
|
local original_mac
|
|
original_mac=$(ip link show "$interface" | awk '/ether/ {print $2}' | tr '[:upper:]' '[:lower:]')
|
|
target_mac=$(echo "$target_mac" | tr '[:upper:]' '[:lower:]')
|
|
|
|
if [ -z "$original_mac" ]; then
|
|
log "Erro crítico: Não foi possível obter o MAC original para criar regra udev."
|
|
return 1
|
|
fi
|
|
|
|
# Cria o conteúdo da regra
|
|
local rule_content="ACTION==\"add\", SUBSYSTEM==\"net\", ATTR{address}==\"$original_mac\", RUN+=\"/usr/bin/ip link set dev \$name address $target_mac\""
|
|
|
|
# Escreve no ficheiro de regras
|
|
echo "$rule_content" > "$UDEV_RULES_FILE"
|
|
|
|
# Verifica se o ficheiro foi criado com sucesso
|
|
if [ -f "$UDEV_RULES_FILE" ]; then
|
|
log "Sucesso: Ficheiro de regras Udev criado em $UDEV_RULES_FILE."
|
|
log "Conteúdo da regra: $rule_content"
|
|
else
|
|
log "Erro: Falha ao criar o ficheiro de regras Udev em $UDEV_RULES_FILE."
|
|
return 1
|
|
fi
|
|
|
|
# Recarrega as regras do udev
|
|
if udevadm control --reload-rules; then
|
|
log "Regras Udev recarregadas com sucesso."
|
|
else
|
|
log "Erro: Falha ao recarregar regras Udev."
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Função robusta para verificar persistência
|
|
is_persistence_configured() {
|
|
if [ -f "$UDEV_RULES_FILE" ]; then
|
|
if [ -s "$UDEV_RULES_FILE" ]; then
|
|
log "Ficheiro de persistência encontrado: $UDEV_RULES_FILE"
|
|
return 0
|
|
else
|
|
log "Ficheiro de persistência existe mas está vazio. Invalidando."
|
|
return 1
|
|
fi
|
|
else
|
|
log "Ficheiro de persistência NÃO encontrado."
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Tarefa em Background para monitorizar rede
|
|
monitor_network_task() {
|
|
log "Monitor: A iniciar verificação de rede (aguardando 60s)..."
|
|
sleep 60
|
|
|
|
local interface="eth0"
|
|
local wlan="wlan0"
|
|
|
|
if ip link show "$interface" &> /dev/null; then
|
|
if ip link show "$interface" | grep -q "NO-CARRIER"; then
|
|
log "Monitor: Interface $interface sem cabo (NO-CARRIER). A ativar Wi-Fi..."
|
|
if ip link show "$wlan" &> /dev/null; then
|
|
ip link set "$wlan" up
|
|
log "Monitor: Wi-Fi ($wlan) ativado."
|
|
fi
|
|
else
|
|
log "Monitor: Interface $interface ativa. Nenhuma ação necessária."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# --- Execução Principal ---
|
|
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
echo "Este script deve ser executado como root." >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$LOG_FILE")"
|
|
|
|
# 1. Verificar Persistência Existente
|
|
if is_persistence_configured; then
|
|
log "Configuração já persistida no sistema. A saltar configuração de MAC."
|
|
monitor_network_task &
|
|
exit 0
|
|
fi
|
|
|
|
# 2. Esperar pela Interface de Rede (Importante para boot/curl)
|
|
IFACE="eth0"
|
|
log "A aguardar pela interface $IFACE..."
|
|
for i in {1..30}; do
|
|
if ip link show "$IFACE" &> /dev/null; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if ! ip link show "$IFACE" &> /dev/null; then
|
|
log "Erro: Interface $IFACE não disponível após 30 segundos. A sair."
|
|
exit 1
|
|
fi
|
|
|
|
# 3. Determinar o MAC Address
|
|
TARGET_MAC=""
|
|
|
|
# Verificar argumento ($1)
|
|
if [ -n "$1" ]; then
|
|
TARGET_MAC="$1"
|
|
log "MAC definido via argumento: $TARGET_MAC"
|
|
else
|
|
# Verificar se é interativo
|
|
if [ -t 0 ] && [ -e /dev/tty ]; then
|
|
# Pergunta ao utilizador se quer gerar um MAC automaticamente
|
|
if ask_confirmation "Deseja gerar um novo MAC único automaticamente?" "y"; then
|
|
TARGET_MAC=$(generate_unique_mac)
|
|
log "MAC gerado automaticamente: $TARGET_MAC"
|
|
else
|
|
# Pergunta para introduzir MAC manualmente
|
|
while true; do
|
|
read -p "Introduza o MAC (formato XX:XX:XX:XX:XX:XX): " TARGET_MAC < /dev/tty
|
|
if [[ "$TARGET_MAC" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
|
|
break
|
|
else
|
|
echo "Formato de MAC inválido. Por favor, introduza no formato XX:XX:XX:XX:XX:XX."
|
|
fi
|
|
done
|
|
fi
|
|
else
|
|
# Modo não interativo (boot/curl) sem argumentos: Gerar automático
|
|
log "Execução não interativa. A gerar MAC único..."
|
|
TARGET_MAC=$(generate_unique_mac)
|
|
log "MAC gerado: $TARGET_MAC"
|
|
fi
|
|
fi
|
|
|
|
# Validação simples do MAC
|
|
if [[ ! "$TARGET_MAC" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]; then
|
|
log "MAC Address inválido ou vazio: $TARGET_MAC"
|
|
exit 1
|
|
fi
|
|
|
|
# 4. Aplicar Configuração
|
|
log "A configurar sistema com MAC: $TARGET_MAC"
|
|
|
|
if set_mac "$IFACE" "$TARGET_MAC"; then
|
|
setup_udev_persistence "$IFACE" "$TARGET_MAC"
|
|
else
|
|
log "Aviso: Falha ao definir MAC em tempo real, mas a tentar criar persistência..."
|
|
setup_udev_persistence "$IFACE" "$TARGET_MAC"
|
|
fi
|
|
|
|
# 5. Lançar Monitor de Rede
|
|
monitor_network_task &
|
|
|
|
exit 0 |