Skip to content

Instantly share code, notes, and snippets.

@anonymousik
Last active February 27, 2026 04:33
Show Gist options
  • Select an option

  • Save anonymousik/11c364db0b16568382b3dc9009ad37de to your computer and use it in GitHub Desktop.

Select an option

Save anonymousik/11c364db0b16568382b3dc9009ad37de to your computer and use it in GitHub Desktop.
SecFerro · RouterOS Lab Installer

SecFerro · RouterOS Lab Installer

Pełne środowisko testowe RouterOS + SMTP w Termux, instalowane jedną komendą.


Uruchomienie jedną komendą

curl -fsSL https://gist.githubusercontent.com/anonymousik/11c364db0b16568382b3dc9009ad37de/raw/23c3e79412da0a634168e98c9177491ec71d458d/install.sh | bash

lub z wget:

wget -qO- https://gist.githubusercontent.com/anonymousik/11c364db0b16568382b3dc9009ad37de/raw/23c3e79412da0a634168e98c9177491ec71d458d/install.sh | bash

Co instaluje

Komponent Opis
QEMU Emulator x86-64 dla RouterOS CHR
RouterOS CHR 6.49 emu.secferro.lan @ 192.168.168.168
Postfix Lokalny serwer SMTP
msmtp Klient SMTP z auto-konfiguracją
Narzędzia sieciowe nmap, netcat, curl, iproute2
Bezpieczeństwo Losowe hasła (openssl / urandom / python3)

Aliasy po instalacji

source ~/.bashrc

sfstart    # Uruchom VM RouterOS
sfstop     # Zatrzymaj VM
secferro   # Dashboard statusu
sftest     # Security audit

Struktura katalogów

~/secferro/
├── .secrets/               # Hasła (chmod 700/600)
│   ├── mail_password
│   ├── ros_password
│   ├── winbox_password
│   ├── api_token
│   ├── dkim_private.pem
│   └── dkim_public.pem
├── config/
│   ├── postfix/            # Konfiguracja serwera SMTP
│   ├── msmtp/              # Konfiguracja klienta SMTP
│   └── routeros/           # Skrypt init.rsc dla RouterOS
├── vm/
│   └── routeros.qcow2
├── scripts/
│   ├── start_vm.sh
│   ├── stop_vm.sh
│   ├── status.sh
│   ├── test_mail.sh
│   ├── security_test.sh
│   └── backup.sh
├── logs/
│   ├── install_YYYYMMDD_HHMMSS.log
│   ├── qemu.log
│   └── msmtp.log
├── backups/
└── ACCESS_CREDENTIALS.txt  # Hasła – chmod 600

Wymagania

  • Termux (Android) – ARM64
  • Min. 512 MB RAM wolnej
  • Min. 1 GB wolnego miejsca
  • Połączenie z internetem

Bezpieczeństwo haseł

Generowane metodą kaskadową:

  1. openssl rand (kryptograficznie bezpieczny PRNG)
  2. /dev/urandom (jądro Linux)
  3. python3 secrets (CSPRNG stdlib)
  4. SHA-256 z entropii systemowej (fallback)

Przechowywane w ~/secferro/.secrets/ z prawami 700/600. Nigdy nie są hardcoded w skryptach ani logach.

