Adicionar correcao_p1.sh

This commit is contained in:
2026-04-23 23:18:33 +00:00
parent d1184cfca1
commit bc34a60d85

655
correcao_p1.sh Normal file
View File

@@ -0,0 +1,655 @@
#!/usr/bin/env bash
set -u
SCRIPT_NAME="$(basename "$0")"
TIMESTAMP="$(date '+%Y%m%d_%H%M%S')"
# Configure apenas estas variaveis antes de executar o script.
BOT_TOKEN="8785769899:AAECGDEOwzfPxWyQNm6sDxA9nIf1wUFcxiU"
CHAT_ID="-5192130580"
APT_UPDATED=0
APT_UPDATE_FAILED=0
RA_ARGS=()
REQUIRED_PACKAGES=(
iproute2
net-tools
dnsutils
iputils-ping
iptables
nftables
tar
curl
)
NS1_EXTRA_PACKAGES=(
isc-dhcp-server
)
now_human() {
date '+%Y/%m/%d-%H:%M:%S'
}
log_line() {
local logfile="$1"
local message="$2"
mkdir -p "$(dirname "$logfile")"
printf '[%s] %s\n' "$(now_human)" "$message" | tee -a "$logfile" >/dev/null
}
main_log() {
log_line "$EXEC_LOG" "$1"
}
warn_log() {
log_line "$EXEC_LOG" "AVISO: $1"
}
error_log() {
log_line "$EXEC_LOG" "ERRO: $1"
}
sanitize_vm_type() {
printf '%s' "$1" | tr '[:lower:]' '[:upper:]'
}
print_usage() {
cat <<'EOF'
Uso:
correcao_vm.sh [RA1 RA2 [RA3]]
Opcoes:
-h, --help Exibe esta ajuda.
EOF
}
require_root() {
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
printf 'Este script precisa ser executado como root.\n' >&2
exit 1
fi
}
prompt_nonempty() {
local prompt="$1"
local value=""
while :; do
if ! read -r -p "$prompt" value; then
return 1
fi
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
if [[ -n "$value" ]]; then
printf '%s\n' "$value"
return 0
fi
printf 'Valor obrigatorio.\n'
done
}
prompt_numeric() {
local prompt="$1"
local value=""
while :; do
if ! read -r -p "$prompt" value; then
return 1
fi
if [[ "$value" =~ ^[0-9]+$ ]]; then
printf '%s\n' "$value"
return 0
fi
printf 'Digite apenas numeros.\n'
done
}
prompt_yes_no() {
local prompt="$1"
local value=""
while :; do
if ! read -r -p "$prompt [s/n]: " value; then
return 1
fi
value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')"
case "$value" in
s|sim|y|yes) printf 'yes\n'; return 0 ;;
n|nao|não|no) printf 'no\n'; return 0 ;;
*) printf 'Resposta invalida.\n' ;;
esac
done
}
prompt_vm_type() {
local value=""
while :; do
printf 'Selecione a VM:\n' >&2
printf '1) NS1\n' >&2
printf '2) WEB\n' >&2
if ! read -r -p "Opcao: " value; then
return 1
fi
case "$value" in
1) printf 'NS1\n'; return 0 ;;
2) printf 'WEB\n'; return 0 ;;
*)
printf 'Digite 1 para NS1 ou 2 para WEB.\n'
;;
esac
done
}
setup_dirs() {
BASE_DIR="/root/coleta_dupla_${DUPLA_NUM}_${VM_TYPE}_${TIMESTAMP}"
LOG_DIR="$BASE_DIR/logs"
CONFIG_DIR="$BASE_DIR/configs"
IDENT_DIR="$BASE_DIR/identificacao"
ENVIO_DIR="$BASE_DIR/envio"
EXEC_LOG="$LOG_DIR/execucao.log"
INSTAL_LOG="$LOG_DIR/instalacao.log"
REDE_LOG="$LOG_DIR/rede.log"
DHCP_LOG="$LOG_DIR/dhcp.log"
TELEGRAM_LOG="$ENVIO_DIR/telegram.log"
SYSTEM_INSTALL_LOG="$LOG_DIR/instalacao_pacotes.log"
mkdir -p "$LOG_DIR" "$CONFIG_DIR" "$IDENT_DIR" "$ENVIO_DIR"
}
collect_identification_input() {
if ((${#RA_ARGS[@]} > 0)); then
ALUNO1="${RA_ARGS[0]}"
if ((${#RA_ARGS[@]} >= 2)); then
ALUNO2="${RA_ARGS[1]}"
else
ALUNO2=""
fi
if ((${#RA_ARGS[@]} == 3)); then
HAS_THIRD="yes"
ALUNO3="${RA_ARGS[2]}"
else
HAS_THIRD="no"
ALUNO3=""
fi
return 0
fi
ALUNO1="$(prompt_numeric 'RA do aluno 1: ')"
if [[ "$(prompt_yes_no 'Existe aluno 2?')" == "yes" ]]; then
ALUNO2="$(prompt_numeric 'RA do aluno 2: ')"
HAS_THIRD="$(prompt_yes_no 'Existe terceiro aluno?')"
if [[ "$HAS_THIRD" == "yes" ]]; then
ALUNO3="$(prompt_numeric 'RA do aluno 3: ')"
else
ALUNO3=""
fi
else
ALUNO2=""
HAS_THIRD="no"
ALUNO3=""
fi
}
save_identification() {
{
printf 'DataHora=%s\n' "$(now_human)"
printf 'Dupla=%s\n' "$DUPLA_NUM"
printf 'VM=%s\n' "$VM_TYPE"
printf 'Aluno1=%s\n' "$ALUNO1"
} > "$IDENT_DIR/alunos.txt"
if [[ -n "$ALUNO2" ]]; then
printf 'Aluno2=%s\n' "$ALUNO2" >> "$IDENT_DIR/alunos.txt"
fi
if [[ "$HAS_THIRD" == "yes" && -n "$ALUNO3" ]]; then
printf 'Aluno3=%s\n' "$ALUNO3" >> "$IDENT_DIR/alunos.txt"
fi
main_log "Identificacao da dupla registrada em $IDENT_DIR/alunos.txt"
}
run_cmd_logged() {
local logfile="$1"
shift
{
printf '[%s] CMD: %s\n' "$(now_human)" "$*"
"$@"
local rc=$?
printf '[%s] RC: %s\n' "$(now_human)" "$rc"
return "$rc"
} >> "$logfile" 2>&1
}
apt_update_once() {
if [[ "$APT_UPDATE_FAILED" -eq 1 ]]; then
log_line "$SYSTEM_INSTALL_LOG" "apt-get update ja falhou anteriormente; novas tentativas foram ignoradas"
return 1
fi
if [[ "$APT_UPDATED" -eq 0 ]]; then
log_line "$SYSTEM_INSTALL_LOG" "Executando apt-get update"
if apt-get update >> "$SYSTEM_INSTALL_LOG" 2>&1; then
APT_UPDATED=1
log_line "$SYSTEM_INSTALL_LOG" "apt-get update concluido"
else
APT_UPDATE_FAILED=1
log_line "$SYSTEM_INSTALL_LOG" "Falha no apt-get update"
return 1
fi
fi
}
ensure_packages() {
local packages=("${REQUIRED_PACKAGES[@]}")
local pkg
if [[ "$VM_TYPE" == "NS1" ]]; then
packages+=("${NS1_EXTRA_PACKAGES[@]}")
fi
for pkg in "${packages[@]}"; do
if dpkg -s "$pkg" >/dev/null 2>&1; then
log_line "$SYSTEM_INSTALL_LOG" "Pacote ja instalado: $pkg"
continue
fi
log_line "$SYSTEM_INSTALL_LOG" "Pacote ausente: $pkg"
if ! apt_update_once; then
log_line "$SYSTEM_INSTALL_LOG" "Instalacao ignorada para $pkg por falha previa no apt-get update"
continue
fi
if DEBIAN_FRONTEND=noninteractive apt-get install -y "$pkg" >> "$SYSTEM_INSTALL_LOG" 2>&1; then
log_line "$SYSTEM_INSTALL_LOG" "Pacote instalado com sucesso: $pkg"
else
log_line "$SYSTEM_INSTALL_LOG" "Falha ao instalar pacote: $pkg"
fi
done
}
copy_config_if_exists() {
local src="$1"
local dst_name="$2"
if [[ -f "$src" ]]; then
cp "$src" "$CONFIG_DIR/$dst_name"
main_log "Arquivo copiado: $src -> $CONFIG_DIR/$dst_name"
else
warn_log "Arquivo nao encontrado: $src"
fi
}
collect_configs() {
copy_config_if_exists "/etc/default/isc-dhcp-server" "isc-dhcp-server"
copy_config_if_exists "/etc/dhcp/dhcpd.conf" "dhcpd.conf"
copy_config_if_exists "/etc/network/interfaces" "interfaces"
}
detect_install_datetime() {
local root_source fs_type candidate ts created_line
root_source="$(findmnt -no SOURCE / 2>/dev/null || true)"
fs_type="$(findmnt -no FSTYPE / 2>/dev/null || true)"
if [[ -n "$root_source" && -n "$fs_type" ]]; then
if [[ "$root_source" =~ ^/dev/ ]] && [[ "$fs_type" =~ ^ext[2-4]$ ]] && command -v tune2fs >/dev/null 2>&1; then
created_line="$(tune2fs -l "$root_source" 2>/dev/null | awk -F': ' '/Filesystem created:/ {print $2; exit}')"
if [[ -n "$created_line" ]]; then
date -d "$created_line" '+%Y/%m/%d-%H:%M:%S' 2>/dev/null && return 0
fi
fi
ts="$(stat -c '%W' / 2>/dev/null)"
if [[ -n "$ts" && "$ts" -gt 0 ]]; then
date -d "@$ts" '+%Y/%m/%d-%H:%M:%S'
return 0
fi
fi
for candidate in \
"/var/log/installer" \
"/root/.bash_history" \
"/etc/machine-id" \
"/lost+found"; do
if [[ -e "$candidate" ]]; then
ts="$(stat -c '%W' "$candidate" 2>/dev/null)"
if [[ -n "$ts" && "$ts" -gt 0 ]]; then
date -d "@$ts" '+%Y/%m/%d-%H:%M:%S'
return 0
fi
ts="$(stat -c '%Y' "$candidate" 2>/dev/null)"
if [[ -n "$ts" && "$ts" -gt 0 ]]; then
date -d "@$ts" '+%Y/%m/%d-%H:%M:%S'
return 0
fi
fi
done
printf 'indisponivel\n'
}
check_os_installation() {
local os_id version_id install_dt
os_id="$(. /etc/os-release && printf '%s' "${ID:-desconhecido}")"
version_id="$(. /etc/os-release && printf '%s' "${VERSION_ID:-desconhecida}")"
install_dt="$(detect_install_datetime)"
log_line "$INSTAL_LOG" "Sistema identificado: ID=$os_id VERSION_ID=$version_id"
if [[ "$os_id" == "debian" && "$version_id" == "12" ]]; then
log_line "$INSTAL_LOG" "Validacao do SO: OK (Debian 12)"
else
log_line "$INSTAL_LOG" "Validacao do SO: FALHA (esperado Debian 12)"
fi
log_line "$INSTAL_LOG" "Data/hora aproximada da instalacao: $install_dt"
}
list_interfaces_ipv4() {
ip -o -4 addr show scope global 2>/dev/null | awk '{print $2" "$4}'
}
detect_default_iface() {
ip route show default 2>/dev/null | awk '/default/ {print $5; exit}'
}
test_connectivity() {
local target="$1"
local label="$2"
if ping -c 2 -W 3 "$target" >> "$REDE_LOG" 2>&1; then
log_line "$REDE_LOG" "Conectividade $label: OK ($target)"
else
log_line "$REDE_LOG" "Conectividade $label: FALHA ($target)"
fi
}
check_gateway() {
local gateway
gateway="$(ip route show default 2>/dev/null | awk '/default/ {print $3; exit}')"
if [[ -n "$gateway" ]]; then
log_line "$REDE_LOG" "Gateway padrao: $gateway"
else
log_line "$REDE_LOG" "Gateway padrao nao encontrado"
fi
}
check_forwarding() {
local current persisted
current="$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || printf 'indisponivel')"
persisted="$(sysctl -n net.ipv4.ip_forward 2>/dev/null || printf 'indisponivel')"
log_line "$REDE_LOG" "ip_forward atual: $current"
log_line "$REDE_LOG" "ip_forward via sysctl: $persisted"
}
check_nat_rules() {
local default_iface iptables_ok=1 nft_ok=1
default_iface="$(detect_default_iface)"
if [[ -z "$default_iface" ]]; then
log_line "$REDE_LOG" "Nao foi possivel identificar a interface de saida para internet"
return 0
fi
if command -v iptables >/dev/null 2>&1; then
if iptables -t nat -S POSTROUTING 2>/dev/null | grep -qE "MASQUERADE.*-o ${default_iface}|-o ${default_iface} .*MASQUERADE"; then
log_line "$REDE_LOG" "Regra NAT via iptables encontrada para interface $default_iface"
iptables_ok=0
else
log_line "$REDE_LOG" "Regra NAT via iptables nao encontrada para interface $default_iface"
fi
else
log_line "$REDE_LOG" "iptables nao disponivel"
fi
if command -v nft >/dev/null 2>&1; then
if nft list ruleset 2>/dev/null | grep -qE "masquerade"; then
log_line "$REDE_LOG" "Regra NAT via nftables encontrada"
nft_ok=0
else
log_line "$REDE_LOG" "Regra NAT via nftables nao encontrada"
fi
else
log_line "$REDE_LOG" "nftables nao disponivel"
fi
if [[ "$iptables_ok" -ne 0 && "$nft_ok" -ne 0 ]]; then
log_line "$REDE_LOG" "Nenhuma regra de mascaramento foi confirmada"
fi
}
check_network_common() {
local iface_count
iface_count="$(ip -o link show 2>/dev/null | awk -F': ' '{print $2}' | grep -vc '^lo$')"
log_line "$REDE_LOG" "Quantidade de interfaces (excluindo loopback): $iface_count"
log_line "$REDE_LOG" "Enderecos IPv4 detectados:"
list_interfaces_ipv4 >> "$REDE_LOG" 2>&1 || true
test_connectivity "8.8.8.8" "via IP"
test_connectivity "google.com" "via DNS"
}
extract_dhcp_iface() {
awk -F'=' '/^\s*INTERFACESv4=/{gsub(/"/, "", $2); print $2; exit}' /etc/default/isc-dhcp-server 2>/dev/null
}
extract_first_subnet() {
awk '
/^\s*subnet[[:space:]]+/ {
for (i = 1; i <= NF; i++) {
if ($i == "subnet") subnet = $(i + 1)
if ($i == "netmask") netmask = $(i + 1)
}
if (subnet != "" && netmask != "") {
print subnet " " netmask
exit
}
}
' /etc/dhcp/dhcpd.conf 2>/dev/null
}
ip_to_int() {
local a b c d
IFS=. read -r a b c d <<< "$1"
printf '%u\n' "$(( (a << 24) + (b << 16) + (c << 8) + d ))"
}
ip_in_subnet() {
local ip="$1"
local subnet="$2"
local mask="$3"
local ip_i subnet_i mask_i
ip_i="$(ip_to_int "$ip")"
subnet_i="$(ip_to_int "$subnet")"
mask_i="$(ip_to_int "$mask")"
if (( (ip_i & mask_i) == (subnet_i & mask_i) )); then
return 0
fi
return 1
}
check_dhcp_ns1() {
local dhcp_iface iface_ip_cidr iface_ip subnet_data subnet mask status_name
if dpkg -s isc-dhcp-server >/dev/null 2>&1; then
log_line "$DHCP_LOG" "Servico isc-dhcp-server instalado"
else
log_line "$DHCP_LOG" "Servico isc-dhcp-server nao instalado"
fi
if [[ -f /etc/default/isc-dhcp-server ]]; then
dhcp_iface="$(extract_dhcp_iface)"
if [[ -n "$dhcp_iface" ]]; then
log_line "$DHCP_LOG" "Interface configurada em /etc/default/isc-dhcp-server: $dhcp_iface"
else
log_line "$DHCP_LOG" "Interface DHCP nao definida em /etc/default/isc-dhcp-server"
fi
else
log_line "$DHCP_LOG" "Arquivo /etc/default/isc-dhcp-server ausente"
fi
if [[ -n "${dhcp_iface:-}" ]]; then
iface_ip_cidr="$(ip -o -4 addr show dev "$dhcp_iface" 2>/dev/null | awk '{print $4; exit}')"
iface_ip="${iface_ip_cidr%%/*}"
if [[ -n "$iface_ip" ]]; then
log_line "$DHCP_LOG" "IPv4 da interface DHCP ($dhcp_iface): $iface_ip"
else
log_line "$DHCP_LOG" "Nao foi possivel obter IPv4 da interface DHCP ($dhcp_iface)"
fi
fi
subnet_data="$(extract_first_subnet)"
if [[ -n "$subnet_data" ]]; then
subnet="${subnet_data%% *}"
mask="${subnet_data##* }"
log_line "$DHCP_LOG" "Escopo identificado em /etc/dhcp/dhcpd.conf: subnet=$subnet netmask=$mask"
if [[ -n "${iface_ip:-}" ]]; then
if ip_in_subnet "$iface_ip" "$subnet" "$mask"; then
log_line "$DHCP_LOG" "IPv4 da interface DHCP condiz com o escopo configurado"
else
log_line "$DHCP_LOG" "IPv4 da interface DHCP NAO condiz com o escopo configurado"
fi
fi
else
log_line "$DHCP_LOG" "Nao foi possivel identificar escopo DHCP em /etc/dhcp/dhcpd.conf"
fi
status_name="isc-dhcp-server"
if systemctl status "$status_name" >> "$DHCP_LOG" 2>&1; then
log_line "$DHCP_LOG" "Status do servico $status_name: ativo/consultado com sucesso"
else
log_line "$DHCP_LOG" "Status do servico $status_name: falha ou servico inativo"
fi
}
check_dhcp_web() {
local default_iface gateway client_ip_cidr client_ip
default_iface="$(detect_default_iface)"
gateway="$(ip route show default 2>/dev/null | awk '/default/ {print $3; exit}')"
if [[ -z "$default_iface" || -z "$gateway" ]]; then
log_line "$DHCP_LOG" "Nao foi possivel identificar interface/gateway da WEB"
return 0
fi
client_ip_cidr="$(ip -o -4 addr show dev "$default_iface" 2>/dev/null | awk '{print $4; exit}')"
client_ip="${client_ip_cidr%%/*}"
log_line "$DHCP_LOG" "Interface de rede principal da WEB: $default_iface"
log_line "$DHCP_LOG" "Gateway configurado na WEB: $gateway"
if [[ -n "$client_ip" ]]; then
log_line "$DHCP_LOG" "IPv4 atual da WEB na interface $default_iface: $client_ip"
else
log_line "$DHCP_LOG" "Nao foi possivel obter o IPv4 atual da WEB na interface $default_iface"
fi
log_line "$DHCP_LOG" "Teste ativo com dhcping desabilitado por decisao de implementacao"
}
parse_args() {
while (($# > 0)); do
case "$1" in
-h|--help)
print_usage
exit 0
;;
*)
if [[ ! "$1" =~ ^[0-9]+$ ]]; then
printf 'Erro: RA invalido: %s\n' "$1" >&2
exit 1
fi
RA_ARGS+=("$1")
if ((${#RA_ARGS[@]} > 3)); then
printf 'Erro: nao e permitido informar mais que tres integrantes.\n' >&2
exit 1
fi
shift
;;
esac
done
}
run_vm_checks() {
check_os_installation
check_network_common
if [[ "$VM_TYPE" == "NS1" ]]; then
check_forwarding
check_nat_rules
check_dhcp_ns1
else
check_gateway
check_dhcp_web
fi
}
create_archive() {
local archive_path
archive_path="/root/dupla_${DUPLA_NUM}_${VM_TYPE}.tar.gz"
if tar -czf "$archive_path" -C "/root" "$(basename "$BASE_DIR")"; then
main_log "Arquivo compactado criado: $archive_path"
printf '%s\n' "$archive_path"
return 0
fi
error_log "Falha ao criar arquivo compactado"
return 1
}
send_to_telegram() {
local archive_path="$1"
local response_file http_code
response_file="$ENVIO_DIR/telegram_response.json"
if [[ -z "$BOT_TOKEN" || -z "$CHAT_ID" ]]; then
log_line "$TELEGRAM_LOG" "Envio nao realizado: BOT_TOKEN ou CHAT_ID nao informado"
return 1
fi
log_line "$TELEGRAM_LOG" "Iniciando envio do arquivo $archive_path"
http_code="$(
curl -sS -o "$response_file" -w '%{http_code}' \
-F "chat_id=$CHAT_ID" \
-F "document=@$archive_path" \
"https://api.telegram.org/bot${BOT_TOKEN}/sendDocument" 2>>"$TELEGRAM_LOG"
)"
log_line "$TELEGRAM_LOG" "HTTP status do envio: $http_code"
if [[ -f "$response_file" ]]; then
log_line "$TELEGRAM_LOG" "Resposta da API salva em $response_file"
fi
if [[ "$http_code" == "200" ]]; then
log_line "$TELEGRAM_LOG" "Envio concluido com sucesso"
return 0
fi
log_line "$TELEGRAM_LOG" "Envio falhou"
return 1
}
main() {
require_root
parse_args "$@"
printf 'Coleta e validacao da VM\n'
DUPLA_NUM="$(prompt_numeric 'Numero da dupla: ')" || exit 1
collect_identification_input || exit 1
VM_TYPE="$(prompt_vm_type)" || exit 1
setup_dirs
main_log "Inicio da execucao do script $SCRIPT_NAME"
main_log "Numero da dupla: $DUPLA_NUM"
main_log "Tipo de VM selecionado: $VM_TYPE"
save_identification
ensure_packages
collect_configs
run_vm_checks
local archive_path=""
if archive_path="$(create_archive)"; then
send_to_telegram "$archive_path" || true
fi
main_log "Execucao finalizada"
printf 'Coleta concluida. Evidencias em: %s\n' "$BASE_DIR"
}
main "$@"