Дополнительные инструменты (tools)
This commit is contained in:
parent
1deb68bd75
commit
7af8d82513
110
tools/subnet-calc.sh
Normal file
110
tools/subnet-calc.sh
Normal file
|
|
@ -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
|
||||||
Loading…
Reference in a new issue