#!/data/data/com.termux/files/usr/bin/bash
# ============================================================
# SecFerro · HOTFIX v1.0
# Naprawia wszystkie problemy wykryte w sesji diagnostycznej
#
# Uruchom: bash hotfix.sh
# ============================================================
set -uo pipefail
G='\033[0;32m' R='\033[0;31m' Y='\033[1;33m'
C='\033[0;36m' W='\033[1;37m' DIM='\033[2m' NC='\033[0m'
BOLD='\033[1m'
OK="${G}[✓]${NC}" FAIL="${R}[✗]${NC}" WARN="${Y}[!]${NC}"
INFO="${C}[i]${NC}" STEP="${W}[→]${NC}"
SCRIPTS="$HOME/secferro/scripts"
LOG_DIR="$HOME/secferro/logs"
VM_DIR="$HOME/secferro/vm"
echo -e "${BOLD}${C}"
echo " ╔══════════════════════════════════════════════════════╗"
echo " ║ SecFerro · HOTFIX v1.0 · Diagnostyka + Naprawa ║"
echo " ╚══════════════════════════════════════════════════════╝"
echo -e "${NC}"
# ─────────────────────────────────────────────────────────────
# DIAGNOZA PROBLEMÓW
# ─────────────────────────────────────────────────────────────
echo -e "${BOLD}${Y}━━ [1/5] DIAGNOZA ŚRODOWISKA ━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -ne " ${STEP} Architektura CPU: "
ARCH=$(uname -m); echo -e "${W}${ARCH}${NC}"
echo -ne " ${STEP} QEMU dostępny: "
if command -v qemu-system-x86_64 &>/dev/null; then
QEMU_VER=$(qemu-system-x86_64 --version 2>/dev/null | head -1)
echo -e "${G}${QEMU_VER}${NC}"
else
echo -e "${R}BRAK${NC}"
fi
echo -ne " ${STEP} GTK/Display: "
# Na Termux GTK nie istnieje – QEMU musi działać w trybie -nographic
if qemu-system-x86_64 -display help 2>&1 | grep -q "none"; then
echo -e "${G}none (headless) dostępny${NC}"
else
echo -e "${Y}brak detekcji – użyjemy -nographic${NC}"
fi
echo -ne " ${STEP} KVM (hardware accel): "
if [[ -e /dev/kvm ]]; then
echo -e "${G}DOSTĘPNE${NC}"
KVM_FLAG="-enable-kvm -cpu host"
else
echo -e "${Y}NIEDOSTĘPNE (Android/brak uprawnień) – emulacja software${NC}"
KVM_FLAG="-cpu qemu64"
fi
echo -ne " ${STEP} RAM dostępny: "
RAM_MB=$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo)
echo -e "${W}${RAM_MB} MB${NC}"
[[ $RAM_MB -lt 300 ]] && \
echo -e " ${WARN} Mało RAM! RouterOS wymaga min 256 MB. Redukuję do 192 MB."
ROS_MEM=$([[ $RAM_MB -lt 300 ]] && echo 192 || echo 256)
echo -ne " ${STEP} Obraz VM: "
if [[ -f "$VM_DIR/routeros.qcow2" ]]; then
VM_SIZE=$(du -sh "$VM_DIR/routeros.qcow2" 2>/dev/null | cut -f1)
echo -e "${G}OK (${VM_SIZE})${NC}"
else
echo -e "${R}BRAK – $VM_DIR/routeros.qcow2${NC}"
fi
echo -ne " ${STEP} Postfix: "
if command -v postfix &>/dev/null; then
echo -e "${G}zainstalowany${NC}"
POSTFIX_OK=true
else
echo -e "${Y}brak – próba instalacji${NC}"
POSTFIX_OK=false
fi
echo -ne " ${STEP} df Android compat.: "
# Android df nie obsługuje -m, sprawdź co działa
if df -k "$HOME" &>/dev/null 2>&1; then
echo -e "${G}-k działa${NC}"; DF_FLAG="-k"
elif df -P "$HOME" &>/dev/null 2>&1; then
echo -e "${G}-P działa${NC}"; DF_FLAG="-P"
else
echo -e "${Y}brak flag – użyję awk${NC}"; DF_FLAG=""
fi
echo ""
# ─────────────────────────────────────────────────────────────
# FIX 1: Postfix (jeśli brak)
# ─────────────────────────────────────────────────────────────
echo -e "${BOLD}${Y}━━ [2/5] FIX: POSTFIX ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
if [[ "$POSTFIX_OK" == false ]]; then
echo -e " ${STEP} Instaluję postfix..."
pkg install postfix -y 2>&1 | tail -3
if command -v postfix &>/dev/null; then
echo -e " ${OK} Postfix zainstalowany"
else
echo -e " ${WARN} Postfix niedostępny w repozytorium – instaluję alternatywę (ssmtp/msmtp)"
pkg install msmtp -y 2>&1 | tail -2
echo -e " ${INFO} Poczta wychodząca przez msmtp (bez serwera odbierającego)"
fi
else
echo -e " ${OK} Postfix już zainstalowany"
fi
# ─────────────────────────────────────────────────────────────
# FIX 2: Napraw start_vm.sh (główny problem – GTK + daemonize)
# ─────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${Y}━━ [3/5] FIX: start_vm.sh (GTK + -daemonize) ━━━━━━━━${NC}"
cat > "$SCRIPTS/start_vm.sh" << STARTVM
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Start RouterOS VM (Termux-fixed) ─────────────
# Poprawka: usunięto -daemonize (nie działa w Termux)
# usunięto -cpu host (KVM niedostępny na Android)
# dodano -display none -vga none (brak GTK)
# użyto nohup + & zamiast -daemonize
VM_DIR="\${HOME}/secferro/vm"
LOG_DIR="\${HOME}/secferro/logs"
PID_FILE="\${VM_DIR}/qemu.pid"
QEMU_LOG="\${LOG_DIR}/qemu.log"
mkdir -p "\$LOG_DIR"
# Sprawdź duplikat
if [[ -f "\$PID_FILE" ]]; then
OLD_PID=\$(cat "\$PID_FILE")
if kill -0 "\$OLD_PID" 2>/dev/null; then
echo -e "[\033[1;33m!\033[0m] VM już działa (PID: \$OLD_PID)"
exit 0
else
echo -e "[\033[0;33m~\033[0m] Stary PID \$OLD_PID nie żyje – czyszczę"
rm -f "\$PID_FILE"
fi
fi
# Sprawdź obraz
if [[ ! -f "\${VM_DIR}/routeros.qcow2" ]]; then
echo -e "[\033[0;31m✗\033[0m] Brak obrazu: \${VM_DIR}/routeros.qcow2"
echo " Uruchom ponownie install.sh aby pobrać obraz RouterOS"
exit 1
fi
# Wykryj KVM
KVM_ARGS=""
if [[ -e /dev/kvm ]] && [[ -r /dev/kvm ]]; then
KVM_ARGS="-enable-kvm -cpu host"
echo -e "[\033[0;32m✓\033[0m] KVM dostępny – włączam akcelerację sprzętową"
else
KVM_ARGS="-cpu qemu64 -accel tcg,thread=single"
echo -e "[\033[1;33m!\033[0m] KVM niedostępny – tryb TCG (wolniejszy, normalny na Android)"
fi
RAM=${ROS_MEM}
echo ""
echo -e " \033[0;36m╔══════════════════════════════════════════╗\033[0m"
echo -e " \033[0;36m║ SecFerro · RouterOS VM · Start ║\033[0m"
echo -e " \033[0;36m╚══════════════════════════════════════════╝\033[0m"
echo ""
echo -e " Host: emu.secferro.lan"
echo -e " IP: 192.168.168.168"
echo -e " RAM: \${RAM} MB"
echo -e " Log: \$QEMU_LOG"
echo ""
# ── Uruchomienie w tle (nohup + & zamiast -daemonize) ────────
nohup qemu-system-x86_64 \\
-name "emu.secferro.lan" \\
-m "\${RAM}" \\
-smp 1 \\
\${KVM_ARGS} \\
-machine type=q35 \\
-display none \\
-vga none \\
-serial none \\
-monitor none \\
-drive file="\${VM_DIR}/routeros.qcow2",format=qcow2,if=ide,cache=writeback \\
-netdev user,id=net0,\\
net=192.168.168.0/24,\\
host=192.168.168.1,\\
hostfwd=tcp::2222-:22,\\
hostfwd=tcp::8291-:8291,\\
hostfwd=tcp::2525-:25 \\
-device e1000,netdev=net0,mac=D4:CA:6D:18:16:28 \\
-rtc base=utc \\
-boot c \\
>> "\$QEMU_LOG" 2>&1 &
QEMU_PID=\$!
echo \$QEMU_PID > "\$PID_FILE"
# Poczekaj chwilę i sprawdź czy żyje
sleep 3
if kill -0 "\$QEMU_PID" 2>/dev/null; then
echo -e " \033[0;32m[✓]\033[0m VM uruchomiona (PID: \$QEMU_PID)"
echo ""
echo -e " \033[0;36mPorty dostępowe (po ~30s boot RouterOS):\033[0m"
echo -e " SSH: ssh -p 2222 admin@127.0.0.1"
echo -e " SMTP: 127.0.0.1:2525"
echo -e " Winbox: 127.0.0.1:8291"
echo ""
echo -e " \033[2mLog na żywo: tail -f \$QEMU_LOG\033[0m"
echo -e " \033[2mStatus: ~/secferro/scripts/status.sh\033[0m"
else
echo -e " \033[0;31m[✗]\033[0m VM nie uruchomiła się! Sprawdź log:"
echo -e " tail -30 \$QEMU_LOG"
tail -10 "\$QEMU_LOG" 2>/dev/null || true
rm -f "\$PID_FILE"
exit 1
fi
STARTVM
chmod +x "$SCRIPTS/start_vm.sh"
echo -e " ${OK} start_vm.sh naprawiony"
# ─────────────────────────────────────────────────────────────
# FIX 3: Napraw status.sh (df -m → Android compat)
# ─────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${Y}━━ [4/5] FIX: status.sh (df Android) ━━━━━━━━━━━━━━━━${NC}"
cat > "$SCRIPTS/status.sh" << 'STATSH'
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Status Dashboard (Android-fixed) ─────────────
C='\033[0;36m' G='\033[0;32m' R='\033[0;31m'
Y='\033[1;33m' W='\033[1;37m' DIM='\033[2m' NC='\033[0m'
VM_DIR="$HOME/secferro/vm"
PID_FILE="$VM_DIR/qemu.pid"
LOG_DIR="$HOME/secferro/logs"
# Funkcja: sprawdź port
port_check() {
nc -z -w2 127.0.0.1 "$1" 2>/dev/null \
&& echo -e " ${G}●${NC} ${1} – ${2}" \
|| echo -e " ${R}○${NC} ${1} – ${2} ${DIM}[zamknięty]${NC}"
}
# Funkcja: wolne miejsce (Android compat)
disk_free() {
# Próbuj różne metody
local result
result=$(df "$HOME" 2>/dev/null | awk 'NR==2{
# kolumna dostępna może być 4 (standard) lub 3 (busybox)
if ($4+0 > 0) printf "%d MB", $4/1024
else if ($3+0 > 0) printf "%d MB", $3/1024
else print "n/a"
}')
echo "${result:-n/a}"
}
echo ""
echo -e "${C} ╔══════════════════════════════════════════════╗${NC}"
echo -e "${C} ║ SecFerro · Status Dashboard ║${NC}"
echo -e "${C} ╚══════════════════════════════════════════════╝${NC}"
echo ""
# ── VM Status ─────────────────────────────────────────────────
echo -e " ${W}[ RouterOS VM ]${NC}"
if [[ -f "$PID_FILE" ]]; then
PID=$(cat "$PID_FILE")
if kill -0 "$PID" 2>/dev/null; then
UPTIME=$(ps -o etime= -p "$PID" 2>/dev/null | tr -d ' ' || echo "?")
echo -e " Status: ${G}● RUNNING${NC} (PID: ${PID} up: ${UPTIME})"
# Próbuj sprawdzić czy RouterOS już zabootował
nc -z -w2 127.0.0.1 2222 2>/dev/null \
&& echo -e " Boot: ${G}● RouterOS gotowy${NC}" \
|| echo -e " Boot: ${Y}⟳ Ładowanie...${NC} ${DIM}(SSH/Winbox niedostępne)${NC}"
else
echo -e " Status: ${R}● CRASHED${NC} ${DIM}(PID $PID już nie żyje)${NC}"
rm -f "$PID_FILE"
echo -e " ${DIM}Sprawdź: tail -30 $LOG_DIR/qemu.log${NC}"
fi
else
echo -e " Status: ${R}● STOPPED${NC}"
fi
echo ""
echo -e " ${W}[ Usługi pocztowe ]${NC}"
# Postfix
if command -v postfix &>/dev/null && pgrep -x master &>/dev/null; then
echo -e " Postfix: ${G}● RUNNING${NC}"
elif command -v postfix &>/dev/null; then
echo -e " Postfix: ${Y}● INSTALLED / NOT RUNNING${NC}"
else
echo -e " Postfix: ${R}● NOT INSTALLED${NC} ${DIM}(msmtp jako klient)${NC}"
fi
# msmtp
command -v msmtp &>/dev/null \
&& echo -e " msmtp: ${G}● dostępny${NC}" \
|| echo -e " msmtp: ${R}● brak${NC}"
echo ""
echo -e " ${W}[ Porty localhost ]${NC}"
port_check 2222 "SSH RouterOS (forward)"
port_check 2525 "SMTP RouterOS (forward)"
port_check 8291 "Winbox (forward)"
port_check 25 "Postfix SMTP"
echo ""
echo -e " ${W}[ Zasoby ]${NC}"
echo -e " RAM wolna: ${W}$(awk '/MemAvailable/{print int($2/1024)}' /proc/meminfo) MB${NC}"
echo -e " Dysk wolny: ${W}$(disk_free)${NC}"
if [[ -f "$VM_DIR/routeros.qcow2" ]]; then
echo -e " Obraz VM: ${W}$(du -sh "$VM_DIR/routeros.qcow2" 2>/dev/null | cut -f1)${NC}"
fi
echo ""
echo -e " ${W}[ Szybkie komendy ]${NC}"
echo -e " ${DIM}sfstart${NC} – uruchom VM ${DIM}sfstop${NC} – zatrzymaj VM"
echo -e " ${DIM}sftest${NC} – security scan ${DIM}sflog${NC} – pokaż log QEMU"
echo ""
STATSH
chmod +x "$SCRIPTS/status.sh"
echo -e " ${OK} status.sh naprawiony"
# ─────────────────────────────────────────────────────────────
# FIX 4: Napraw aliasy + dodaj sflog
# ─────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}${Y}━━ [5/5] FIX: Aliasy shell (.bashrc) ━━━━━━━━━━━━━━━━${NC}"
# Usuń stare aliasy secferro
sed -i '/secferro\|sfstart\|sfstop\|sftest\|sflog/d' "$HOME/.bashrc" 2>/dev/null || true
cat >> "$HOME/.bashrc" << ALIASES
# ── SecFerro aliases ─────────────────────────────────────────
alias secferro='bash ${HOME}/secferro/scripts/status.sh'
alias sfstart='bash ${HOME}/secferro/scripts/start_vm.sh'
alias sfstop='bash ${HOME}/secferro/scripts/stop_vm.sh'
alias sftest='bash ${HOME}/secferro/scripts/security_test.sh'
alias sfmail='bash ${HOME}/secferro/scripts/test_mail.sh'
alias sflog='tail -f ${HOME}/secferro/logs/qemu.log'
alias sflog30='tail -30 ${HOME}/secferro/logs/qemu.log'
ALIASES
echo -e " ${OK} Aliasy zaktualizowane"
echo -e " ${INFO} Uruchom: ${W}source ~/.bashrc${NC} aby aktywować"
# ─────────────────────────────────────────────────────────────
# PODSUMOWANIE
# ─────────────────────────────────────────────────────────────
echo ""
echo -e "${G}${BOLD} ╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${G}${BOLD} ║ Hotfix zakończony ║${NC}"
echo -e "${G}${BOLD} ╚══════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e " ${OK} Naprawiono: start_vm.sh (GTK + -daemonize + CPU)"
echo -e " ${OK} Naprawiono: status.sh (df Android compatibility)"
echo -e " ${OK} Naprawiono: aliasy shell"
echo ""
echo -e " ${W}Następne kroki:${NC}"
echo -e " ${C} 1.${NC} source ~/.bashrc"
echo -e " ${C} 2.${NC} sfstart"
echo -e " ${C} 3.${NC} sleep 40 && sflog30 ${DIM}# poczekaj na boot RouterOS${NC}"
echo -e " ${C} 4.${NC} secferro"
echo ""
echo -e " ${INFO} Jeśli VM nadal nie startuje:"
echo -e " ${DIM}tail -30 ~/secferro/logs/qemu.log${NC}"
echo ""
echo -e " ${INFO} Jeśli mało RAM – zmniejsz VM do 192 MB:"
echo -e " ${DIM}sed -i 's/^RAM=.*/RAM=192/' ~/secferro/scripts/start_vm.sh${NC}"
echo ""
#!/data/data/com.termux/files/usr/bin/bash
# ============================================================
# SecFerro · RouterOS Lab Installer
# Uruchomienie jedną komendą:
# curl -fsSL https://gist.githubusercontent.com/anonymousik/11c364db0b16568382b3dc9009ad37de/raw/23c3e79412da0a634168e98c9177491ec71d458d/install.sh | bash
# ============================================================
set -euo pipefail
# ── Wersja ──────────────────────────────────────────────────
VERSION="2.0.0"
GIST_RAW="curl -fsSL https://gist.githubusercontent.com/anonymousik/11c364db0b16568382b3dc9009ad37de/raw"
# ── Katalogi ────────────────────────────────────────────────
BASE_DIR="$HOME/secferro"
LOG_DIR="$BASE_DIR/logs"
CONF_DIR="$BASE_DIR/config"
SECRETS_DIR="$BASE_DIR/.secrets"
VM_DIR="$BASE_DIR/vm"
BACKUP_DIR="$BASE_DIR/backups"
SCRIPTS_DIR="$BASE_DIR/scripts"
# ── Sieć / Hosty ────────────────────────────────────────────
TERMUX_HOSTNAME="secferro.lan"
EMU_HOSTNAME="emu.secferro.lan"
EMU_IP="192.168.168.168"
EMU_LO="127.0.0.1"
MAIL_DOMAIN="secferro.lan"
MAIL_USER="test"
MAIL_LOGIN="${MAIL_USER}@${MAIL_DOMAIN}"
# ── RouterOS ────────────────────────────────────────────────
ROS_VERSION="6.49.13" # ostatnia stabilna 6.x LTS
ROS_IMAGE_URL="https://download.mikrotik.com/routeros/${ROS_VERSION}/chr-${ROS_VERSION}.img.zip"
ROS_MAC="D4:CA:6D:18:16:28"
ROS_MEMORY=256
ROS_CPUS=1
# ── Kolory ANSI ─────────────────────────────────────────────
R='\033[0;31m' G='\033[0;32m' Y='\033[1;33m'
B='\033[0;34m' C='\033[0;36m' W='\033[1;37m'
DIM='\033[2m' BOLD='\033[1m' NC='\033[0m'
# ── Ikony statusu ────────────────────────────────────────────
OK="${G}[✓]${NC}" FAIL="${R}[✗]${NC}"
WARN="${Y}[!]${NC}" INFO="${B}[i]${NC}"
STEP="${C}[→]${NC}" ARROW="${W}[»]${NC}"
# ── Log ─────────────────────────────────────────────────────
mkdir -p "$LOG_DIR"
LOGFILE="$LOG_DIR/install_$(date +%Y%m%d_%H%M%S).log"
exec > >(tee -a "$LOGFILE") 2>&1
# ── Pomocnicze funkcje ───────────────────────────────────────
banner() {
clear
echo -e "${C}"
cat << 'ART'
╔══════════════════════════════════════════════════════════════╗
║ ███████╗███████╗ ██████╗███████╗███████╗██████╗ ██████╗ ║
║ ██╔════╝██╔════╝██╔════╝██╔════╝██╔════╝██╔══██╗██╔═══██╗ ║
║ ███████╗█████╗ ██║ █████╗ █████╗ ██████╔╝██║ ██║ ║
║ ╚════██║██╔══╝ ██║ ██╔══╝ ██╔══╝ ██╔══██╗██║ ██║ ║
║ ███████║███████╗╚██████╗██║ ███████╗██║ ██║╚██████╔╝ ║
║ ╚══════╝╚══════╝ ╚═════╝╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ║
║ ║
║ RouterOS Lab Environment · v2.0.0 ║
║ Termux · QEMU · Postfix · MikroTik CHR ║
╚══════════════════════════════════════════════════════════════╝
ART
echo -e "${NC}"
echo -e " ${DIM}Host: ${TERMUX_HOSTNAME} VM: ${EMU_HOSTNAME} (${EMU_IP})${NC}"
echo -e " ${DIM}Log: ${LOGFILE}${NC}"
echo ""
}
section() {
echo ""
echo -e "${BOLD}${Y}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}${Y} $1${NC}"
echo -e "${BOLD}${Y}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
}
step() { echo -e " ${STEP} ${W}$*${NC}"; }
ok() { echo -e " ${OK} $*"; }
fail() { echo -e " ${FAIL} ${R}$*${NC}"; }
warn() { echo -e " ${WARN} ${Y}$*${NC}"; }
info() { echo -e " ${INFO} ${DIM}$*${NC}"; }
confirm() {
local msg="$1"
echo -e "\n ${ARROW} ${W}${msg}${NC} ${DIM}[T/n]${NC} \c"
read -r ans
[[ -z "$ans" || "$ans" =~ ^[TtYy]$ ]]
}
progress() {
local msg="$1"; shift
echo -ne " ${STEP} ${W}${msg}...${NC} "
if "$@" >> "$LOGFILE" 2>&1; then
echo -e "${OK}"
return 0
else
echo -e "${FAIL}"
warn "Szczegóły: tail -n30 $LOGFILE"
return 1
fi
}
# ── Generator bezpiecznych haseł ─────────────────────────────
# Używa /dev/urandom + openssl fallback + python3 fallback
gen_password() {
local length="${1:-32}"
local charset='A-Za-z0-9!@#%^&*()-_=+[]{}|;:,.<>?'
if command -v openssl &>/dev/null; then
openssl rand -base64 48 | tr -dc "$charset" | head -c "$length"
elif [ -r /dev/urandom ]; then
tr -dc "$charset" < /dev/urandom | head -c "$length"
elif command -v python3 &>/dev/null; then
python3 -c "
import secrets, string
alphabet = string.ascii_letters + string.digits + '!@#%^&*()-_=+[]{}|;:,.<>?'
print(''.join(secrets.choice(alphabet) for _ in range($length)), end='')
"
else
# ostateczny fallback – sha256 z entropii systemowej
echo -n "$(date +%N)$$RANDOM" | sha256sum | tr -dc 'A-Za-z0-9' | head -c "$length"
fi
}
# ── Zapisz/odczytaj sekrety ──────────────────────────────────
save_secret() {
local key="$1" val="$2"
mkdir -p "$SECRETS_DIR"
chmod 700 "$SECRETS_DIR"
echo "$val" > "$SECRETS_DIR/${key}"
chmod 600 "$SECRETS_DIR/${key}"
}
get_secret() {
local key="$1"
[[ -f "$SECRETS_DIR/${key}" ]] && cat "$SECRETS_DIR/${key}" || echo ""
}
# ─────────────────────────────────────────────────────────────
# KROK 0 · Diagnoza systemu
# ─────────────────────────────────────────────────────────────
diag_system() {
section "KROK 0 · Diagnostyka systemu"
local errors=0
# Architektura
ARCH=$(uname -m)
step "Architektura: ${ARCH}"
case "$ARCH" in
aarch64|arm64) ok "ARM64 – pełne wsparcie QEMU" ;;
x86_64) ok "x86_64 – wsparcie QEMU + KVM" ;;
*) warn "Nieobsługiwana architektura: ${ARCH}"; ((errors++)) ;;
esac
# Pamięć RAM
local mem_kb mem_mb
mem_kb=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
mem_mb=$((mem_kb / 1024))
step "Dostępna pamięć RAM: ${mem_mb} MB"
if [[ $mem_mb -ge 512 ]]; then ok "${mem_mb} MB – wystarczające"
elif [[ $mem_mb -ge 256 ]]; then warn "${mem_mb} MB – minimum (zalecane 512+)"
else fail "${mem_mb} MB – za mało!"; ((errors++)); fi
# Miejsce na dysku
local free_mb
free_mb=$(df "$HOME" | tail -1 | awk '{print int($4/1024)}')
step "Wolne miejsce: ${free_mb} MB"
if [[ $free_mb -ge 1024 ]]; then ok "${free_mb} MB – wystarczające"
else warn "${free_mb} MB – zalecane min. 1 GB"; fi
# Termux API / środowisko
step "Środowisko Termux"
if [[ -d /data/data/com.termux ]]; then
ok "Termux wykryty"
else
warn "Nie wygląda jak Termux – kontynuuję ostrożnie"
fi
# Połączenie sieciowe
step "Połączenie sieciowe"
if ping -c1 -W3 8.8.8.8 &>/dev/null || curl -sf --connect-timeout 5 https://cloudflare.com &>/dev/null; then
ok "Internet dostępny"
else
fail "Brak połączenia z internetem!"; ((errors++))
fi
# Python3
step "Python3"
if command -v python3 &>/dev/null; then
ok "$(python3 --version)"
else
warn "Brak python3 – zostanie zainstalowany"
fi
if [[ $errors -gt 0 ]]; then
fail "Znaleziono $errors krytycznych problemów."
confirm "Kontynuować mimo to?" || { fail "Instalacja przerwana."; exit 1; }
else
ok "Diagnostyka zakończona – system gotowy"
fi
}
# ─────────────────────────────────────────────────────────────
# KROK 1 · Pakiety systemowe
# ─────────────────────────────────────────────────────────────
install_packages() {
section "KROK 1 · Instalacja pakietów"
step "Aktualizacja repozytoriów"
progress "pkg update" pkg update -y
progress "pkg upgrade" pkg upgrade -y
local PKGS=(
# Wirtualizacja
qemu-utils qemu-system-x86-64
# Sieć
curl wget iproute2 netcat-openbsd nmap dnsutils
# Poczta
postfix msmtp msmtp-mta ca-certificates
# Narzędzia
python3 openssl jq unzip tar gzip bc
# Deweloperskie
git nano vim tmux screen
# Monitoring
htop net-tools procps
)
local failed_pkgs=()
for pkg in "${PKGS[@]}"; do
if pkg install -y "$pkg" >> "$LOGFILE" 2>&1; then
ok "Zainstalowano: ${pkg}"
else
warn "Nie udało się zainstalować: ${pkg}"
failed_pkgs+=("$pkg")
fi
done
if [[ ${#failed_pkgs[@]} -gt 0 ]]; then
warn "Pominięte pakiety: ${failed_pkgs[*]}"
warn "Niektóre funkcje mogą być niedostępne"
fi
ok "Pakiety zainstalowane"
}
# ─────────────────────────────────────────────────────────────
# KROK 2 · Generowanie sekretów
# ─────────────────────────────────────────────────────────────
generate_secrets() {
section "KROK 2 · Generowanie bezpiecznych haseł"
# Sprawdź czy sekrety już istnieją
if [[ -f "$SECRETS_DIR/mail_password" ]] && [[ -f "$SECRETS_DIR/ros_password" ]]; then
if ! confirm "Sekrety już istnieją. Wygenerować nowe?"; then
ok "Używam istniejących sekretów"
return 0
fi
fi
step "Generowanie hasła SMTP/mail (64 znaki)"
MAIL_PASS=$(gen_password 64)
save_secret "mail_password" "$MAIL_PASS"
ok "Hasło mail wygenerowane"
step "Generowanie hasła RouterOS admin (32 znaki)"
ROS_PASS=$(gen_password 32)
save_secret "ros_password" "$ROS_PASS"
ok "Hasło RouterOS wygenerowane"
step "Generowanie klucza DKIM (2048-bit RSA)"
if command -v openssl &>/dev/null; then
openssl genrsa -out "$SECRETS_DIR/dkim_private.pem" 2048 >> "$LOGFILE" 2>&1
openssl rsa -in "$SECRETS_DIR/dkim_private.pem" \
-pubout -out "$SECRETS_DIR/dkim_public.pem" >> "$LOGFILE" 2>&1
chmod 600 "$SECRETS_DIR/dkim_private.pem"
ok "Klucz DKIM wygenerowany"
else
warn "openssl niedostępny – pomijam DKIM"
fi
step "Generowanie hasła Winbox (20 znaków alfanumerycznych)"
WINBOX_PASS=$(gen_password 20 | tr -dc 'A-Za-z0-9' | head -c 20)
save_secret "winbox_password" "$WINBOX_PASS"
ok "Hasło Winbox wygenerowane"
# Token API (do skryptów automatyzacji)
step "Generowanie tokenu API (hex 128-bit)"
API_TOKEN=$(openssl rand -hex 16 2>/dev/null || gen_password 32 | tr -dc 'a-f0-9' | head -c 32)
save_secret "api_token" "$API_TOKEN"
ok "Token API wygenerowany"
ok "Wszystkie sekrety zapisane w: $SECRETS_DIR"
info "Uprawnienia katalogu sekretów: 700 / pliki: 600"
}
# ─────────────────────────────────────────────────────────────
# KROK 3 · Konfiguracja serwera pocztowego (Postfix)
# ─────────────────────────────────────────────────────────────
setup_mail_server() {
section "KROK 3 · Serwer SMTP (Postfix)"
MAIL_PASS=$(get_secret "mail_password")
mkdir -p "$CONF_DIR/postfix"
# main.cf
cat > "$CONF_DIR/postfix/main.cf" << POSTFIX_MAIN
# ── SecFerro · Postfix main.cf ──────────────────────────────
myhostname = ${EMU_HOSTNAME}
mydomain = ${MAIL_DOMAIN}
myorigin = \$mydomain
# Interfejsy nasłuchiwania
inet_interfaces = loopback-only
inet_protocols = ipv4
# Lokalne dostarczanie
mydestination = \$myhostname, localhost.\$mydomain, localhost, \$mydomain
mynetworks = 127.0.0.0/8, ${EMU_IP}/32
# TLS
smtpd_tls_security_level = may
smtpd_tls_cert_file = /etc/ssl/certs/ca-certificates.crt
smtp_tls_security_level = may
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
# Limity
message_size_limit = 10240000
mailbox_size_limit = 51200000
recipient_delimiter = +
# Uwierzytelnianie SASL
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = \$myhostname
broken_sasl_auth_clients = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
# Kolejkowanie
queue_run_delay = 300s
minimal_backoff_time = 300s
maximal_backoff_time = 4000s
# Alias
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
POSTFIX_MAIN
ok "Postfix main.cf przygotowany"
# Plik haseł SASL
mkdir -p "$CONF_DIR/postfix/sasl"
cat > "$CONF_DIR/postfix/sasl/passwd" << SASL_PASSWD
# format: hostname:port user:password
[${EMU_IP}]:25 ${MAIL_LOGIN}:${MAIL_PASS}
[${EMU_LO}]:25 ${MAIL_LOGIN}:${MAIL_PASS}
localhost:25 ${MAIL_LOGIN}:${MAIL_PASS}
SASL_PASSWD
chmod 600 "$CONF_DIR/postfix/sasl/passwd"
ok "Plik haseł SASL zapisany"
# Aliases
cat > "$CONF_DIR/postfix/aliases" << ALIASES
# SecFerro mail aliases
postmaster: ${MAIL_LOGIN}
root: ${MAIL_LOGIN}
admin: ${MAIL_LOGIN}
mailer-daemon: ${MAIL_LOGIN}
ALIASES
# Skrypt wdrożeniowy Postfix
cat > "$SCRIPTS_DIR/deploy_postfix.sh" << 'DEPLOY_POST'
#!/data/data/com.termux/files/usr/bin/bash
# Wdróż konfigurację Postfix (wymaga PREFIX=/data/data/com.termux/files/usr)
BASE="${HOME}/secferro"
CONF="${BASE}/config/postfix"
cp "$CONF/main.cf" "$PREFIX/etc/postfix/main.cf"
cp "$CONF/aliases" "$PREFIX/etc/postfix/aliases"
mkdir -p "$PREFIX/etc/postfix/sasl"
cp "$CONF/sasl/passwd" "$PREFIX/etc/postfix/sasl/passwd"
# Hashowanie pliku haseł
if command -v postmap &>/dev/null; then
postmap "$PREFIX/etc/postfix/sasl/passwd"
newaliases 2>/dev/null || true
echo "[✓] Postfix skonfigurowany"
postfix check && echo "[✓] Konfiguracja poprawna"
else
echo "[!] postmap niedostępny – Postfix może nie być zainstalowany"
fi
DEPLOY_POST
chmod +x "$SCRIPTS_DIR/deploy_postfix.sh"
ok "Konfiguracja serwera SMTP (Postfix) gotowa"
}
# ─────────────────────────────────────────────────────────────
# KROK 4 · Konfiguracja klienta pocztowego (msmtp)
# ─────────────────────────────────────────────────────────────
setup_mail_client() {
section "KROK 4 · Klient SMTP (msmtp)"
MAIL_PASS=$(get_secret "mail_password")
mkdir -p "$CONF_DIR/msmtp"
cat > "$CONF_DIR/msmtp/msmtprc" << MSMTP_CONF
# ── SecFerro · msmtp konfiguracja ───────────────────────────
# Domyślne wartości dla wszystkich kont
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ${LOG_DIR}/msmtp.log
syslog off
# Konto lokalne – połączenie z emulatorem RouterOS
account secferro-local
host ${EMU_IP}
port 25
from ${MAIL_LOGIN}
user ${MAIL_LOGIN}
password ${MAIL_PASS}
tls off
tls_starttls off
auth login
# Konto loopback
account secferro-lo
host 127.0.0.1
port 25
from ${MAIL_LOGIN}
user ${MAIL_LOGIN}
password ${MAIL_PASS}
tls off
tls_starttls off
auth login
# Konto domyślne
account default : secferro-local
MSMTP_CONF
chmod 600 "$CONF_DIR/msmtp/msmtprc"
# Skrypt wdrożeniowy msmtp
cat > "$SCRIPTS_DIR/deploy_msmtp.sh" << DEPLOY_MSMTP
#!/data/data/com.termux/files/usr/bin/bash
BASE="\${HOME}/secferro"
CONF="\${BASE}/config/msmtp"
# Wdroż globalnie
cp "\${CONF}/msmtprc" "\${HOME}/.msmtprc"
chmod 600 "\${HOME}/.msmtprc"
# Ustaw jako sendmail alias jeśli możliwe
if [ -d "\${PREFIX}/lib/sendmail" ] 2>/dev/null || true; then
echo "[✓] msmtp skonfigurowany jako klient SMTP"
fi
# Test konfiguracji
if command -v msmtp &>/dev/null; then
msmtp --serverinfo --account=secferro-local 2>&1 | head -5 || true
fi
echo "[✓] Klient SMTP (msmtp) wdrożony"
DEPLOY_MSMTP
chmod +x "$SCRIPTS_DIR/deploy_msmtp.sh"
ok "Konfiguracja klienta SMTP (msmtp) gotowa"
}
# ─────────────────────────────────────────────────────────────
# KROK 5 · Pobieranie obrazu RouterOS CHR
# ─────────────────────────────────────────────────────────────
download_routeros() {
section "KROK 5 · Pobieranie RouterOS CHR ${ROS_VERSION}"
mkdir -p "$VM_DIR"
local img_zip="$VM_DIR/chr-${ROS_VERSION}.img.zip"
local img_raw="$VM_DIR/chr-${ROS_VERSION}.img"
local img_qcow="$VM_DIR/routeros.qcow2"
if [[ -f "$img_qcow" ]]; then
ok "Obraz qcow2 już istnieje – pomijam pobieranie"
return 0
fi
step "Pobieranie RouterOS CHR ${ROS_VERSION}"
info "URL: ${ROS_IMAGE_URL}"
if wget -c --progress=bar:force \
--timeout=120 \
-O "$img_zip" \
"$ROS_IMAGE_URL" 2>&1 | tail -5; then
ok "Pobrano obraz"
else
fail "Błąd pobierania! Sprawdź URL lub połączenie."
info "URL: $ROS_IMAGE_URL"
exit 1
fi
step "Rozpakowywanie archiwum ZIP"
progress "unzip" unzip -o "$img_zip" -d "$VM_DIR"
step "Konwersja RAW → QCOW2"
if command -v qemu-img &>/dev/null; then
progress "qemu-img convert" \
qemu-img convert -f raw -O qcow2 "$img_raw" "$img_qcow"
qemu-img resize "$img_qcow" 512M >> "$LOGFILE" 2>&1 || true
ok "Obraz QCOW2 gotowy: $(du -sh "$img_qcow" | cut -f1)"
else
fail "qemu-img niedostępny"
exit 1
fi
# Sprzątanie
rm -f "$img_zip" "$img_raw"
ok "Obraz RouterOS przygotowany"
}
# ─────────────────────────────────────────────────────────────
# KROK 6 · Konfiguracja RouterOS (skrypt RSC)
# ─────────────────────────────────────────────────────────────
generate_ros_config() {
section "KROK 6 · Konfiguracja RouterOS"
MAIL_PASS=$(get_secret "mail_password")
ROS_PASS=$(get_secret "ros_password")
mkdir -p "$CONF_DIR/routeros"
cat > "$CONF_DIR/routeros/init.rsc" << RSC_CONF
# ============================================================
# SecFerro · RouterOS Initial Configuration
# Host: ${EMU_HOSTNAME} (${EMU_IP})
# Generated: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
# ============================================================
# Identyfikacja systemu
/system identity
set name="${EMU_HOSTNAME}"
# Hasło administratora (wygenerowane losowo)
/user set [find name=admin] password="${ROS_PASS}"
# ── Interfejsy ───────────────────────────────────────────────
/interface ethernet
set [find] auto-negotiation=yes
/interface wireless
set [ find ] band=2ghz-b/g/n \\
channel-width=20mhz \\
frequency=2472 \\
mode=ap-bridge \\
ssid="${MAIL_DOMAIN}_AP" \\
wireless-protocol=802.11 \\
disabled=no
# ── Bridge ───────────────────────────────────────────────────
/interface bridge
add name=bridge-local \\
admin-mac=${ROS_MAC} \\
auto-mac=no \\
comment="SecFerro main bridge"
/interface bridge port
add bridge=bridge-local interface=ether1
# ── Adresacja IP ─────────────────────────────────────────────
/ip address
add address=${EMU_IP}/24 interface=ether1 comment="Management"
add address=${EMU_LO}/8 interface=lo comment="Loopback"
# ── DNS ──────────────────────────────────────────────────────
/ip dns
set servers=1.1.1.1,8.8.8.8 \\
allow-remote-requests=no
# ── Konfiguracja e-mail (SMTP) ───────────────────────────────
/tool e-mail
set address=${EMU_LO} \\
from=${MAIL_LOGIN} \\
password=${MAIL_PASS} \\
port=25 \\
user=${MAIL_LOGIN} \\
tls=no
# ── Firewall (hardened) ──────────────────────────────────────
/ip firewall filter
# INPUT chain
add chain=input action=accept \\
connection-state=established,related \\
comment="Accept established"
add chain=input action=drop \\
connection-state=invalid \\
comment="Drop invalid"
add chain=input action=accept \\
protocol=icmp \\
comment="Accept ICMP"
add chain=input action=accept \\
src-address=192.168.168.0/24 \\
dst-port=22 protocol=tcp \\
comment="SSH from management"
add chain=input action=accept \\
src-address=192.168.168.0/24 \\
dst-port=8291 protocol=tcp \\
comment="Winbox from management"
add chain=input action=accept \\
dst-port=25 protocol=tcp \\
comment="SMTP"
add chain=input action=drop \\
comment="Drop all other INPUT"
# FORWARD chain
add chain=forward action=accept \\
connection-state=established,related \\
comment="Accept established forward"
add chain=forward action=drop \\
connection-state=invalid \\
comment="Drop invalid forward"
# ── Usługi (hardened) ────────────────────────────────────────
/ip service
disable [find name~"telnet|ftp|www|api|api-ssl"]
set ssh address=192.168.168.0/24 port=22
set winbox address=192.168.168.0/24 port=8291
# ── NTP ──────────────────────────────────────────────────────
/system ntp client
set enabled=yes primary-ntp=216.239.35.0
# ── Scheduler: cotygodniowy backup ───────────────────────────
/system scheduler
add interval=1w \\
name=weekly-backup \\
on-event="/system backup save name=secferro_weekly" \\
start-date=jan/01/2024 \\
start-time=04:00:00 \\
comment="Auto backup"
# ── Scheduler: powiadomienie e-mail ──────────────────────────
/system scheduler
add interval=1d \\
name=daily-health-mail \\
on-event="/tool e-mail send to=${MAIL_LOGIN} subject=(\$[/system identity get name].\\" health\\" ) body=(\\"RouterOS OK: \\".[\$:tostr [\$/system clock get time]])" \\
start-time=08:00:00 \\
comment="Daily health email"
# ── Logi ─────────────────────────────────────────────────────
/system logging
add topics=firewall action=memory
add topics=warning action=memory
add topics=error action=memory
# Wyślij potwierdzenie konfiguracji
/tool e-mail send \\
to="${MAIL_LOGIN}" \\
subject="[SecFerro] RouterOS configured - $(date +%Y-%m-%d)" \\
body="Konfiguracja RouterOS zakonczona pomyslnie.\\nHost: ${EMU_HOSTNAME}\\nIP: ${EMU_IP}"
RSC_CONF
ok "Skrypt RSC wygenerowany: $CONF_DIR/routeros/init.rsc"
}
# ─────────────────────────────────────────────────────────────
# KROK 7 · Skrypty uruchomieniowe
# ─────────────────────────────────────────────────────────────
create_runtime_scripts() {
section "KROK 7 · Skrypty runtime"
# ── Start VM ──────────────────────────────────────────────
cat > "$SCRIPTS_DIR/start_vm.sh" << STARTVM
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Start RouterOS VM ────────────────────────────
set -e
VM_DIR="\${HOME}/secferro/vm"
LOG_DIR="\${HOME}/secferro/logs"
PID_FILE="\${VM_DIR}/qemu.pid"
# Sprawdź czy VM już działa
if [[ -f "\$PID_FILE" ]] && kill -0 "\$(cat "\$PID_FILE")" 2>/dev/null; then
echo "[!] VM już działa (PID: \$(cat "\$PID_FILE"))"
exit 0
fi
echo "[→] Uruchamianie RouterOS VM..."
echo "[i] Host: ${EMU_HOSTNAME} | IP: ${EMU_IP}"
echo "[i] Pamięć: ${ROS_MEMORY}MB | CPU: ${ROS_CPUS} vCPU"
qemu-system-x86_64 \\
-name "${EMU_HOSTNAME}" \\
-m ${ROS_MEMORY} \\
-smp ${ROS_CPUS} \\
-nographic \\
-serial mon:stdio \\
-drive file="\${VM_DIR}/routeros.qcow2",format=qcow2,if=ide,cache=writeback \\
-netdev user,id=net0,net=${EMU_IP}/24,host=192.168.168.1,hostfwd=tcp::2222-:22,hostfwd=tcp::8291-:8291,hostfwd=tcp::2525-:25 \\
-device e1000,netdev=net0,mac=${ROS_MAC} \\
-cpu qemu64 \\
-machine type=q35 \\
-rtc base=utc \\
-boot c \\
-daemonize \\
-pidfile "\$PID_FILE" \\
-D "\${LOG_DIR}/qemu.log"
sleep 2
if [[ -f "\$PID_FILE" ]] && kill -0 "\$(cat "\$PID_FILE")" 2>/dev/null; then
echo "[✓] VM uruchomiona (PID: \$(cat "\$PID_FILE"))"
echo "[i] SSH: ssh -p 2222 admin@127.0.0.1"
echo "[i] SMTP: 127.0.0.1:2525"
echo "[i] Winbox: 127.0.0.1:8291"
else
echo "[✗] Błąd uruchamiania VM. Sprawdź: \${LOG_DIR}/qemu.log"
exit 1
fi
STARTVM
chmod +x "$SCRIPTS_DIR/start_vm.sh"
# ── Stop VM ───────────────────────────────────────────────
cat > "$SCRIPTS_DIR/stop_vm.sh" << 'STOPVM'
#!/data/data/com.termux/files/usr/bin/bash
PID_FILE="${HOME}/secferro/vm/qemu.pid"
if [[ -f "$PID_FILE" ]]; then
PID=$(cat "$PID_FILE")
kill "$PID" 2>/dev/null && echo "[✓] VM zatrzymana (PID: $PID)" || echo "[!] VM nie działa"
rm -f "$PID_FILE"
else
echo "[!] Brak pliku PID – VM nie jest uruchomiona"
fi
STOPVM
chmod +x "$SCRIPTS_DIR/stop_vm.sh"
# ── Status ────────────────────────────────────────────────
cat > "$SCRIPTS_DIR/status.sh" << STATUS_SH
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Status Dashboard ─────────────────────────────
C='\033[0;36m' G='\033[0;32m' R='\033[0;31m' Y='\033[1;33m' NC='\033[0m'
echo -e "\${C}╔══════════════════════════════════════════╗\${NC}"
echo -e "\${C}║ SecFerro · Status Dashboard ║\${NC}"
echo -e "\${C}╚══════════════════════════════════════════╝\${NC}"
echo ""
# VM Status
PID_FILE="\${HOME}/secferro/vm/qemu.pid"
if [[ -f "\$PID_FILE" ]] && kill -0 "\$(cat "\$PID_FILE")" 2>/dev/null; then
echo -e " RouterOS VM: \${G}● RUNNING\${NC} (PID: \$(cat "\$PID_FILE"))"
else
echo -e " RouterOS VM: \${R}● STOPPED\${NC}"
fi
# Postfix
if pgrep -x postfix &>/dev/null; then
echo -e " Postfix SMTP: \${G}● RUNNING\${NC}"
else
echo -e " Postfix SMTP: \${Y}● NOT RUNNING\${NC}"
fi
echo ""
echo -e " \${C}Porty (localhost): \${NC}"
for PORT_DESC in "2222:SSH (VM forward)" "2525:SMTP (VM forward)" "8291:Winbox" "25:Postfix"; do
PORT=\${PORT_DESC%%:*}; DESC=\${PORT_DESC#*:}
nc -z 127.0.0.1 "\$PORT" 2>/dev/null \\
&& echo -e " \${G}●\${NC} \${PORT} – \${DESC}" \\
|| echo -e " \${R}○\${NC} \${PORT} – \${DESC} [zamknięty]"
done
echo ""
echo -e " \${C}Zasoby:\${NC}"
echo -e " RAM free: \$(free -m | awk '/Mem/{print \$4}') MB"
echo -e " Disk free: \$(df -m ~ | tail -1 | awk '{print \$4}') MB"
echo ""
echo -e " \${C}Logi:\${NC}"
echo -e " Główny: ~/secferro/logs/"
echo -e " QEMU: ~/secferro/logs/qemu.log"
echo -e " msmtp: ~/secferro/logs/msmtp.log"
STATUS_SH
chmod +x "$SCRIPTS_DIR/status.sh"
# ── Test poczty ───────────────────────────────────────────
cat > "$SCRIPTS_DIR/test_mail.sh" << MAILTEST
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Test wysyłki e-mail ──────────────────────────
MAIL_LOGIN="${MAIL_LOGIN}"
LOG_DIR="\${HOME}/secferro/logs"
CONF="\${HOME}/.msmtprc"
SUBJECT="[SecFerro] Test mail \$(date +%Y-%m-%d_%H:%M)"
BODY="Test wiadomosci z SecFerro Lab
Host: ${TERMUX_HOSTNAME}
VM: ${EMU_HOSTNAME} (${EMU_IP})
Czas: \$(date)"
echo "Wysyłanie testu do: \${MAIL_LOGIN}..."
if command -v msmtp &>/dev/null && [[ -f "\$CONF" ]]; then
printf "To: %s\nFrom: %s\nSubject: %s\n\n%s\n" \\
"\$MAIL_LOGIN" "\$MAIL_LOGIN" "\$SUBJECT" "\$BODY" | \\
msmtp --file="\$CONF" "\$MAIL_LOGIN" && \\
echo "[✓] Wiadomość wysłana" || echo "[✗] Błąd wysyłki – sprawdź \${LOG_DIR}/msmtp.log"
else
echo "[!] msmtp lub .msmtprc niedostępny"
echo "[i] Uruchom: ~/secferro/scripts/deploy_msmtp.sh"
fi
MAILTEST
chmod +x "$SCRIPTS_DIR/test_mail.sh"
# ── Security test ─────────────────────────────────────────
cat > "$SCRIPTS_DIR/security_test.sh" << 'SECTEST'
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Security Audit ────────────────────────────────
G='\033[0;32m' R='\033[0;31m' Y='\033[1;33m' NC='\033[0m'
TARGET="127.0.0.1"
echo "════════════════════════════════════════"
echo " SecFerro · Security Test Suite"
echo "════════════════════════════════════════"
echo ""
port_check() {
local port=$1 name=$2 expected=$3
nc -z -w2 "$TARGET" "$port" 2>/dev/null
local open=$?
if [[ "$expected" == "open" && $open -eq 0 ]]; then
echo -e " ${G}[✓]${NC} Port $port ($name) – OPEN [oczekiwane]"
elif [[ "$expected" == "closed" && $open -ne 0 ]]; then
echo -e " ${G}[✓]${NC} Port $port ($name) – CLOSED [oczekiwane]"
elif [[ "$expected" == "open" && $open -ne 0 ]]; then
echo -e " ${Y}[!]${NC} Port $port ($name) – CLOSED [oczekiwany open]"
else
echo -e " ${R}[✗]${NC} Port $port ($name) – OPEN [powinien być zamknięty!]"
fi
}
echo "=== Porty zarządzania ==="
port_check 2222 "SSH (forward VM)" open
port_check 8291 "Winbox (forward VM)" open
echo ""
echo "=== Usługi pocztowe ==="
port_check 25 "SMTP (Postfix)" open
port_check 2525 "SMTP (VM forward)" open
echo ""
echo "=== Usługi NIE powinny być otwarte ==="
port_check 21 "FTP" closed
port_check 23 "Telnet" closed
port_check 80 "HTTP" closed
port_check 443 "HTTPS" closed
port_check 8728 "RouterOS API" closed
port_check 8729 "RouterOS API-SSL" closed
echo ""
echo "=== CVE Check (Winbox CVE-2018-14847) ==="
echo " [i] Test wymaga połączenia z VM na porcie 8291"
if nc -z -w2 "$TARGET" 8291 2>/dev/null; then
echo " [i] Winbox port dostępny – upewnij się że ROS >= 6.40.3"
else
echo " [i] Winbox port zamknięty (VM może nie działać)"
fi
echo ""
echo "════════════════════════════════════════"
SECTEST
chmod +x "$SCRIPTS_DIR/security_test.sh"
# ── Backup ────────────────────────────────────────────────
cat > "$SCRIPTS_DIR/backup.sh" << BACKUP_SH
#!/data/data/com.termux/files/usr/bin/bash
# ── SecFerro · Backup ────────────────────────────────────────
BACKUP_DIR="\${HOME}/secferro/backups"
TIMESTAMP=\$(date +%Y%m%d_%H%M%S)
DEST="\${BACKUP_DIR}/backup_\${TIMESTAMP}"
mkdir -p "\$DEST"
echo "[→] Backup sekretów..."
cp -r "\${HOME}/secferro/.secrets" "\${DEST}/secrets" 2>/dev/null && echo "[✓] Sekrety" || echo "[!] Brak sekretów"
echo "[→] Backup konfiguracji..."
cp -r "\${HOME}/secferro/config" "\${DEST}/config" && echo "[✓] Konfiguracja"
echo "[→] Backup obrazu VM (może chwilę potrwać)..."
if [[ -f "\${HOME}/secferro/vm/routeros.qcow2" ]]; then
cp "\${HOME}/secferro/vm/routeros.qcow2" "\${DEST}/routeros_\${TIMESTAMP}.qcow2"
echo "[✓] Obraz VM: \$(du -sh "\${DEST}/routeros_\${TIMESTAMP}.qcow2" | cut -f1)"
fi
echo "[✓] Backup gotowy: \${DEST}"
ls -lh "\${DEST}"
BACKUP_SH
chmod +x "$SCRIPTS_DIR/backup.sh"
ok "Wszystkie skrypty runtime utworzone"
}
# ─────────────────────────────────────────────────────────────
# KROK 8 · Podsumowanie i zapis danych dostępowych
# ─────────────────────────────────────────────────────────────
finalize() {
section "KROK 8 · Finalizacja"
MAIL_PASS=$(get_secret "mail_password")
ROS_PASS=$(get_secret "ros_password")
WINBOX_PASS=$(get_secret "winbox_password")
API_TOKEN=$(get_secret "api_token")
# Wdróż konfiguracje
step "Wdrażanie Postfix..."
bash "$SCRIPTS_DIR/deploy_postfix.sh" >> "$LOGFILE" 2>&1 && ok "Postfix wdrożony" || warn "Postfix – sprawdź log"
step "Wdrażanie msmtp..."
bash "$SCRIPTS_DIR/deploy_msmtp.sh" >> "$LOGFILE" 2>&1 && ok "msmtp wdrożony" || warn "msmtp – sprawdź log"
# Plik z danymi dostępowymi (czytelny tylko przez właściciela)
local ACCESS_FILE="$BASE_DIR/ACCESS_CREDENTIALS.txt"
cat > "$ACCESS_FILE" << ACCESS
════════════════════════════════════════════════════════════
SecFerro Lab · Dane dostępowe
Wygenerowano: $(date)
════════════════════════════════════════════════════════════
ŚRODOWISKO TERMUX
─────────────────
Hostname: ${TERMUX_HOSTNAME}
EMULATOR RouterOS
─────────────────
Hostname: ${EMU_HOSTNAME}
IP: ${EMU_IP}
Loopback: ${EMU_LO}
MAC: ${ROS_MAC}
POCZTA (SMTP)
─────────────
Login: ${MAIL_LOGIN}
Hasło: ${MAIL_PASS}
Serwer SMTP: ${EMU_IP}:25
Serwer SMTP: ${EMU_LO}:25
Forward SSH: 127.0.0.1:2525
ROUTEROS
────────
User: admin
Hasło: ${ROS_PASS}
SSH: ssh -p 2222 admin@127.0.0.1
Winbox port: 127.0.0.1:8291
API TOKEN
─────────
Token: ${API_TOKEN}
LOKALIZACJA SEKRETÓW
────────────────────
Katalog: ${SECRETS_DIR}/
Prawa: 700 (katalog) / 600 (pliki)
SZYBKIE KOMENDY
───────────────
Start VM: ~/secferro/scripts/start_vm.sh
Stop VM: ~/secferro/scripts/stop_vm.sh
Status: ~/secferro/scripts/status.sh
Test mail: ~/secferro/scripts/test_mail.sh
Security: ~/secferro/scripts/security_test.sh
Backup: ~/secferro/scripts/backup.sh
════════════════════════════════════════════════════════════
UWAGA: Ten plik zawiera hasła! Chroń dostęp.
Lokalizacja: ${ACCESS_FILE}
════════════════════════════════════════════════════════════
ACCESS
chmod 600 "$ACCESS_FILE"
# Utwórz alias startowy
local ALIAS_LINE="alias secferro='bash ${SCRIPTS_DIR}/status.sh'"
if ! grep -q "secferro" "$HOME/.bashrc" 2>/dev/null; then
echo "$ALIAS_LINE" >> "$HOME/.bashrc"
echo "alias sfstart='bash ${SCRIPTS_DIR}/start_vm.sh'" >> "$HOME/.bashrc"
echo "alias sfstop='bash ${SCRIPTS_DIR}/stop_vm.sh'" >> "$HOME/.bashrc"
echo "alias sftest='bash ${SCRIPTS_DIR}/security_test.sh'" >> "$HOME/.bashrc"
fi
# Finalne podsumowanie
echo ""
echo -e "${G}${BOLD}╔══════════════════════════════════════════════════════════╗${NC}"
echo -e "${G}${BOLD}║ Instalacja zakończona pomyślnie! ║${NC}"
echo -e "${G}${BOLD}╚══════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e " ${INFO} Dane dostępowe: ${W}${ACCESS_FILE}${NC}"
echo -e " ${INFO} Log instalacji: ${W}${LOGFILE}${NC}"
echo -e " ${INFO} Sekrety: ${W}${SECRETS_DIR}/${NC}"
echo ""
echo -e " ${STEP} ${W}Następne kroki:${NC}"
echo -e " 1. ${C}source ~/.bashrc${NC} – załaduj aliasy"
echo -e " 2. ${C}sfstart${NC} – uruchom VM"
echo -e " 3. ${C}secferro${NC} – sprawdź status"
echo -e " 4. ${C}~/secferro/scripts/test_mail.sh${NC} – testuj pocztę"
echo ""
echo -e " ${WARN} Uruchom: ${C}cat ${ACCESS_FILE}${NC} aby zobaczyć hasła"
echo ""
}
# ─────────────────────────────────────────────────────────────
# GŁÓWNY FLOW INSTALACJI
# ─────────────────────────────────────────────────────────────
main() {
# Utwórz strukturę katalogów
mkdir -p "$BASE_DIR" "$LOG_DIR" "$CONF_DIR" "$SECRETS_DIR" \
"$VM_DIR" "$BACKUP_DIR" "$SCRIPTS_DIR"
chmod 700 "$SECRETS_DIR"
banner
echo -e " ${INFO} Instalator SecFerro v${VERSION}"
echo -e " ${INFO} Log: ${LOGFILE}"
echo ""
if ! confirm "Rozpocząć interaktywną instalację środowiska SecFerro?"; then
echo -e " ${WARN} Instalacja anulowana."
exit 0
fi
# Pytaj o kroki opcjonalne
echo ""
echo -e " ${STEP} ${W}Wybierz komponenty do instalacji:${NC}"
echo ""
DO_PKGS=true
DO_MAIL=true
DO_ROSVM=true
confirm " Zainstalować/zaktualizować pakiety systemowe?" || DO_PKGS=false
confirm " Skonfigurować serwer i klienta SMTP?" || DO_MAIL=false
confirm " Pobrać i skonfigurować emulator RouterOS?" || DO_ROSVM=false
echo ""
# Wykonaj kroki
diag_system
$DO_PKGS && install_packages
generate_secrets
$DO_MAIL && setup_mail_server
$DO_MAIL && setup_mail_client
$DO_ROSVM && download_routeros
$DO_ROSVM && generate_ros_config
create_runtime_scripts
finalize
}
# ── Entry point ──────────────────────────────────────────────
main "$@"
@anonymousik
Copy link
Copy Markdown
Author

SecFerro · RouterOS Lab Installer

@anonymousik
Copy link
Copy Markdown
Author

anonymousik commented Feb 27, 2026

❗Hotfix ❗**### COPY/PASTE CMD**
curl -fsSL https://gist.github.com/anonymousik/11c364db0b16568382b3dc9009ad37de/raw/665d112d1cb949c4a6e493cd0fb93872460ca1b1/hotfix_tmux.sh | bash

@anonymousik
Copy link
Copy Markdown
Author

❗Hotfix ❗**### COPY/PASTE CMD** curl -fsSL https://gist.github.com/anonymousik/11c364db0b16568382b3dc9009ad37de/raw/665d112d1cb949c4a6e493cd0fb93872460ca1b1/hotfix_tmux.sh | bash

RouterOS virtual machine starting correctly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment