From bbee2efaec065047b809ed02aedf056351486bd2 Mon Sep 17 00:00:00 2001 From: kimoi Date: Fri, 6 Nov 2026 16:39:10 +0500 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=201:?= =?UTF-8?q?=20=D1=81=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D1=8B=20=D0=BD=D0=B0?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B8=20=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- check/zadanie1/br-fw.sh | 91 ++++++++++++++ check/zadanie1/br-rtr.sh | 117 ++++++++++++++++++ check/zadanie1/br-srv.sh | 87 ++++++++++++++ check/zadanie1/hq-cli.sh | 80 ++++++++++++ check/zadanie1/hq-rtr.sh | 141 ++++++++++++++++++++++ check/zadanie1/hq-srv.sh | 129 ++++++++++++++++++++ check/zadanie1/isp.sh | 113 +++++++++++++++++ tools/subnet-calc.sh | 110 +++++++++++++++++ zadanie1/br-fw.sh | 162 +++++++++++++++++++++++++ zadanie1/br-rtr.sh | 217 +++++++++++++++++++++++++++++++++ zadanie1/br-srv.sh | 131 ++++++++++++++++++++ zadanie1/hq-cli.sh | 73 +++++++++++ zadanie1/hq-rtr.sh | 254 +++++++++++++++++++++++++++++++++++++++ zadanie1/hq-srv.sh | 186 ++++++++++++++++++++++++++++ zadanie1/hq-sw.sh | 132 ++++++++++++++++++++ zadanie1/isp.sh | 182 ++++++++++++++++++++++++++++ 16 files changed, 2205 insertions(+) create mode 100644 check/zadanie1/br-fw.sh create mode 100644 check/zadanie1/br-rtr.sh create mode 100644 check/zadanie1/br-srv.sh create mode 100644 check/zadanie1/hq-cli.sh create mode 100644 check/zadanie1/hq-rtr.sh create mode 100644 check/zadanie1/hq-srv.sh create mode 100644 check/zadanie1/isp.sh create mode 100644 tools/subnet-calc.sh create mode 100644 zadanie1/br-fw.sh create mode 100644 zadanie1/br-rtr.sh create mode 100644 zadanie1/br-srv.sh create mode 100644 zadanie1/hq-cli.sh create mode 100644 zadanie1/hq-rtr.sh create mode 100644 zadanie1/hq-srv.sh create mode 100644 zadanie1/hq-sw.sh create mode 100644 zadanie1/isp.sh diff --git a/check/zadanie1/br-fw.sh b/check/zadanie1/br-fw.sh new file mode 100644 index 0000000..b8f0492 --- /dev/null +++ b/check/zadanie1/br-fw.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — BR-FW (только читает состояние!) +# Пункты vtysh требуют root — иначе ПРОПУЩЕНО. +# Работает только если BR-FW — Linux (см. MANUAL.md про BR-FW). +# ============================================================ + +NAME="br-fw" +LOG="check_${NAME}_z1.txt" + +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="br-fw.au-team.irpo" # таблица 3 + +BR_RTR_IF="" # интерфейс к BR-RTR +BR_RTR_ADDR="" # адрес BR-FW в сети /30, адрес/префикс +BR_RTR_GW="" # адрес BR-RTR — маршрут по умолчанию +BR_SRV_IF="" # интерфейс к BR-SRV +BR_SRV_ADDR="" # адрес BR-FW в сети BR-SRV, адрес/префикс +BR_SRV_PING="" # адрес BR-SRV для проверки связи + +EXAM_TZ="" + +main () { +echo "=== Проверка задания 1: BR-FW ===" + +# --- 1. Имя хоста --- +check_var "имя хоста" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. Адреса интерфейсов --- +check_var "адрес линка к BR-RTR" BR_RTR_ADDR && + if grep -qF -- "$BR_RTR_ADDR" <(ip -4 -o addr show "$BR_RTR_IF" 2>/dev/null); then + ok "адрес на $BR_RTR_IF = $BR_RTR_ADDR" + else fail "адрес линка к BR-RTR" "на $BR_RTR_IF нет $BR_RTR_ADDR"; fi +check_var "адрес в сети BR-SRV" BR_SRV_ADDR && + if grep -qF -- "$BR_SRV_ADDR" <(ip -4 -o addr show "$BR_SRV_IF" 2>/dev/null); then + ok "адрес на $BR_SRV_IF = $BR_SRV_ADDR" + else fail "адрес в сети BR-SRV" "на $BR_SRV_IF нет $BR_SRV_ADDR"; fi + +# --- 3. Шлюз по умолчанию через BR-RTR --- +check_var "шлюз по умолчанию" BR_RTR_GW && + if ip route show default 2>/dev/null | grep -qF "$BR_RTR_GW"; then + ok "маршрут по умолчанию через $BR_RTR_GW" + else fail "маршрут по умолчанию" "ожидался via $BR_RTR_GW, получено: $(ip route show default)"; fi + +# --- 4. OSPF-сосед BR-RTR (только по линку к BR-RTR) --- +if root_or_skip "OSPF (vtysh)"; then + if ! command -v vtysh &>/dev/null; then + skip "OSPF — vtysh не найден (ПРОВЕРИТЬ OSPF-демон на РЕД ОС 8 / что за система BR-FW)" + else + N_FULL=$(vtysh -c 'show ip ospf neighbor' 2>/dev/null | grep -c "Full") + if [[ $N_FULL -ge 1 ]]; then ok "OSPF сосед BR-RTR в FULL" + else fail "OSPF сосед" "нет соседа в Full: $(vtysh -c 'show ip ospf neighbor' 2>&1)"; fi + fi +fi + +# --- 5. ip_forward --- +FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null) +if [[ "$FWD" == "1" ]]; then ok "ip_forward включён" +else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi + +# --- 6. Связь с BR-SRV --- +check_var "связь с BR-SRV" BR_SRV_PING && + if ping -c2 -W2 "$BR_SRV_PING" &>/dev/null; then ok "ping BR-SRV ($BR_SRV_PING)" + else fail "ping BR-SRV ($BR_SRV_PING)" "недоступен"; fi + +# --- 7. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную ===" +echo " — выход в Интернет из BR-SRV: ping 77.88.8.7 с BR-SRV" +echo " — таблицу 2 (адрес BR-FW, его шлюз) в отчёте" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/check/zadanie1/br-rtr.sh b/check/zadanie1/br-rtr.sh new file mode 100644 index 0000000..6f06eaf --- /dev/null +++ b/check/zadanie1/br-rtr.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — BR-RTR (только читает состояние!) +# Пункты vtysh/iptables требуют root — иначе ПРОПУЩЕНО. +# ============================================================ + +NAME="br-rtr" +LOG="check_${NAME}_z1.txt" + +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="br-rtr.au-team.irpo" # таблица 3 +NET_ADMIN_USER="net_admin" + +ISP_IF="" # интерфейс к ISP +BR_LINK_IF="" # интерфейс к BR-FW (сеть /30) +BR_LINK_ADDR="" # адрес BR-RTR на этом линке, адрес/префикс + +GRE_IF="gre1" +GRE_LOCAL="" # локальный конец туннеля +GRE_REMOTE="" # адрес HQ-RTR в сети ISP (пингуем через туннель) + +OSPF_PASSWORD="P@ssw0rd" +EXAM_TZ="" + +main () { +echo "=== Проверка задания 1: BR-RTR ===" + +# --- 1. Имя хоста --- +check_var "имя хоста" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. Пользователь net_admin --- +check_var "пользователь net_admin" NET_ADMIN_USER && + if id "$NET_ADMIN_USER" &>/dev/null; then ok "пользователь $NET_ADMIN_USER существует" + else fail "пользователь $NET_ADMIN_USER" "нет такого пользователя"; fi +check_var "sudo для net_admin" NET_ADMIN_USER && + if root_or_skip "sudo для net_admin" ; then + if sudo -ln -U "$NET_ADMIN_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then + ok "net_admin — sudo без пароля (NOPASSWD: ALL)" + else fail "sudo для net_admin" "нет NOPASSWD: ALL"; fi + fi + +# --- 3. Адeline в сторону BR-FW (сеть /30) --- +check_var "адрес линка к BR-FW" BR_LINK_ADDR && + if grep -qF -- "$BR_LINK_ADDR" <(ip -4 -o addr show "$BR_LINK_IF" 2>/dev/null); then + ok "адрес на $BR_LINK_IF = $BR_LINK_ADDR" + else fail "адрес линка к BR-FW" "на $BR_LINK_IF нет $BR_LINK_ADDR"; fi + +# --- 4. GRE-туннель --- +check_var "адрес туннеля" GRE_LOCAL && + if grep -qF -- "$GRE_LOCAL" <(ip -4 -o addr show "$GRE_IF" 2>/dev/null); then + ok "туннель $GRE_IF поднят с $GRE_LOCAL" + else fail "туннель $GRE_IF" "не нашёлся адрес $GRE_LOCAL"; fi + +# --- 5. OSPF: два соседа (HQ-RTR через туннель, BR-FW через линк) --- +if root_or_skip "OSPF (vtysh)"; then + if ! command -v vtysh &>/dev/null; then + skip "OSPF — vtysh не найден (ПРОВЕРИТЬ OSPF-демон на РЕД ОС 8)" + else + N_FULL=$(vtysh -c 'show ip ospf neighbor' 2>/dev/null | grep -c "Full") + if [[ $N_FULL -ge 2 ]]; then ok "OSPF соседи в FULL: $N_FULL" + else fail "OSPF соседи" "ожидалось 2 (HQ-RTR и BR-FW), найдено $N_FULL: $(vtysh -c 'show ip ospf neighbor' 2>&1)"; fi + if vtysh -c 'show running-config' 2>/dev/null \ + | grep -i "message-digest-key" | grep -qiF "$OSPF_PASSWORD"; then + ok "OSPF MD5-аутентификация с паролем" + else fail "OSPF MD5" "ключ/пароль не найдены в конфиге"; fi + if vtysh -c 'show ip route ospf' 2>/dev/null | grep -q "O "; then + ok "маршруты OSPF присутствуют" + else fail "маршруты OSPF" "нет маршрутов от OSPF"; fi + fi +fi + +# --- 6. NAT и маршрут по умолчанию --- +check_var "интерфейс ISP" ISP_IF && + { if root_or_skip "NAT"; then + COUNT=$(iptables -t nat -S POSTROUTING 2>/dev/null | grep -cF "$ISP_IF") + if [[ $COUNT -ge 1 ]]; then ok "NAT MASQUERADE на $ISP_IF ($COUNT правил)" + else fail "NAT" "нет MASQUERADE на $ISP_IF"; fi + fi + if ip route show default 2>/dev/null | grep -qF "$ISP_IF"; then + ok "маршрут по умолчанию через $ISP_IF" + else fail "маршрут по умолчанию" "через $ISP_IF нет"; fi; } + +# --- 7. Связь через туннель --- +check_var "связь через туннель" GRE_REMOTE && + if ping -c2 -W2 "$GRE_REMOTE" &>/dev/null; then ok "ping HQ-RTR через туннель ($GRE_REMOTE)" + else fail "ping HQ-RTR ($GRE_REMOTE)" "недоступен"; fi + +# --- 8. ip_forward --- +FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null) +if [[ "$FWD" == "1" ]]; then ok "ip_forward включён" +else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi + +# --- 9. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную ===" +echo " — связь офис-к-офису: с HQ-SRV ping <адрес BR-SRV> и наоборот (сквозная маршрутизация)" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/check/zadanie1/br-srv.sh b/check/zadanie1/br-srv.sh new file mode 100644 index 0000000..5c2ad3a --- /dev/null +++ b/check/zadanie1/br-srv.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — BR-SRV (только читает состояние!) +# Пункты sshd -T и sudo требуют root. +# ============================================================ + +NAME="br-srv" +LOG="check_${NAME}_z1.txt" + +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="br-srv.au-team.irpo" # таблица 3 + +SRV_IF="" # интерфейс к BR-SRV +SRV_ADDR="" # адрес BR-SRV, адрес/префикс +SRV_GW="" # шлюз (адрес BR-FW) + +SSH_PORT="2027" +SSH_USER="sshuser" +SSH_USER_UID="2027" +SSH_BANNER_TEXT="Authorized access only" +EXAM_TZ="" + +main () { +echo "=== Проверка задания 1: BR-SRV ===" + +# --- 1. Имя хоста --- +check_var "имя хоста" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. Сеть --- +check_var "адрес" SRV_ADDR && + if grep -qF -- "$SRV_ADDR" <(ip -4 -o addr show "$SRV_IF" 2>/dev/null); then + ok "адрес = $SRV_ADDR" + else fail "адрес" "не нашёлся $SRV_ADDR"; fi +check_var "шлюз" SRV_GW && + expect_eq "шлюз по умолчанию" "$SRV_GW" "$(ip route show default 2>/dev/null | awk '{print $3}')" + +# --- 3. Пользователь sshuser --- +check_var "пользователь sshuser" SSH_USER && + if id "$SSH_USER" &>/dev/null; then + expect_eq "UID $SSH_USER" "$SSH_USER_UID" "$(id -u "$SSH_USER")" + else fail "пользователь $SSH_USER" "нет такого пользователя"; fi +check_var "sudo для sshuser" SSH_USER && + if root_or_skip "sudo для sshuser"; then + if sudo -ln -U "$SSH_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then + ok "sshuser — sudo без пароля" + else fail "sudo для sshuser" "нет NOPASSWD: ALL"; fi + fi + +# --- 4. SSH: порт 2027, только sshuser, 2 попытки, баннер --- +if root_or_skip "sshd -T"; then + T=$(sshd -T 2>/dev/null) + expect_eq "SSH порт" "$SSH_PORT" "$(grep -E "^port " <<<"$T" | awk '{print $2}')" + if grep -E "^allowusers " <<<"$T" | grep -qw "$SSH_USER"; then + ok "SSH AllowUsers = $SSH_USER" + else fail "SSH AllowUsers" "$(grep -E '^allowusers' <<<"$T")"; fi + expect_eq "SSH MaxAuthTries" "2" "$(grep -E "^maxauthtries " <<<"$T" | awk '{print $2}')" + got_banner=$(grep -E "^banner " <<<"$T" | awk '{print $2}') + if [[ -n "$got_banner" ]] && grep -qF "$SSH_BANNER_TEXT" "$got_banner" 2>/dev/null; then + ok "SSH баннер '$SSH_BANNER_TEXT'" + else fail "SSH баннер" "banner=$got_banner"; fi +fi + +# --- 5. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную ===" +echo " — ssh -p 2027 sshuser@<адрес BR-SRV> с другой машины" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/check/zadanie1/hq-cli.sh b/check/zadanie1/hq-cli.sh new file mode 100644 index 0000000..66873ba --- /dev/null +++ b/check/zadanie1/hq-cli.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — HQ-CLI (только читает состояние!) +# Клиент получает адрес по DHCP от HQ-RTR (VLAN 200): проверяем +# что адрес есть, шлюз и DNS правильные, суффикс домена — в resolv. +# ============================================================ + +NAME="hq-cli" +LOG="check_${NAME}_z1.txt" + +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="hq-cli.au-team.irpo" # таблица 3 + +CLI_IF="" # интерфейс, подключённый к VLAN 200 +HQ_RTR_ADDR="" # адрес HQ-RTR в VLAN 200 (ожидаемый шлюз) +HQ_SRV_ADDR="" # адрес HQ-SRV (ожидаемый DNS) +DNS_DOMAIN="au-team.irpo" # суффикс по заданию +EXAM_TZ="" + +main () { +echo "=== Проверка задания 1: HQ-CLI ===" + +# --- 1. Имя хоста --- +check_var "имя хоста" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. Адрес по DHCP --- +if [[ -n "$CLI_IF" ]]; then + METHOD=$(nmcli -g ipv4.method con show "$CLI_IF" 2>/dev/null) + expect_eq "IPv4 ($CLI_IF) по DHCP" "auto" "$METHOD" + IP4=$(ip -4 -o addr show dev "$CLI_IF" 2>/dev/null | awk '{print $4}') + if [[ -n "$IP4" ]]; then ok "адрес получен по DHCP: $IP4" + else fail "адрес по DHCP" "адреса на $CLI_IF нет (DHCP-сервер на HQ-RTR работает?)"; fi + # DHCP-лизинг фактически выдан NetworkManager + if root_or_skip "файл DHCP-лизинга"; then + LEASE=$(grep -rls "ip_address=" /var/lib/NetworkManager/*.lease 2>/dev/null | head -1) + if [[ -n "$LEASE" ]]; then ok "лизинг DHCP сохранён в $LEASE" + else fail "DHCP-лизинг" "файл лизинга не найден в /var/lib/NetworkManager"; fi + fi +else + skip "адрес по DHCP — не задано CLI_IF" +fi + +# --- 3. Шлюз и DNS из DHCP --- +check_var "шлюз = HQ-RTR" HQ_RTR_ADDR && + expect_eq "шлюз по умолчанию" "$HQ_RTR_ADDR" "$(ip route show default 2>/dev/null | awk '{print $3}')" +check_var "DNS = HQ-SRV" HQ_SRV_ADDR && + expect_eq "DNS-сервер в resolv.conf" "$HQ_SRV_ADDR" "$(grep -m1 nameserver /etc/resolv.conf | awk '{print $2}')" + +# --- 4. Суффикс домена в resolv.conf --- +check_var "суффикс домена" DNS_DOMAIN && + if grep -qE "(search|domain) .*$DNS_DOMAIN" /etc/resolv.conf 2>/dev/null; then + ok "суффикс $DNS_DOMAIN в resolv.conf" + else fail "суффикс домена" "нет $DNS_DOMAIN: $(cat /etc/resolv.conf 2>/dev/null)"; fi + +# --- 5. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную ===" +echo " — ping <адрес HQ-SRV> (маршрутизация VLAN 100/200)" +echo " — разрешение имён через новый DNS: dig hq-srv.$DNS_DOMAIN" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/check/zadanie1/hq-rtr.sh b/check/zadanie1/hq-rtr.sh new file mode 100644 index 0000000..95ada87 --- /dev/null +++ b/check/zadanie1/hq-rtr.sh @@ -0,0 +1,141 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — HQ-RTR (только читает состояние!) +# Пункты ssh/frr/iptables/DHCP требуют root — иначе ПРОПУЩЕНО. +# ============================================================ + +NAME="hq-rtr" +LOG="check_${NAME}_z1.txt" + +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="hq-rtr.au-team.irpo" # таблица 3 +NET_ADMIN_USER="net_admin" + +ISP_IF="" # интерфейс к ISP (для маршрута по умолчанию) +VLAN100_IF="vlan100" # имя vlan-подинтерфейса VLAN 100 +VLAN100_ADDR="" # адрес роутера в VLAN 100, адрес/префикс +VLAN200_IF="vlan200" +VLAN200_ADDR="" +VLAN999_IF="vlan999" +VLAN999_ADDR="" + +GRE_IF="gre1" # имя туннеля +GRE_LOCAL="" # локальный конец туннеля, адрес/префикс +GRE_REMOTE="" # адрес BR-RTR в сети ISP (пингуем через туннель) + +OSPF_PASSWORD="P@ssw0rd" # пароль OSPF по заданию +DHCP_PORT_CHECK="67" # порт DHCP-сервера (изменять не нужно) +EXAM_TZ="" + +main () { +echo "=== Проверка задания 1: HQ-RTR ===" + +# --- 1. Имя хоста --- +check_var "имя хоста" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. Пользователь net_admin --- +check_var "пользователь net_admin" NET_ADMIN_USER && + if id "$NET_ADMIN_USER" &>/dev/null; then ok "пользователь $NET_ADMIN_USER существует" + else fail "пользователь $NET_ADMIN_USER" "нет такого пользователя"; fi +check_var "sudo для net_admin" NET_ADMIN_USER && + if root_or_skip "sudo для net_admin"; then + if sudo -ln -U "$NET_ADMIN_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then + ok "net_admin — sudo без пароля (NOPASSWD: ALL)" + else fail "sudo для net_admin" "нет NOPASSWD: ALL: $(sudo -l -U "$NET_ADMIN_USER" 2>&1 | tail -3)"; fi + fi + +# --- 3. VLAN-подинтерфейсы на одном адаптере --- +check_var "адрес в VLAN 100" VLAN100_ADDR && + if grep -qF -- "$VLAN100_ADDR" <(ip -4 -o addr show "$VLAN100_IF" 2>/dev/null); then + ok "адрес VLAN 100 ($VLAN100_IF) = $VLAN100_ADDR" + else fail "адрес VLAN 100" "на $VLAN100_IF не нашёлся $VLAN100_ADDR"; fi +check_var "адрес в VLAN 200" VLAN200_ADDR && + if grep -qF -- "$VLAN200_ADDR" <(ip -4 -o addr show "$VLAN200_IF" 2>/dev/null); then + ok "адрес VLAN 200 ($VLAN200_IF) = $VLAN200_ADDR" + else fail "адрес VLAN 200" "на $VLAN200_IF не нашёлся $VLAN200_ADDR"; fi +check_var "адрес в VLAN 999" VLAN999_ADDR && + if grep -qF -- "$VLAN999_ADDR" <(ip -4 -o addr show "$VLAN999_IF" 2>/dev/null); then + ok "адрес VLAN 999 ($VLAN999_IF) = $VLAN999_ADDR" + else fail "адрес VLAN 999" "на $VLAN999_IF не нашёлся $VLAN999_ADDR"; fi + +# --- 4. GRE-туннель --- +check_var "адрес туннеля" GRE_LOCAL && + if grep -qF -- "$GRE_LOCAL" <(ip -4 -o addr show "$GRE_IF" 2>/dev/null); then + ok "туннель $GRE_IF поднят с $GRE_LOCAL" + else fail "туннель $GRE_IF" "не нашёлся адрес $GRE_LOCAL ($(ip -4 -o addr show "$GRE_IF" 2>/dev/null))"; fi + +# --- 5. OSPF: сосед через туннель и аутентификация MD5 --- +if root_or_skip "OSPF (vtysh)"; then + if ! command -v vtysh &>/dev/null; then + skip "OSPF сосед — vtysh не найден (ПРОВЕРИТЬ: пакет/имя OSPF-демона на РЕД ОС 8)" + else + NEIGH_STATE=$(vtysh -c 'show ip ospf neighbor' 2>/dev/null | grep -c "Full") + if [[ $NEIGH_STATE -ge 1 ]]; then ok "OSPF сосед в FULL (найдено $NEIGH_STATE)" + else fail "OSPF сосед" "нет соседа в Full: $(vtysh -c 'show ip ospf neighbor' 2>&1)"; fi + if vtysh -c 'show running-config' 2>/dev/null \ + | grep -i "message-digest-key" | grep -qiF "$OSPF_PASSWORD"; then + ok "OSPF MD5-аутентификация с паролем $OSPF_PASSWORD" + else fail "OSPF MD5" "ключ/пароль не найдены в ospf-конфиге"; fi + if vtysh -c 'show ip route ospf' 2>/dev/null | grep -q "O "; then + ok "маршруты OSPF присутствуют" + else fail "маршруты OSPF" "нет маршрутов от OSPF"; fi + fi +fi + +# --- 6. NAT на выход в сторону ISP --- +if [[ -n "$ISP_IF" ]]; then + if root_or_skip "NAT на ISP-интерфейс"; then + COUNT=$(iptables -t nat -S POSTROUTING 2>/dev/null | grep -cF "$ISP_IF") + if [[ $COUNT -ge 1 ]]; then ok "NAT правило MASQUERADE на $ISP_IF ($COUNT правил)" + else fail "NAT" "нет MASQUERADE на $ISP_IF"; fi + fi + if ip route show default 2>/dev/null | grep -qF "$ISP_IF"; then + ok "маршрут по умолчанию через $ISP_IF" + else fail "маршрут по умолчанию" "через $ISP_IF нет"; fi +else + skip "NAT/маршрут по умолчанию — не задано ISP_IF" +fi + +# --- 7. DHCP слушает на 67 --- +if root_or_skip "DHCP-сервер слушает порт $DHCP_PORT_CHECK"; then + if ss -ulnp 2>/dev/null | grep -q ":$DHCP_PORT_CHECK"; then + ok "DHCP слушает порт $DHCP_PORT_CHECK (udp)" + else fail "DHCP порт $DHCP_PORT_CHECK" "ничего не слушает udp/$DHCP_PORT_CHECK"; fi +fi + +# --- 8. Связь через туннель (адрес BR-RTR в сети ISP) --- +check_var "связь через туннель" GRE_REMOTE && + if ping -c2 -W2 "$GRE_REMOTE" &>/dev/null; then ok "ping BR-RTR ($GRE_REMOTE)" + else fail "ping BR-RTR ($GRE_REMOTE)" "недоступен (туннель/OSPF/NAT?)"; fi + +# --- 9. IP forwarding --- +FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null) +if [[ "$FWD" == "1" ]]; then ok "ip_forward включён" +else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi + +# --- 10. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную ===" +echo " — DHCP-лизинг на HQ-CLI (скрипт check/zadanie1/hq-cli.sh)" +echo " — vtysh -c 'show ip ospf interface' (протокол только на $GRE_IF?)" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/check/zadanie1/hq-srv.sh b/check/zadanie1/hq-srv.sh new file mode 100644 index 0000000..3111b87 --- /dev/null +++ b/check/zadanie1/hq-srv.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — HQ-SRV (только читает состояние!) +# Пункты sshd -T и sudo требуют root — иначе ПРОПУЩЕНО. +# Требует установленный dig (bind-utils): если его нет — DNS +# проверки получат [ПРОПУЩЕНО] с подсказкой. +# ============================================================ + +NAME="hq-srv" +LOG="check_${NAME}_z1.txt" + +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="hq-srv.au-team.irpo" # таблица 3 + +SRV_IF="" # интерфейс к VLAN 100 +SRV_ADDR="" # адрес HQ-SRV, адрес/префикс +SRV_GW="" # шлюз (адрес HQ-RTR в VLAN 100) + +SSH_PORT="2027" # по заданию 1 п. 5 +SSH_USER="sshuser" +SSH_USER_UID="2027" # по заданию 1 п. 3 +SSH_BANNER_TEXT="Authorized access only" + +# Адреса для DNS-записей (таблица 3) +HQ_RTR_IP="" BR_RTR_IP="" BR_FW_IP="" HQ_CLI_IP="" +BR_SRV_IP="" ISP_TO_HQ_IP="" ISP_TO_BR_IP="" + +EXAM_TZ="" + +main () { +echo "=== Проверка задания 1: HQ-SRV ===" + +# --- 1. Имя хоста --- +check_var "имя хоста" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. Сеть --- +check_var "адрес" SRV_ADDR && + if grep -qF -- "$SRV_ADDR" <(ip -4 -o addr show "$SRV_IF" 2>/dev/null); then + ok "адрес = $SRV_ADDR" + else fail "адрес" "не нашёлся $SRV_ADDR ($(ip -4 -o addr show 2>/dev/null | grep inet))"; fi +check_var "шлюз" SRV_GW && + expect_eq "шлюз по умолчанию" "$SRV_GW" "$(ip route show default 2>/dev/null | awk '{print $3}')" + +# --- 3. Пользователь sshuser (UID 2027) и sudo --- +check_var "пользователь sshuser" SSH_USER && + if id "$SSH_USER" &>/dev/null; then + got_uid=$(id -u "$SSH_USER") + expect_eq "UID $SSH_USER" "$SSH_USER_UID" "$got_uid" + else fail "пользователь $SSH_USER" "нет такого пользователя"; fi +check_var "sudo для sshuser" SSH_USER && + if root_or_skip "sudo для sshuser"; then + if sudo -ln -U "$SSH_USER" 2>/dev/null | grep -q "NOPASSWD: ALL"; then + ok "sshuser — sudo без пароля" + else fail "sudo для sshuser" "нет NOPASSWD: ALL"; fi + fi + +# --- 4. SSH: порт 2027, только sshuser, 2 попытки, баннер --- +if root_or_skip "sshd -T (эффективный конфиг)"; then + T=$(sshd -T 2>/dev/null) + if [[ -z "$T" ]]; then fail "sshd -T" "команда не отработала" + else + got_port=$(grep -E "^port " <<<"$T" | awk '{print $2}') + expect_eq "SSH порт" "$SSH_PORT" "$got_port" + if grep -E "^allowusers " <<<"$T" | grep -qw "$SSH_USER"; then + ok "SSH AllowUsers = $SSH_USER" + else fail "SSH AllowUsers" "$(grep -E '^allowusers' <<<"$T")"; fi + got_tries=$(grep -E "^maxauthtries " <<<"$T" | awk '{print $2}') + expect_eq "SSH MaxAuthTries" "2" "$got_tries" + got_banner=$(grep -E "^banner " <<<"$T" | awk '{print $2}') + if [[ -n "$got_banner" ]] && grep -qF "$SSH_BANNER_TEXT" "$got_banner" 2>/dev/null; then + ok "SSH баннер '$SSH_BANNER_TEXT'" + else fail "SSH баннер" "banner=$got_banner, текст не совпал"; fi + fi +fi + +# --- 5. DNS: A- и PTR-записи по таблице 3 --- +if ! command -v dig &>/dev/null; then + skip "DNS-проверки — dig не установлен (dnf install bind-utils)" +else + check_dns_a () { + local RECORD="$1" EXPECT="$2" + local GOT; GOT=$(dig +short "$RECORD" @127.0.0.1 2>/dev/null) + if [[ "$GOT" == "$EXPECT" ]]; then ok "DNS A: $RECORD -> $EXPECT" + else fail "DNS A: $RECORD" "ожидалось '$EXPECT', получено '$GOT'"; fi + } + check_var "DNS hq-rtr" HQ_RTR_IP && check_dns_a "hq-rtr.au-team.irpo" "$HQ_RTR_IP" + check_var "DNS br-rtr" BR_RTR_IP && check_dns_a "br-rtr.au-team.irpo" "$BR_RTR_IP" + check_var "DNS br-fw" BR_FW_IP && check_dns_a "br-fw.au-team.irpo" "$BR_FW_IP" + # PTR для HQ-SRV (адрес = наш собственный, из переменной SRV_ADDR) + check_var "PTR HQ-SRV" SRV_ADDR && + { GOT_PTR=$(dig +short -x "${SRV_ADDR%/*}" @127.0.0.1 2>/dev/null) + if grep -q "hq-srv.au-team.irpo" <<<"$GOT_PTR"; then ok "PTR: ${SRV_ADDR%/*} -> hq-srv.au-team.irpo" + else fail "PTR HQ-SRV" "ожидалось 'hq-srv.au-team.irpo', получено '$GOT_PTR'"; fi; } + check_var "DNS hq-cli" HQ_CLI_IP && check_dns_a "hq-cli.au-team.irpo" "$HQ_CLI_IP" + check_var "DNS br-srv" BR_SRV_IP && + { check_dns_a "br-srv.au-team.irpo" "$BR_SRV_IP" + GOT_PTR=$(dig +short -x "$BR_SRV_IP" @127.0.0.1 2>/dev/null) + if grep -q "br-srv.au-team.irpo" <<<"$GOT_PTR"; then ok "PTR: $BR_SRV_IP -> br-srv.au-team.irpo" + else fail "PTR BR-SRV" "ожидалось 'br-srv.au-team.irpo', получено '$GOT_PTR'"; fi; } + check_var "DNS docker" ISP_TO_HQ_IP && check_dns_a "docker.au-team.irpo" "$ISP_TO_HQ_IP" + check_var "DNS web" ISP_TO_BR_IP && check_dns_a "web.au-team.irpo" "$ISP_TO_BR_IP" +fi + +# --- 6. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную ===" +echo " — ssh -p 2027 sshuser@<адрес HQ-SRV> с другой машины (подключение работает)" +echo " — fork wong вход под другими пользователями по ssh запрещён (MaxAuthTries/AllowUsers)" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/check/zadanie1/isp.sh b/check/zadanie1/isp.sh new file mode 100644 index 0000000..396bd82 --- /dev/null +++ b/check/zadanie1/isp.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# ============================================================ +# ПРОВЕРКА ЗАДАНИЯ 1 — ISP (только читает состояние!) +# Ничего не настраивает и не перезапускает. +# Пункты с iptables требуют root — при запуске от обычного +# пользователя они получат [ПРОПУЩЕНО (нужен root)]. +# ============================================================ + +NAME="isp" +LOG="check_${NAME}_z1.txt" + +# ---------- счётчики и мини-функции вывода ---------- +OK=0; FAIL=0; SKIP=0 +ok() { echo "[OK] $1"; OK=$((OK+1)); } +fail() { echo "[FAIL] $1 — $2"; FAIL=$((FAIL+1)); } +skip() { echo "[ПРОПУЩЕНО] $1"; SKIP=$((SKIP+1)); } +# Для пунктов, где нужен root (iptables и т.п.) +root_or_skip() { if [[ $EUID -ne 0 ]]; then skip "$1 (нужен root)"; return 1; fi; return 0; } +# Для пунктов, где нужна какая-то переменная +check_var() { if [[ -z "${!2}" ]]; then skip "$1 — не задано $2"; return 1; fi; return 0; } +# Сравнение ожидание/факт +expect_eq() { if [[ "$3" == "$2" ]]; then ok "$1"; else fail "$1" "ожидалось '$2', получено '$3'"; fi; } + +# ================= ПЕРЕМЕННЫЕ (заполните для проверки) ================= +HOSTNAME_EXPECTED="" # полное имя ISP (в таблице 3 записи нет — как задали) +WAN_IF="" # WAN-интерфейс (пример: enp0s3) +HQ_IF="" # интерфейс к HQ-RTR +HQ_NET="" # адрес ISP на этом интерфейсе, адрес/префикс +BR_IF="" # интерфейс к BR-RTR +BR_NET="" # адрес ISP на этом интерфейсе, адрес/префикс +HQ_RTR_ADDR="" # адрес HQ-RTR на линке (для пинга) +BR_RTR_ADDR="" # адрес BR-RTR на линке (для пинга) +EXAM_TZ="" # ожидаемый часовой пояс (например Europe/Moscow) + +main () { +echo "=== Проверка задания 1: ISP ===" + +# --- 1. Имя хоста --- +check_var "имя хоста (FQDN)" HOSTNAME_EXPECTED && + expect_eq "имя хоста" "$HOSTNAME_EXPECTED" "$(hostname)" + +# --- 2. WAN получает адрес по DHCP (method=auto) --- +if [[ -n "$WAN_IF" ]]; then + METHOD=$(nmcli -g ipv4.method con show "$WAN_IF" 2>/dev/null) + expect_eq "IPv4 WAN ($WAN_IF) по DHCP" "auto" "$METHOD" + IP4=$(ip -4 -o addr show dev "$WAN_IF" 2>/dev/null | awk '{print $4}') + if [[ -n "$IP4" ]]; then ok "WAN получил адрес: $IP4" + else fail "WAN получил адрес" "адреса на $WAN_IF нет"; fi +else + skip "WAN DHCP — не задано WAN_IF" +fi + +# --- 3. Статические адреса на линках к роутерам --- +check_var "адрес на $HQ_IF (линк HQ)" HQ_NET && + if grep -qF -- "$HQ_NET" <(ip -4 -o addr show dev "$HQ_IF" 2>/dev/null); then + ok "адрес на $HQ_IF = $HQ_NET" + else fail "адрес на $HQ_IF" "не нашёлся $HQ_NET в: $(ip -4 -o addr show dev "$HQ_IF" 2>/dev/null)"; fi +check_var "адрес на $BR_IF (линк BR)" BR_NET && + if grep -qF -- "$BR_NET" <(ip -4 -o addr show dev "$BR_IF" 2>/dev/null); then + ok "адрес на $BR_IF = $BR_NET" + else fail "адрес на $BR_IF" "не нашёлся $BR_NET в: $(ip -4 -o addr show dev "$BR_IF" 2>/dev/null)"; fi + +# --- 4. Маршрут по умолчанию через WAN --- +check_var "маршрут по умолчанию к WAN" WAN_IF && + if ip route show default 2>/dev/null | grep -qF "$WAN_IF"; then + ok "маршрут по умолчанию через $WAN_IF: $(ip route show default)" + else fail "маршрут по умолчанию" "через $WAN_IF нет; маршруты: $(ip route show)"; fi + +# --- 5. NAT (MASQUERADE) для сетей HQ-RTR и BR-RTR --- +if root_or_skip "NAT (iptables)"; then + check_var "NAT для сети HQ" HQ_NET && { + if grep -qF "$HQ_NET" <(iptables -t nat -S POSTROUTING 2>/dev/null); then + ok "NAT для $HQ_NET" + else fail "NAT для $HQ_NET" "нет правила MASQUERADE"; fi + } + check_var "NAT для сети BR" BR_NET && { + if grep -qF "$BR_NET" <(iptables -t nat -S POSTROUTING 2>/dev/null); then + ok "NAT для $BR_NET" + else fail "NAT для $BR_NET" "нет правила MASQUERADE"; fi + } +fi + +# --- 6. IP forwarding --- +FWD=$(cat /proc/sys/net/ipv4/ip_forward 2>/dev/null) +if [[ "$FWD" == "1" ]]; then ok "ip_forward включён" +else fail "ip_forward" "ожидалось 1, получено '$FWD'"; fi + +# --- 7. Связь с роутерами (по адресам из переменных) --- +check_var "связь с HQ-RTR" HQ_RTR_ADDR && + if ping -c1 -W2 "$HQ_RTR_ADDR" &>/dev/null; then ok "ping HQ-RTR ($HQ_RTR_ADDR)" + else fail "ping HQ-RTR ($HQ_RTR_ADDR)" "недоступен"; fi +check_var "связь с BR-RTR" BR_RTR_ADDR && + if ping -c1 -W2 "$BR_RTR_ADDR" &>/dev/null; then ok "ping BR-RTR ($BR_RTR_ADDR)" + else fail "ping BR-RTR ($BR_RTR_ADDR)" "недоступен"; fi + +# --- 8. Часовой пояс --- +check_var "часовой пояс" EXAM_TZ && + expect_eq "часовой пояс" "$EXAM_TZ" "$(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Проверить вручную: ===" +echo " — доступ в Интернет с ISP: ping -c2 77.88.8.7" +echo " — доступ в Интернет из офисов: с HQ-SRV/BR-SRV ping 77.88.8.7" +echo " — таблицу 2 в отчёте сверить с выводом ip -4 -br a на всех машинах" + +echo "" +echo "=== Итог: OK=$OK FAIL=$FAIL ПРОПУЩЕНО=$SKIP ===" +[[ $FAIL -eq 0 ]] +} +main 2>&1 | tee "$LOG" +STATUS=${PIPESTATUS[0]} +echo "Лог сохранён: $LOG" +exit $STATUS diff --git a/tools/subnet-calc.sh b/tools/subnet-calc.sh new file mode 100644 index 0000000..8f3616c --- /dev/null +++ b/tools/subnet-calc.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# ============================================================ +# Калькулятор подсетей для экзамена 09.02.06 (python3 + ipaddress) +# +# ЗАПУСК: +# bash tools/subnet-calc.sh <базовая_сеть> [имя=ЧИСЛО ...] +# +# ЧИСЛО — это АДРЕСА, а не хосты: считаются адрес сети и broadcast. +# Если нужен именно объём ХОСТОВ — добавьте суффикс h, например: +# srv=30 -> 30 адресов (включая сеть и broadcast) +# srv=28h -> 28 хостов + 2 спецадреса = 30 адресов +# +# ПРИМЕР (адреса подбираются последовательно из базовой сети): +# bash tools/subnet-calc.sh 10.0.0.0/24 hq_srv=32 hq_cli=16 mgmt=8 br_srv=16 br_link=2 +# +# Для туннеля и линка BR-FW<->BR-RTR достаточно 2 адресов хостов: +# link=2 -> маска /30 (4 адреса: сеть, 2 хоста, broadcast) +# +# Пример вывода готовой таблицы — просто скопировать в отчёт (таблица 2). +# ============================================================ + +if ! command -v python3 >/dev/null 2>&1; then + echo "Нужен python3. Установите: dnf install -y python3" + exit 1 +fi + +python3 - "$@" <<'PY' +import sys +import ipaddress + + +def usage_and_exit(): + print("Использование: subnet-calc.sh <базовая_сеть> [имя=число_адресов ...]") + print("Суффикс h означает число ХОСТОВ (например srv=28h -> 28 хостов).") + sys.exit(1) + + +def parse_size(value): + value = value.strip().lower() + hosts = value.endswith("h") + if hosts: + value = value[:-1] + try: + count = int(value) + except ValueError: + usage_and_exit() + if count < 1: + usage_and_exit() + need = count + 2 if hosts else count + return count, need + + +def main(): + if len(sys.argv) < 2: + usage_and_exit() + try: + base = ipaddress.ip_network(sys.argv[1], strict=False) + except ValueError: + print("Некорректная базовая сеть:", sys.argv[1]) + usage_and_exit() + + print("Базовая сеть:", base, "| всего адресов:", base.num_addresses) + print() + + cursor = int(base.network_address) + last = int(base.broadcast_address) + rows = [] + overflow = False + + for item in sys.argv[2:]: + name, sep, raw = item.partition("=") + if not sep: + print("Ошибка: параметр без '=' ->", item) + usage_and_exit() + count, need = parse_size(raw) + prefix = base.max_prefixlen - (need - 1).bit_length() + # Выравниваем начало подсети по границе новой маски + step = 1 << (base.max_prefixlen - prefix) + cursor = (cursor + step - 1) // step * step + net = ipaddress.ip_network((cursor, prefix), strict=False) + if int(net.broadcast_address) > last: + overflow = True + rows.append([ + name, + str(net.network_address) + "/" + str(prefix), + str(net.netmask), + str(net.network_address + 1) if need > 2 else str(net.network_address), + str(net.broadcast_address - 1) if need > 2 else str(net.broadcast_address), + str(net.broadcast_address), + str(net.num_addresses), + ]) + cursor = int(net.broadcast_address) + 1 + + if overflow: + print("ВНИМАНИЕ: подсетей не хватило внутри базовой сети!") + print() + + headers = ["Назначение", "Сеть", "Маска", "Первый хост", "Последний хост", + "Broadcast", "Адресов"] + widths = [max(len(headers[i]), max(len(r[i]) for r in rows)) for i in range(len(headers))] + + line = "-+-".join("-" * w for w in widths) + print(" | ".join(h.ljust(w) for h, w in zip(headers, widths))) + print(line) + for row in rows: + print(" | ".join(c.ljust(w) for c, w in zip(row, widths))) + + +main() +PY diff --git a/zadanie1/br-fw.sh b/zadanie1/br-fw.sh new file mode 100644 index 0000000..1f4d472 --- /dev/null +++ b/zadanie1/br-fw.sh @@ -0,0 +1,162 @@ +#!/bin/bash +# ============================================================ +# ЗАДАНИЕ 1. Настройка BR-FW +# ------------------------------------------------------------ +# ВНИМАНИЕ: СИСТЕМА BR-FW НЕИЗВЕСТНА (УТОЧНИТЬ, что за система). +# Скрипт написан В ПРЕДПОЛОЖЕНИИ Linux / РЕД ОС 8. Если на стенде +# BR-FW — не Linux, используйте MANUAL.md и настраивайте по-своему. +# ------------------------------------------------------------ +# Имя, интерфейсы (к BR-RTR: сеть /30, к BR-SRV: сеть <=16 адресов), +# маршрут по умолчанию через BR-RTR, OSPF (только интерфейс к BR-RTR), +# IP forwarding, часовой пояс. +# NAT для офиса BR НЕ настраивается — NAT делает BR-RTR. +# ============================================================ + +# --- Проверка прав root --- +if [[ $EUID -ne 0 ]]; then + echo "Запустите скрипт с правами root (sudo bash br-fw.sh)" + exit 1 +fi + +# ================= ПЕРЕМЕННЫЕ (заполните перед запуском) ================= +HOSTNAME_FQDN="br-fw.au-team.irpo" # таблица 3, запись br-fw.au-team.irpo + +# --- Интерфейс в сторону BR-RTR (сеть с минимально возможной маской /30) --- +BR_RTR_IF="" # интерфейс к BR-RTR +BR_RTR_ADDR="" # адрес BR-FW в этой сети, формат адрес/префикс (/30) +BR_RTR_GW="" # адрес BR-RTR в этой же сети — маршрут по умолчанию + +# --- Интерфейс в сторону BR-SRV (сеть не более 16 адресов) --- +BR_SRV_IF="" # интерфейс к BR-SRV +BR_SRV_ADDR="" # адрес BR-FW в этой сети, формат адрес/префикс + +# --- OSPF (протокол разрешён ТОЛЬКО на интерфейсе к BR-RTR; пароля нет — +# аутентификация по заданию требуется только на туннеле HQ<->BR) --- +OSPF_AREA="0.0.0.0" +# ПРОВЕРИТЬ на РЕД ОС 8: пакет, конфиг и службу OSPF (frr / quagga) +FRR_PACKAGE="frr" +FRR_CONF="/etc/frr/frr.conf" +FRR_DAEMONS="/etc/frr/daemons" +DNS_FW="" # внешний DNS для BR-FW (необязательно, например 77.88.8.7) + +# --- Прочее --- +EXAM_TZ="Europe/Moscow" # проверить на экзамене +FORWARD_CONF="/etc/sysctl.d/99-ip-forward.conf" # перезаписывается целиком +NM_CONF_DIR="/etc/NetworkManager/system-connections" + +# ============ Проверка заполнения переменных ============ +MISSING=() +for NAME in HOSTNAME_FQDN BR_RTR_IF BR_RTR_ADDR BR_RTR_GW BR_SRV_IF \ + BR_SRV_ADDR EXAM_TZ; do + [[ -z "${!NAME}" ]] && MISSING+=("$NAME") +done +if [[ ${#MISSING[@]} -gt 0 ]]; then + echo "Заполните переменные в начале скрипта: ${MISSING[*]}" + exit 1 +fi + +echo "=== Настройка BR-FW (предположение: Linux / РЕД ОС 8) ===" + +# --- 1. Имя хоста --- +hostnamectl set-hostname "$HOSTNAME_FQDN" +echo "Имя хоста: $(hostname)" + +# --- 2. Интерфейс в сторону BR-RTR (+ маршрут по умолчанию) --- +echo "--- Профиль $BR_RTR_IF (статика, шлюз $BR_RTR_GW) ---" +cat > "$NM_CONF_DIR/$BR_RTR_IF.nmconnection" < "$NM_CONF_DIR/$BR_SRV_IF.nmconnection" < "$FORWARD_CONF" +sysctl -p "$FORWARD_CONF" + +# --- 5. OSPF: рекламируем обе сети BR, но HELLO только на линке к BR-RTR --- +echo "--- OSPF (${FRR_PACKAGE}) ---" +dnf install -y "$FRR_PACKAGE" || echo "ПРОВЕРИТЬ: пакет $FRR_PACKAGE не установился" +LINK_NET=$(python3 -c "import ipaddress,sys; print(ipaddress.ip_network(sys.argv[1], strict=False))" "$BR_RTR_ADDR") +SRV_NET=$(python3 -c "import ipaddress,sys; print(ipaddress.ip_network(sys.argv[1], strict=False))" "$BR_SRV_ADDR") +cat > "$FRR_CONF" </dev/null; then + echo "DNS уже прописан: $(grep '^nameserver' /etc/resolv.conf)" + else + echo "nameserver $DNS_FW" > /etc/resolv.conf + fi +fi + +# --- 7. Часовой пояс --- +timedatectl set-timezone "$EXAM_TZ" + +echo "" +echo "=== Самопроверка для BR-FW ===" +ip -4 -br address show +echo "" +echo "Маршруты:" +ip route show +echo "" +echo "Дополнительные проверки вручную:" +echo " vtysh -c 'show ip ospf neighbor' (сосед BR-RTR в FULL?)" +echo " ping -c2 $BR_RTR_GW (BR-RTR доступен?)" +echo " ping -c2 77.88.8.7 (Интернет через BR-RTR, у BR-RTR NAT)" diff --git a/zadanie1/br-rtr.sh b/zadanie1/br-rtr.sh new file mode 100644 index 0000000..7a0662a --- /dev/null +++ b/zadanie1/br-rtr.sh @@ -0,0 +1,217 @@ +#!/bin/bash +# ============================================================ +# ЗАДАНИЕ 1. Настройка BR-RTR (Linux / РЕД ОС 8) +# Имя, net_admin, интерфейсы (к ISP и к BR-FW: сеть /30), +# GRE-туннель до HQ-RTR, OSPF (MD5), NAT, часовой пояс. +# ============================================================ + +# --- Проверка прав root --- +if [[ $EUID -ne 0 ]]; then + echo "Запустите скрипт с правами root (sudo bash br-rtr.sh)" + exit 1 +fi + +# ================= ПЕРЕМЕННЫЕ (заполните перед запуском) ================= +HOSTNAME_FQDN="br-rtr.au-team.irpo" # таблица 3, запись br-rtr.au-team.irpo + +# --- Пользователь net_admin (значения из задания) --- +NET_ADMIN_USER="net_admin" +NET_ADMIN_PASS="P@ssw0rd" + +# --- Интерфейс в сторону ISP --- +ISP_IF="" # интерфейс к ISP (пример: enp0s3) +ISP_NET="" # адрес BR-RTR в этой сети, формат адрес/префикс + # (по заданию сеть 172.16.2.0/28) +ISP_GW="" # шлюз по умолчанию — адрес ISP в этой же сети +DNS_ROUTER="" # внешний DNS для роутера (необязательно, например 77.88.8.7) + +# --- Интерфейс в сторону BR-FW (сеть с минимально возможной маской) --- +BR_LINK_IF="" # интерфейс к BR-FW (пример: enp0s8) +BR_LINK_ADDR="" # адрес BR-RTR в этой сети, адрес/префикс (маска /30 — см. калькулятор) + +# --- Локальная сеть в сторону BR-SRV (через BR-FW; не более 16 адресов) --- +# Нужна только для правил NAT — адрес BR-RTR здесь назначает BR-FW. +NAT_NETS="" # через пробел, например: "<сеть к BR-FW/префикс> <сеть BR-SRV/префикс>" + +# --- GRE-туннель до HQ-RTR (сеть 10.10.10.0/24, минимальная маска -> /30) --- +GRE_IF="gre1" +GRE_LOCAL="" # локальный конец туннеля, адрес/префикс (из калькулятора, /30) +GRE_REMOTE="" # удалённый конец — адрес HQ-RTR в сети ISP (без префикса) + +# --- OSPF (значения из задания) --- +OSPF_PASSWORD="P@ssw0rd" +OSPF_AREA="0.0.0.0" +# ПРОВЕРИТЬ на РЕД ОС 8: пакет, конфиг и службу OSPF (frr / quagga) +FRR_PACKAGE="frr" +FRR_CONF="/etc/frr/frr.conf" +FRR_DAEMONS="/etc/frr/daemons" + +# --- Прочее --- +EXAM_TZ="Europe/Moscow" # проверить на экзамене +FORWARD_CONF="/etc/sysctl.d/99-ip-forward.conf" # перезаписывается целиком +NM_CONF_DIR="/etc/NetworkManager/system-connections" +IPTABLES_SERVICE="iptables" # ПРОВЕРИТЬ + +# ============ Проверка заполнения переменных ============ +MISSING=() +for NAME in HOSTNAME_FQDN ISP_IF ISP_NET ISP_GW BR_LINK_IF BR_LINK_ADDR \ + NAT_NETS GRE_LOCAL GRE_REMOTE EXAM_TZ; do + [[ -z "${!NAME}" ]] && MISSING+=("$NAME") +done +if [[ ${#MISSING[@]} -gt 0 ]]; then + echo "Заполните переменные в начале скрипта: ${MISSING[*]}" + exit 1 +fi + +echo "=== Настройка BR-RTR ===" + +# --- 1. Имя хоста --- +hostnamectl set-hostname "$HOSTNAME_FQDN" +echo "Имя хоста: $(hostname)" + +# --- 2. Пользователь net_admin с sudo без пароля --- +echo "--- Пользователь $NET_ADMIN_USER ---" +if id "$NET_ADMIN_USER" &>/dev/null; then + echo "Пользователь уже существует" +else + useradd -m "$NET_ADMIN_USER" +fi +echo "$NET_ADMIN_USER:$NET_ADMIN_PASS" | chpasswd +echo "$NET_ADMIN_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/net_admin +chmod 440 /etc/sudoers.d/net_admin + +# --- 3. Интерфейс в сторону ISP --- +echo "--- Профиль $ISP_IF (статика, шлюз $ISP_GW) ---" +cat > "$NM_CONF_DIR/$ISP_IF.nmconnection" < "$NM_CONF_DIR/$BR_LINK_IF.nmconnection" < "$NM_CONF_DIR/$GRE_IF.nmconnection" < "$FORWARD_CONF" +sysctl -p "$FORWARD_CONF" + +# --- 7. NAT в сторону ISP --- +echo "--- NAT (MASQUERADE) ---" +for SRC_NET in $NAT_NETS; do + if iptables -t nat -C POSTROUTING -s "$SRC_NET" -o "$ISP_IF" -j MASQUERADE 2>/dev/null; then + echo "Правило для $SRC_NET уже есть" + else + iptables -t nat -A POSTROUTING -s "$SRC_NET" -o "$ISP_IF" -j MASQUERADE + echo "Добавлено MASQUERADE для $SRC_NET" + fi +done +iptables-save > /etc/sysconfig/iptables +systemctl enable --now "$IPTABLES_SERVICE" 2>/dev/null \ + || echo "ПРОВЕРИТЬ: служба $IPTABLES_SERVICE не запустилась" + +# --- 8. OSPF: туннель (MD5) + интерфейс к BR-FW (сосед BR-FW) --- +echo "--- OSPF (${FRR_PACKAGE}) ---" +dnf install -y "$FRR_PACKAGE" || echo "ПРОВЕРИТЬ: пакет $FRR_PACKAGE не установился" +TUN_NET=$(python3 -c "import ipaddress,sys; print(ipaddress.ip_network(sys.argv[1], strict=False))" "$GRE_LOCAL") +LINK_NET=$(python3 -c "import ipaddress,sys; print(ipaddress.ip_network(sys.argv[1], strict=False))" "$BR_LINK_ADDR") +cat > "$FRR_CONF" < "$NM_CONF_DIR/$SRV_IF.nmconnection" </dev/null; then + echo "DNS уже прописан: $(grep '^nameserver' /etc/resolv.conf)" + else + echo "nameserver $DNS_SRV" > /etc/resolv.conf + fi +fi + +# --- 3. Пользователь sshuser: UID 2027, пароль, sudo без пароля --- +if id "$SSH_USER" &>/dev/null; then + echo "Пользователь уже существует" +else + useradd -u "$SSH_USER_UID" -m "$SSH_USER" +fi +echo "$SSH_USER:$SSH_USER_PASS" | chpasswd +echo "$SSH_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/sshuser +chmod 440 /etc/sudoers.d/sshuser +echo "Проверка UID: id $SSH_USER" + +# --- 4. SSH: порт 2027, только sshuser, MaxAuthTries 2, баннер --- +echo "--- Настройка SSH (порт $SSH_PORT) ---" +echo "$SSH_BANNER_TEXT" > "$SSH_BANNER_FILE" +for KEY in Port AllowUsers MaxAuthTries Banner; do + sed -riE "s/^[[:space:]]*[#]*[[:space:]]*${KEY}[[:space:]].*$//" "$SSHD_CONF" +done +cat >> "$SSHD_CONF" </dev/null 2>&1 && [[ $(getenforce) == "Enforcing" ]]; then + if ! semanage port -l | grep -qw "$SSH_PORT" 2>/dev/null; then + semanage port -a -t ssh_port_t -p tcp "$SSH_PORT" 2>/dev/null \ + || echo "ПРОВЕРИТЬ: не удалось добавить SELinux-порт $SSH_PORT" + fi +fi +sshd -t && echo "Конфиг sshd корректен" || echo "ПРОВЕРИТЬ: sshd -t вернул ошибку" +systemctl restart sshd || systemctl restart ssh +echo "Проверка: ss -tlnp | grep ':$SSH_PORT'" + +# --- 5. Часовой пояс --- +timedatectl set-timezone "$EXAM_TZ" + +echo "" +echo "=== Самопроверка для BR-SRV ===" +ip -4 -br address show +echo "" +echo "Дополнительные проверки вручную:" +echo " ss -tlnp | grep ':$SSH_PORT' (SSH на порту 2027?)" +echo " ping -c2 $SRV_GW (BR-FW доступен?)" diff --git a/zadanie1/hq-cli.sh b/zadanie1/hq-cli.sh new file mode 100644 index 0000000..50296ae --- /dev/null +++ b/zadanie1/hq-cli.sh @@ -0,0 +1,73 @@ +#!/bin/bash +# ============================================================ +# ЗАДАНИЕ 1. Настройка HQ-CLI (Linux / РЕД ОС 8, только консоль) +# Имя, адрес по DHCP от HQ-RTR (VLAN 200), часовой пояс. +# DHCP-сервер находится на HQ-RTR: выдаёт адрес, шлюз (HQ-RTR), +# DNS (HQ-SRV) и суффикс au-team.irpo. +# ============================================================ + +# --- Проверка прав root --- +if [[ $EUID -ne 0 ]]; then + echo "Запустите скрипт с правами root (sudo bash hq-cli.sh)" + exit 1 +fi + +# ================= ПЕРЕМЕННЫЕ (заполните перед запуском) ================= +HOSTNAME_FQDN="hq-cli.au-team.irpo" # таблица 3, запись hq-cli.au-team.irpo + +CLI_IF="" # интерфейс к HQ-SW (access-порт VLAN 200; тег ставит только HQ-SW) + +EXAM_TZ="Europe/Moscow" # проверить на экзамене +NM_CONF_DIR="/etc/NetworkManager/system-connections" + +# ============ Проверка заполнения переменных ============ +MISSING=() +for NAME in HOSTNAME_FQDN CLI_IF EXAM_TZ; do + [[ -z "${!NAME}" ]] && MISSING+=("$NAME") +done +if [[ ${#MISSING[@]} -gt 0 ]]; then + echo "Заполните переменные в начале скрипта: ${MISSING[*]}" + exit 1 +fi + +echo "=== Настройка HQ-CLI ===" + +# --- 1. Имя хоста --- +hostnamectl set-hostname "$HOSTNAME_FQDN" +echo "Имя хоста: $(hostname)" + +# --- 2. Интерфейс: адрес по DHCP --- +echo "--- Профиль $CLI_IF (DHCP) ---" +cat > "$NM_CONF_DIR/$CLI_IF.nmconnection" <" diff --git a/zadanie1/hq-rtr.sh b/zadanie1/hq-rtr.sh new file mode 100644 index 0000000..d9bb0ac --- /dev/null +++ b/zadanie1/hq-rtr.sh @@ -0,0 +1,254 @@ +#!/bin/bash +# ============================================================ +# ЗАДАНИЕ 1. Настройка HQ-RTR (Linux / РЕД ОС 8) +# Имя, net_admin, интерфейс к ISP, VLAN 100/200/999 на ОДНОМ адаптере, +# GRE-туннель до BR-RTR, OSPF (MD5) в туннеле, NAT, DHCP для VLAN 200, +# часовой пояс. +# ============================================================ + +# --- Проверка прав root --- +if [[ $EUID -ne 0 ]]; then + echo "Запустите скрипт с правами root (sudo bash hq-rtr.sh)" + exit 1 +fi + +# ================= ПЕРЕМЕННЫЕ (заполните перед запуском) ================= +HOSTNAME_FQDN="hq-rtr.au-team.irpo" # таблица 3, запись hq-rtr.au-team.irpo + +# --- Пользователь net_admin (значения из задания) --- +NET_ADMIN_USER="net_admin" +NET_ADMIN_PASS="P@ssw0rd" + +# --- Интерфейс в сторону ISP --- +ISP_IF="" # интерфейс к ISP (пример: enp0s3) +ISP_NET="" # адрес HQ-RTR в этой сети, формат адрес/префикс + # (по заданию сеть 172.16.1.0/28) +ISP_GW="" # шлюз по умолчанию — адрес ISP в этой же сети +DNS_ROUTER="" # внешний DNS для роутера (необязательно, например 77.88.8.7) + +# --- Локальные VLAN на ОДНОМ физическом адаптере --- +LAN_IF="" # физический адаптер в сторону HQ-SW (пример: enp0s8) +VLAN100_ADDR="" # адрес HQ-RTR в VLAN 100 (сеть не более 32 адресов), адрес/префикс +VLAN200_ADDR="" # адрес HQ-RTR в VLAN 200 (сеть не более 16 адресов), адрес/префикс +VLAN999_ADDR="" # адрес HQ-RTR в VLAN 999 (сеть не более 8 адресов), адрес/префикс + +# --- GRE-туннель до BR-RTR (сеть 10.10.10.0/24, минимальная маска -> /30) --- +GRE_IF="gre1" +GRE_LOCAL="" # локальный конец туннеля, адрес/префикс (из calculator, /30) +GRE_REMOTE="" # удалённый конец туннеля — адрес BR-RTR в сети ISP (без префикса) + +# --- OSPF (значения из задания) --- +OSPF_PASSWORD="P@ssw0rd" +OSPF_AREA="0.0.0.0" +# ПРОВЕРИТЬ на РЕД ОС 8: пакет, конфиг и службу OSPF (frr / quagga) +FRR_PACKAGE="frr" +FRR_CONF="/etc/frr/frr.conf" +FRR_DAEMONS="/etc/frr/daemons" + +# --- NAT в сторону ISP (адресации не содержит) --- +# Список сетей офиса для NAT — адреса сетей с префиксом (для правил iptables). +NAT_NETS="" # через пробел, например: "<сеть VLAN100/префикс> <сеть VLAN200/префикс> <сеть VLAN999/префикс>" + +# --- DHCP для VLAN 200 (клиент — HQ-CLI) --- +DHCP_PACKAGE="dhcp-server" # ПРОВЕРИТЬ: пакет DHCP-сервера в РЕД ОС 8 +DHCPD_SERVICE="dhcpd" # ПРОВЕРИТЬ: имя службы +DHCPD_CONF="/etc/dhcp/dhcpd.conf" +DHCP_SUBNET="" # адрес сети VLAN 200 (без префикса) +DHCP_NETMASK="" # маска этой сети (255.255.255.x) +DHCP_RANGE_FIRST="" # первый адрес выдачи (АДРЕС HQ-RTR ВЫПАДАЕТ: он вне range) +DHCP_RANGE_LAST="" # последний адрес выдачи +DHCP_DOMAIN="au-team.irpo" +HQ_SRV_IP="" # адрес HQ-SRV (VLAN 100) — DNS-сервер для HQ-CLI + +# --- Прочее --- +EXAM_TZ="Europe/Moscow" # проверить на экзамене +FORWARD_CONF="/etc/sysctl.d/99-ip-forward.conf" # перезаписывается целиком +NM_CONF_DIR="/etc/NetworkManager/system-connections" +IPTABLES_SERVICE="iptables" # ПРОВЕРИТЬ + +# ============ Проверка заполнения переменных ============ +MISSING=() +for NAME in HOSTNAME_FQDN ISP_IF ISP_NET ISP_GW LAN_IF VLAN100_ADDR VLAN200_ADDR \ + VLAN999_ADDR GRE_LOCAL GRE_REMOTE NAT_NETS DHCP_SUBNET DHCP_NETMASK \ + DHCP_RANGE_FIRST DHCP_RANGE_LAST HQ_SRV_IP EXAM_TZ; do + [[ -z "${!NAME}" ]] && MISSING+=("$NAME") +done +if [[ ${#MISSING[@]} -gt 0 ]]; then + echo "Заполните переменные в начале скрипта: ${MISSING[*]}" + exit 1 +fi + +echo "=== Настройка HQ-RTR ===" + +# --- 1. Имя хоста --- +hostnamectl set-hostname "$HOSTNAME_FQDN" +echo "Имя хоста: $(hostname)" + +# --- 2. Пользователь net_admin с sudo без пароля --- +echo "--- Пользователь $NET_ADMIN_USER ---" +if id "$NET_ADMIN_USER" &>/dev/null; then + echo "Пользователь уже существует" +else + useradd -m "$NET_ADMIN_USER" +fi +echo "$NET_ADMIN_USER:$NET_ADMIN_PASS" | chpasswd +# Файл в sudoers.d перезаписывается целиком — дублей нет +echo "$NET_ADMIN_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/net_admin +chmod 440 /etc/sudoers.d/net_admin +echo "Проверка: su - $NET_ADMIN_USER -c 'sudo -n true && echo sudo OK'" + +# --- 3. Интерфейс в сторону ISP --- +echo "--- Профиль $ISP_IF (статика, шлюз $ISP_GW) ---" +cat > "$NM_CONF_DIR/$ISP_IF.nmconnection" < "$NM_CONF_DIR/$1.nmconnection" + chmod 600 "$NM_CONF_DIR/$1.nmconnection" +} +echo "--- VLAN 100 ---"; make_vlan_profile vlan100 100 "$VLAN100_ADDR" +echo "--- VLAN 200 ---"; make_vlan_profile vlan200 200 "$VLAN200_ADDR" +echo "--- VLAN 999 ---"; make_vlan_profile vlan999 999 "$VLAN999_ADDR" + +# --- 5. GRE-туннель --- +echo "--- Туннель $GRE_IF ---" +cat > "$NM_CONF_DIR/$GRE_IF.nmconnection" < "$FORWARD_CONF" +sysctl -p "$FORWARD_CONF" + +# --- 7. NAT в сторону ISP --- +echo "--- NAT (MASQUERADE) ---" +for SRC_NET in $NAT_NETS; do + if iptables -t nat -C POSTROUTING -s "$SRC_NET" -o "$ISP_IF" -j MASQUERADE 2>/dev/null; then + echo "Правило для $SRC_NET уже есть" + else + iptables -t nat -A POSTROUTING -s "$SRC_NET" -o "$ISP_IF" -j MASQUERADE + echo "Добавлено MASQUERADE для $SRC_NET" + fi +done +iptables-save > /etc/sysconfig/iptables +systemctl enable --now "$IPTABLES_SERVICE" 2>/dev/null \ + || echo "ПРОВЕРИТЬ: служба $IPTABLES_SERVICE не запустилась" + +# --- 8. OSPF в туннеле с аутентификацией MD5 --- +echo "--- OSPF (${FRR_PACKAGE}) ---" +dnf install -y "$FRR_PACKAGE" || echo "ПРОВЕРИТЬ: пакет $FRR_PACKAGE не установился" +# Сеть туннеля вычисляем из адреса туннеля (нужен python3) +TUN_NET=$(python3 -c "import ipaddress,sys; print(ipaddress.ip_network(sys.argv[1], strict=False))" "$GRE_LOCAL") +cat > "$FRR_CONF" < "$DHCPD_CONF" < "$NM_CONF_DIR/$SRV_IF.nmconnection" </dev/null; then + echo "DNS уже прописан: $(grep '^nameserver' /etc/resolv.conf)" + else + echo "nameserver $DNS_SRV" > /etc/resolv.conf + fi +fi + +# --- 3. Пользователь sshuser: UID 2027, пароль, sudo без пароля --- +if id "$SSH_USER" &>/dev/null; then + echo "Пользователь уже существует" +else + useradd -u "$SSH_USER_UID" -m "$SSH_USER" +fi +echo "$SSH_USER:$SSH_USER_PASS" | chpasswd +echo "$SSH_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/sshuser +chmod 440 /etc/sudoers.d/sshuser +echo "Проверка UID: id $SSH_USER" + +# --- 4. SSH: порт 2027, только sshuser, MaxAuthTries 2, баннер --- +echo "--- Настройка SSH (порт $SSH_PORT) ---" +echo "$SSH_BANNER_TEXT" > "$SSH_BANNER_FILE" +# Удаляем старые значения (в т.ч. закомментированные), затем дописываем новые. +# Повторный запуск не создаёт дублей: сначала чистим, потом пишем. +for KEY in Port AllowUsers MaxAuthTries Banner; do + sed -riE "s/^[[:space:]]*[#]*[[:space:]]*${KEY}[[:space:]].*$//" "$SSHD_CONF" +done +cat >> "$SSHD_CONF" </dev/null 2>&1 && [[ $(getenforce) == "Enforcing" ]]; then + if ! semanage port -l | grep -qw "$SSH_PORT" 2>/dev/null; then + semanage port -a -t ssh_port_t -p tcp "$SSH_PORT" 2>/dev/null \ + || echo "ПРОВЕРИТЬ: не удалось добавить SELinux-порт $SSH_PORT" + fi +fi +sshd -t && echo "Конфиг sshd корректен" || echo "ПРОВЕРИТЬ: sshd -t вернул ошибку" +systemctl restart sshd || systemctl restart ssh + +echo "Проверка: ss -tlnp | grep ':$SSH_PORT'" + +# --- 5. DNS-сервер (dnsmasq): зона au-team.irpo по таблице 3 --- +echo "--- DNS ($DNS_PACKAGE) ---" +dnf install -y "$DNS_PACKAGE" || echo "ПРОВЕРИТЬ: пакет $DNS_PACKAGE не установился" +# Записи A и PTR (PTR появляется автоматически по записям hosts — +# убедитесь на стенде, что обратные зоны отвечают) +cat > "$DNS_HOSTS_FILE" < "$DNS_EXTRA_CONF" </dev/null \ + || echo "Мост $BRIDGE уже существует — продолжаем" +ip link set dev "$BRIDGE" up + +# --- 3. Порты в мост --- +echo "--- Порты в мост ---" +for IF in "$RTR_IF" "$SRV_IF" "$CLI_IF"; do + ip link set dev "$IF" nomaster 2>/dev/null || true + ip link set dev "$IF" master "$BRIDGE" || echo "ВНИМАНИЕ: $IF не вошёл в мост" + ip link set dev "$IF" up +done + +# --- 4. VLAN-конфигурация портов --- +# ВАЖНО: сначала убираем дефолтный untagged vid 1, иначе трафик уйдёт в VLAN 1. +echo "--- VLAN-порты ---" + +# Порт к HQ-RTR: trunk (все VLAN тегированными, без untagged) +bridge vlan del dev "$RTR_IF" vid 1 2>/dev/null || true +for VID in $VLAN_SRV $VLAN_CLI $VLAN_MGMT; do + bridge vlan add dev "$RTR_IF" vid "$VID" +done + +# Порты к HQ-SRV и HQ-CLI: access — VLAN уходит наружу без тега +bridge vlan del dev "$SRV_IF" vid 1 2>/dev/null || true +bridge vlan add dev "$SRV_IF" vid "$VLAN_SRV" pvid untagged +bridge vlan del dev "$CLI_IF" vid 1 2>/dev/null || true +bridge vlan add dev "$CLI_IF" vid "$VLAN_CLI" pvid untagged + +# --- 5. Управление коммутатором: адрес в VLAN 999 на подынтерфейсе моста --- +VLAN_IF="$BRIDGE.$VLAN_MGMT" +ip link add link "$BRIDGE" name "$VLAN_IF" type vlan id "$VLAN_MGMT" 2>/dev/null \ + || true +ip addr replace "$MGMT_ADDR" dev "$VLAN_IF" +ip link set dev "$VLAN_IF" up +if [[ -n "$MGMT_GW" ]]; then + ip route replace default via "$MGMT_GW" dev "$VLAN_IF" +fi +echo "Управление: $VLAN_IF = $MGMT_ADDR" + +# --- 6. Сохраняем после reboot: копия скрипта + systemd-юнит --- +# (скрипт идемпотентен, повторный запуск безопасен) +install -m 755 "$0" "$SELF_COPY" \ + || echo "ПРОВЕРИТЬ: не удалось скопировать $0 в $SELF_COPY" +cat > "$UNIT_FILE" <<'EOF' +[Unit] +Description=HQ-SW: bridge с VLAN filtering и управлением в VLAN 999 +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +ExecStart=/usr/local/sbin/hq-sw-bridge + +[Install] +WantedBy=multi-user.target +EOF +systemctl daemon-reload +systemctl enable hq-sw-bridge \ + && echo "После reboot мост восстановится автоматически" \ + || echo "ПРОВЕРИТЬ: не включился автозапуск hq-sw-bridge.service" + +echo "" +echo "=== Самопроверка для HQ-SW ===" +echo "Порты и мост:" +ip -br link show +echo "" +echo "VLAN-конфигурация портов:" +bridge vlan show +echo "" +echo "Управление:" +ip -4 addr show "$VLAN_IF" 2>/dev/null +[[ -n "$MGMT_GW" ]] && ip route show default +echo "" +echo "Дополнительные проверки вручную:" +echo " bridge -d link show (порты в состоянии forward?)" +echo " ping -c2 <адрес HQ-RTR в VLAN 999>" +echo " После reboot: systemctl status hq-sw-bridge" diff --git a/zadanie1/isp.sh b/zadanie1/isp.sh new file mode 100644 index 0000000..a17a5e8 --- /dev/null +++ b/zadanie1/isp.sh @@ -0,0 +1,182 @@ +#!/bin/bash +# ============================================================ +# ЗАДАНИЕ 1. Настройка ISP (Linux / РЕД ОС 8) +# Имя, интерфейсы (WAN по DHCP, линки к HQ-RTR и BR-RTR), +# NAT для сетей HQ-RTR и BR-RTR, часовой пояс. +# ============================================================ + +# --- Проверка прав root --- +if [[ $EUID -ne 0 ]]; then + echo "Запустите скрипт с правами root (sudo bash isp.sh)" + exit 1 +fi + +# ================= ПЕРЕМЕННЫЕ (заполните перед запуском) ================= +# Полное доменное имя ISP. В таблице 3 задания записи ISP нет — уточните имя. +HOSTNAME_FQDN="" + +# Администрирование ниже настраивается без запросов — только переменные. + +WAN_IF="" # интерфейс к провайдеру (пример: enp0s3), получит адрес по DHCP +HQ_IF="" # интерфейс в сторону HQ-RTR +HQ_NET="" # адрес ISP на этом интерфейсе, формат адрес/префикс + # (по заданию сеть 172.16.1.0/28 — вписать свой адрес/префикс) +BR_IF="" # интерфейс в сторону BR-RTR +BR_NET="" # адрес ISP здесь, формат адрес/префикс + # (по заданию сеть 172.16.2.0/28) + +DNS_ISP="" # внешний DNS-сервер, если DHCP провайдера его не выдаёт + # (необязательно, например 77.88.8.7) + +# Часовой пояс — поставьте пояс места проведения экзамена +EXAM_TZ="Europe/Moscow" # проверить на экзамене + +# Служба сохранения iptables на РЕД ОС 8 — проверить на стенде (ПРОВЕРИТЬ: +# пакет iptables-services и имя службы) +IPTABLES_SERVICE="iptables" + +NM_CONF_DIR="/etc/NetworkManager/system-connections" +FORWARD_CONF="/etc/sysctl.d/99-ip-forward.conf" # перезаписывается целиком + +# ============ Проверка заполнения переменных ============ +MISSING=() +for NAME in HOSTNAME_FQDN WAN_IF HQ_IF HQ_NET BR_IF BR_NET EXAM_TZ; do + [[ -z "${!NAME}" ]] && MISSING+=("$NAME") +done +if [[ ${#MISSING[@]} -gt 0 ]]; then + echo "Заполните переменные в начале скрипта: ${MISSING[*]}" + exit 1 +fi + +echo "=== Настройка ISP ===" + +# --- 1. Имя хоста --- +echo "Имя хоста: $HOSTNAME_FQDN" +hostnamectl set-hostname "$HOSTNAME_FQDN" +echo "Проверка: hostnamectl" + +# --- 2. WAN-интерфейс: адрес по DHCP --- +echo "--- Профиль $WAN_IF (DHCP) ---" +cat > "$NM_CONF_DIR/$WAN_IF.nmconnection" < "$NM_CONF_DIR/$HQ_IF.nmconnection" < "$NM_CONF_DIR/$BR_IF.nmconnection" < "$FORWARD_CONF" +sysctl -p "$FORWARD_CONF" + +# --- 7. NAT для сетей HQ-RTR и BR-RTR --- +# Динамическая трансляция (MASQUERADE) на выходе в Интернет только для +# адресов сетей HQ-RTR и BR-RTR. Правила добавляются, только если их нет. +echo "--- NAT (MASQUERADE) ---" +for SRC_NET in "$HQ_NET" "$BR_NET"; do + if iptables -t nat -C POSTROUTING -s "$SRC_NET" -o "$WAN_IF" -j MASQUERADE 2>/dev/null; then + echo "Правило для $SRC_NET уже есть" + else + iptables -t nat -A POSTROUTING -s "$SRC_NET" -o "$WAN_IF" -j MASQUERADE + echo "Добавлено MASQUERADE для $SRC_NET" + fi +done + +# --- 8. Сохраняем правила iptables и включаем службу --- +echo "--- Сохранение правил iptables ---" +if command -v iptables-save >/dev/null 2>&1; then + iptables-save > /etc/sysconfig/iptables + systemctl enable --now "$IPTABLES_SERVICE" 2>/dev/null \ + || echo "ПРОВЕРИТЬ: служба $IPTABLES_SERVICE не запустилась" +else + echo "ПРОВЕРИТЬ: iptables-save недоступен — как сохранить правила на РЕД ОС 8?" +fi + +# --- 9. DNS (если DHCP провайдера не выдал) --- +if [[ -n "$DNS_ISP" ]]; then + echo "ПРОВЕРИТЬ: DNS-сервер для ISP задаётся здесь ($DNS_ISP)." + echo "Если resolv.conf пустой — впишите DNS через nmcli или вручную." +fi + +# --- 10. Часовой пояс --- +timedatectl set-timezone "$EXAM_TZ" +echo "Часовой пояс: $(timedatectl show -p Timezone --value)" + +echo "" +echo "=== Самопроверка для ISP ===" +echo "Адреса интерфейсов:" +ip -4 -br address show +echo "" +echo "Маршруты (маршрут по умолчанию должен идти через $WAN_IF):" +ip route show +echo "" +echo "Правила NAT:" +iptables -t nat -L POSTROUTING -n -v +echo "" +echo "Дополнительные проверки вручную:" +echo " ping -c2 77.88.8.7 (доступ в Интернет от ISP)" +echo " ping -c2 <адрес HQ-RTR> (линк к HQ-RTR)" +echo " ping -c2 <адрес BR-RTR> (линк к BR-RTR)"