#!/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 é boot (não interativo e sem /dev/tty disponível) if [ ! -t 0 ] && [ ! -e /dev/tty ]; then # Modo boot: Não fazer nada, assumindo que já foi configurado log "${YELLOW}Modo boot: A saltar configuração de MAC (assumindo que já foi configurado)${NC}" exit 0 else # 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