create routes via ssh
This commit is contained in:
162
.gitignore
vendored
Normal file
162
.gitignore
vendored
Normal 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/
|
82
Readme.md
82
Readme.md
@ -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
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
requests
|
||||
paramiko
|
122
update_routes.py
122
update_routes.py
@ -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()
|
||||
|
Reference in New Issue
Block a user