#!/usr/bin/env python3 """ Скрипт для загрузки префиксов из текстовых файлов в ExaBGP """ import sys import os import time import json import ipaddress from pathlib import Path from typing import List, Set # Настройки DATA_DIR = "/app/data" LOG_FILE = "/app/logs/prefixes.log" PREFIX_FILES = ["prefixes.txt", "additional_prefixes.txt"] def log_message(message: str): """Запись сообщения в лог""" timestamp = time.strftime("%Y-%m-%d %H:%M:%S") log_entry = f"[{timestamp}] {message}" # Вывод в stdout для ExaBGP print(log_entry, flush=True) # Запись в файл (с обработкой ошибок) try: with open(LOG_FILE, "a") as f: f.write(log_entry + "\n") except (PermissionError, OSError) as e: # Если не можем записать в файл, просто выводим в stderr print(f"Warning: Could not write to log file: {e}", file=sys.stderr, flush=True) def log_error(message: str): """Запись ошибки в лог""" log_message(f"ERROR: {message}") def validate_prefix(prefix: str) -> bool: """Валидация IP префикса""" try: ipaddress.ip_network(prefix, strict=False) return True except ValueError: return False def load_prefixes_from_file(file_path: Path) -> Set[str]: """Загрузка префиксов из файла""" prefixes = set() if not file_path.exists(): log_message(f"File not found: {file_path}") return prefixes try: with open(file_path, 'r') as f: for line_num, line in enumerate(f, 1): line = line.strip() # Пропуск пустых строк и комментариев if not line or line.startswith('#'): continue # Валидация префикса if validate_prefix(line): prefixes.add(line) else: log_message(f"Invalid prefix in {file_path}:{line_num}: {line}") except Exception as e: log_message(f"Error reading {file_path}: {e}") return prefixes def load_all_prefixes() -> Set[str]: """Загрузка всех префиксов из всех файлов""" all_prefixes = set() for filename in PREFIX_FILES: file_path = Path(DATA_DIR) / filename prefixes = load_prefixes_from_file(file_path) all_prefixes.update(prefixes) log_message(f"Loaded {len(prefixes)} prefixes from {filename}") return all_prefixes def announce_prefixes(prefixes: Set[str]): """Анонсирование префиксов через ExaBGP API""" # Получение настроек из переменных окружения neighbor_ip = os.environ.get('BGP_NEIGHBOR_IP', '192.168.1.1') local_as = int(os.environ.get('BGP_LOCAL_AS', '65000')) router_id = os.environ.get('BGP_ROUTER_ID', '192.168.1.100') for prefix in sorted(prefixes): # Формат команды для ExaBGP (упрощенный) command = { "command": "announce route", "neighbor": neighbor_ip, "attribute": { "origin": "igp", "as-path": [local_as], "next-hop": router_id }, "nlri": prefix } # Отправка команды в ExaBGP print(json.dumps(command), flush=True) log_message(f"Announced prefix: {prefix}") def withdraw_prefixes(prefixes: Set[str]): """Отзыв префиксов через ExaBGP API""" # Получение настроек из переменных окружения neighbor_ip = os.environ.get('BGP_NEIGHBOR_IP', '192.168.1.1') for prefix in sorted(prefixes): command = { "command": "withdraw route", "neighbor": neighbor_ip, "nlri": prefix } print(json.dumps(command), flush=True) log_message(f"Withdrew prefix: {prefix}") def main(): """Основная функция""" # Создание директории для логов в начале try: os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True) except (PermissionError, OSError): pass # Игнорируем ошибки создания директории # Проверка тестового режима if len(sys.argv) > 1 and sys.argv[1] == '--test': print("Testing prefix loader...") prefixes = load_all_prefixes() print(f"Found {len(prefixes)} prefixes: {list(prefixes)}") return log_message("Starting prefix loader...") # Загрузка префиксов prefixes = load_all_prefixes() log_message(f"Total prefixes loaded: {len(prefixes)}") if not prefixes: log_message("No valid prefixes found. Exiting.") return # Анонсирование префиксов announce_prefixes(prefixes) log_message("All prefixes announced successfully") # Ожидание команд от ExaBGP try: while True: line = sys.stdin.readline() if not line: break line = line.strip() if not line: # Пропуск пустых строк continue # Обработка команд от ExaBGP try: data = json.loads(line) log_message(f"Received command: {data}") except json.JSONDecodeError: # Не все сообщения от ExaBGP являются JSON # Это может быть обычное текстовое сообщение if line.startswith('[') and line.endswith(']'): # Это может быть лог сообщение от ExaBGP log_message(f"Received log message: {line}") else: log_message(f"Received non-JSON message: {line}") except KeyboardInterrupt: log_message("Received interrupt signal") except Exception as e: log_message(f"Error in main loop: {e}") finally: # Отзыв всех префиксов при завершении log_message("Withdrawing all prefixes...") withdraw_prefixes(prefixes) log_message("Prefix loader stopped") if __name__ == "__main__": main()