create routes via ssh

This commit is contained in:
2024-08-01 15:10:28 +03:00
parent d59451fefa
commit e0e8cd3b4b
4 changed files with 259 additions and 109 deletions

162
.gitignore vendored Normal file
View File

@ -0,0 +1,162 @@
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

View File

@ -1,48 +1,34 @@
Этот скрипт предназначен для добавления статических маршрутов на роутер Keenetic с использованием нотации CIDR. Он загружает список CIDR-блоков с сайта antifilter.download, объединяет их с заранее определенным списком пользовательских CIDR-блоков и добавляет их в таблицу маршрутизации роутера для доступа к ресурсам через заранее настроенный VPN. Скрипт использует базовую аутентификацию для безопасного доступа к роутеру.
Этот скрипт предназначен для автоматического добавления статических маршрутов на роутер Keenetic. Он загружает список CIDR-блоков из указанного URL, объединяет их с предопределенным списком пользовательских CIDR-блоков и добавляет их в таблицу маршрутизации роутера через SSH-соединение.
## Требования
* Python 3.x
* Библиотеки urllib и base64 (входят в стандартную библиотеку)
* Переменные окружения для настройки
- Python 3.x
## Установка
Убедитесь, что у вас установлен Python 3.x. Если нет, скачайте и установите его с официального сайта Python.
Установите необходимые библиотеки с помощью pip:
```bash
pip install -r requirements.txt
```
Скачайте скрипт и сохраните его в файл, например update_routes.py.
## Переменные окружения
Перед запуском скрипта убедитесь, что установлены следующие переменные окружения:
* KEENETIC_USERNAME: Имя пользователя для роутера Keenetic (по умолчанию: admin)
* KEENETIC_PASSWORD: Пароль для роутера Keenetic (обязательно)
* KEENETIC_HOST: IP-адрес роутера Keenetic (по умолчанию: 192.168.0.1)
* KEENETIC_INTERFACE: Сетевая интерфейс для использования (по умолчанию: Proxy0)
- KEENETIC_USERNAME: Имя пользователя для роутера Keenetic (по умолчанию: admin)
- KEENETIC_PASSWORD: Пароль для роутера Keenetic (обязательно)
- KEENETIC_HOST: IP-адрес роутера Keenetic (по умолчанию: 192.168.0.1)
- KEENETIC_PORT: SSH-порт роутера Keenetic (по умолчанию: 22)
- KEENETIC_INTERFACE: Интерфейс, через который отправлять трафик (по умолчанию: Wireguard0)
## Пользовательский список CIDR
Скрипт включает заранее определенный список CIDR-блоков для YouTube. Вы можете изменить этот список в переменной CUSTOM_CIDR_LIST.
```python
CUSTOM_CIDR_LIST = [
"64.18.0.0/20",
"64.233.160.0/19",
"66.102.0.0/20",
"66.249.80.0/20",
"72.14.192.0/18",
"74.125.0.0/16",
"173.194.0.0/16",
"207.126.144.0/20",
"209.85.128.0/17",
"216.58.208.0/20",
"216.239.32.0/19",
"213.0.0.0/8",
]
```
## Функции
* cidr_to_netmask(cidr): Преобразует нотацию CIDR в маску подсети.
* fetch_cidr_list(url): Загружает список CIDR-блоков из указанного URL.
* add_route_to_keenetic(ip, netmask, gateway, username, password): Добавляет маршрут на роутер Keenetic.
* add_routes_to_keenetic(routes, gateway, username, password, max_retries=3): Добавляет несколько маршрутов с логикой повторных попыток.
* main(): Основная функция, которая управляет загрузкой и добавлением маршрутов.
Скрипт включает предопределенный список CIDR-блоков для YouTube. Вы можете изменить этот список в переменной CUSTOM_CIDR_LIST.
## Использование
@ -52,12 +38,26 @@ CUSTOM_CIDR_LIST = [
python3 update_routes.py
```
## Пример
## Логика работы
Чтобы использовать скрипт, установите необходимые переменные окружения и запустите его. Скрипт выведет статус добавления каждого маршрута:
- Скрипт загружает список CIDR-блоков из указанного URL.
- Объединяет загруженный список с пользовательским списком CIDR-блоков.
- Преобразует CIDR-нотацию в IP-адреса и маски подсети.
- Устанавливает SSH-соединение с роутером Keenetic.
- Для каждого маршрута:
- Удаляет существующий маршрут (если есть).
- Добавляет новый маршрут.
- В случае ошибки "Channel closed" повторяет попытку выполнения команды до 3 раз.
```text
Маршрут 64.18.0.0 с маской 255.255.240.0 успешно добавлен.
Маршрут 64.233.160.0 с маской 255.255.224.0 успешно добавлен.
...
```
## Обработка ошибок
Скрипт включает обработку ошибок для следующих ситуаций:
- Ошибки при загрузке CIDR-списка
- Ошибки при подключении к роутеру
- Ошибки при выполнении SSH-команд
- Повторные попытки при ошибке "Channel closed"
## Примечание
Убедитесь, что у вас есть необходимые права доступа к роутеру Keenetic для выполнения команд по SSH. Также проверьте, что указанный интерфейс KEENTIC_INTERFACE существует на вашем роутере.

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
requests
paramiko

View File

@ -1,15 +1,12 @@
#!/usr/bin/env python3
import urllib.request
import urllib.parse
import base64
import time
import paramiko
import os
import time
USERNAME = os.getenv("KEENETIC_USERNAME", "admin")
PASSWORD = os.getenv("KEENETIC_PASSWORD", None)
KEENETIC_HOST = os.getenv("KEENETIC_HOST", "192.168.0.1")
INTERFACE = os.getenv("KEENETIC_INTERFACE", "Proxy0")
KEENETIC_PORT = os.getenv("KEENETIC_PORT", 22)
KEENTIC_INTERFACE = os.getenv("KEENTIC_INTERFACE", "Proxy0")
CUSTOM_CIDR_LIST = [
# Youtube
@ -29,94 +26,83 @@ CUSTOM_CIDR_LIST = [
def cidr_to_netmask(cidr):
"""Преобразует префикс CIDR в маску подсети."""
try:
ip, prefix_length = cidr.split("/")
prefix_length = int(prefix_length)
# Создаем маску подсети из префикса
mask = (0xFFFFFFFF >> (32 - prefix_length)) << (32 - prefix_length)
netmask = ".".join([str((mask >> (i * 8)) & 0xFF) for i in range(4)[::-1]])
return ip, netmask
except ValueError:
raise ValueError("Неверный формат CIDR")
ip, prefix_length = cidr.split("/")
prefix_length = int(prefix_length)
mask = (0xFFFFFFFF >> (32 - prefix_length)) << (32 - prefix_length)
netmask = ".".join([str((mask >> (i * 8)) & 0xFF) for i in range(4)[::-1]])
return ip, netmask
def fetch_cidr_list(url):
"""Загружает список CIDR из указанного URL."""
with urllib.request.urlopen(url) as response:
return response.read().decode().splitlines()
import requests
response = requests.get(url)
response.raise_for_status()
return response.text.splitlines()
def add_route_to_keenetic(ip, netmask, gateway, username, password):
"""Добавляет маршрут на роутер Keenetic с использованием GET-запроса."""
url = f"http://{KEENETIC_HOST}/cgi-bin/luci/admin/network/routes"
params = {"ip": ip, "mask": netmask, "gateway": gateway, "interface": INTERFACE}
def execute_command(ssh, command, retries=3):
attempt = 0
while attempt < retries:
try:
stdin, stdout, stderr = ssh.exec_command(command)
error = stderr.read()
if error:
print(f"Ошибка: {error.decode()}")
return stdout.read().decode()
except paramiko.SSHException as e:
if "Channel closed" in str(e):
print(f"Channel closed detected. Retrying... ({attempt + 1}/{retries})")
attempt += 1
time.sleep(1)
else:
raise e
raise Exception(f"Failed to execute command after {retries} attempts: {command}")
# Кодируем параметры для URL
query_string = urllib.parse.urlencode(params)
full_url = f"{url}?{query_string}"
# Создаем запрос
request = urllib.request.Request(full_url)
request.add_header("Content-Type", "application/x-www-form-urlencoded")
def add_routes_via_ssh(routes):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Аутентификация
credentials = f"{username}:{password}"
base64_credentials = base64.b64encode(credentials.encode()).decode()
request.add_header("Authorization", f"Basic {base64_credentials}")
# Отправка запроса
try:
with urllib.request.urlopen(request) as response:
print(f"Маршрут {ip} с маской {netmask} успешно добавлен.")
return True
print("Connecting to Keenetic")
ssh.connect(
KEENETIC_HOST, port=KEENETIC_PORT, username=USERNAME, password=PASSWORD
)
print("Connected")
for ip, netmask in routes:
print(f"Добавление маршрута: {ip} {netmask}")
command = f"no ip route {ip} {netmask}"
execute_command(ssh, command)
command = f"ip route {ip} {netmask} {KEENTIC_INTERFACE}"
execute_command(ssh, command)
print("Все маршруты добавлены.")
except Exception as e:
print(f"Ошибка при добавлении маршрута {ip}: {e}")
return False
def add_routes_to_keenetic(routes, gateway, username, password, max_retries=3):
"""Добавляет маршруты на роутер Keenetic с повторными попытками."""
for route in routes:
ip, netmask = route
success = False
attempts = 0
while not success and attempts < max_retries:
success = add_route_to_keenetic(ip, netmask, gateway, username, password)
if not success:
attempts += 1
print(f"Попытка {attempts} для маршрута {ip}.")
time.sleep(2) # Задержка перед повторной попыткой
print(f"Ошибка при подключении или выполнении команд: {e}")
finally:
ssh.close()
def main():
url = "https://antifilter.download/list/allyouneed.lst"
if PASSWORD is None:
print(
"Для использования данного скрипта необходимо установить переменные окружения KEENETIC_USERNAME и KEENETIC_PASSWORD."
)
return
try:
cidr_list = fetch_cidr_list(url)
cidr_list.extend(CUSTOM_CIDR_LIST)
routes_to_add = []
# Генерируем маршруты
for cidr in cidr_list:
if cidr.strip(): # Проверяем, что строка не пустая
if cidr.strip():
ip, netmask = cidr_to_netmask(cidr.strip())
routes_to_add.append((ip, netmask))
# Добавляем маршруты пачками
add_routes_to_keenetic(routes_to_add, KEENETIC_HOST, USERNAME, PASSWORD)
add_routes_via_ssh(routes_to_add)
except Exception as e:
print(f"Ошибка: {e}")
# Пример использования
if __name__ == "__main__":
main()