#!/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 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 ficheiro de regras echo "ACTION==\"add\", SUBSYSTEM==\"net\", ATTR{address}==\"$original_mac\", RUN+=\"/usr/bin/ip link set dev \$name address $target_mac\"" > "$UDEV_RULES_FILE" udevadm control --reload-rules log "Regra Udev criada/atualizada em $UDEV_RULES_FILE." return 0 } # Função robusta para verificar persistência is_persistence_configured() { if [ -f "$UDEV_RULES_FILE" ]; then # Verifica se o ficheiro não está vazio (proteção extra) 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) # O script pode correr antes da interface estar pronta. 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 # IMPORTANTE: Ler de /dev/tty para funcionar com curl | bash if [ -t 0 ] && [ -e /dev/tty ]; then # Abre /dev/tty para ler input do utilizador exec < /dev/tty echo "Nenhum MAC definido. Deseja:" echo "1) Gerar um novo MAC único automático" echo "2) Introduzir um MAC manualmente" read -p "Opção [1/2]: " choice case "$choice" in 1) TARGET_MAC=$(generate_unique_mac) log "MAC gerado automaticamente: $TARGET_MAC" ;; 2) read -p "Introduza o MAC (formato XX:XX:XX:XX:XX:XX): " TARGET_MAC ;; *) log "Opção inválida." exit 1 ;; esac # Restaura stdin se necessário (embora geralmente não seja crítico aqui) 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