На информационном ресурсе применяются рекомендательные технологии (информационные технологии предоставления информации на основе сбора, систематизации и анализа сведений, относящихся к предпочтениям пользователей сети "Интернет", находящихся на территории Российской Федерации)

artydev & Co

1 подписчик

Интеграция XRay (VLESS) в телеграм бота используя API Marzban

Делюсь способом интеграции ядра XRay (V2Ray) в телеграм бота с использованием системы marzban

img

Новый протокол подключения

Ряд последних событий тонко намекает на то, что использование VPN в РФ с каждым днем будет только усложняться. К очередной блокировке нужно быть готовым заранее, поэтому добавим новый протокол VLESS на базе ядра XRay (V2Ray) в телеграм бота.

Полученный результат можно посмотреть в этом боте:

https://t.me/artydev_wg_payment_bot?start=xray

Немного теории

V2Ray, V2Fly, XRay (VMess, VLESS, XTLS)

XRay - это форк V2Fly, когда некоторые разработчики из-за ряда разногласий с остальным сообществом ушли из проекта V2Fly и продолжили развивать код параллельно под названием XRay, придумав ему слоган “Penetrates everything”, что очень недалеко от правды.

Формат конфигурационных файлов остался прежним, но при этом новая реализация считается более эффективной в плане производительности, а самое главное - разработчики добавили туда несколько очень крутых фич, направленных в том числе на снижение детектируемости подключений на DPI (например, с помощью выявления TLS-in-TLS), таких как XTLS, речь о которых пойдет ниже.

V2Ray/XRay - это не протокол, а, можно сказать, фреймворк - разные протоколы с разными транспортами и расширениями под одной крышей в одном приложении. Идея простая: что клиент, что сервер - это один бинарник. В конфигурации задаются inbounds (обработчики входящих подключений) и outbound (обработчики исходящих подключений).

На клиенте inbound обычно будет работать как HTTP- или SOCKS-прокси сервер, принимая подключения от браузеров и других программ, а outbound будет настроен как клиент какого-нибудь прокси-протокола для подключения к удаленному серверу.

VLESS - это более новый протокол. В отличие от VMess он не предусматривает механизма шифрования (подразумевается, что шифрование должно производиться нижележащим транспортным протоколом, например TLS), а только проверку “свой/чужой” и паддинг данных (изменение размеров пакетов для затруднения детектирования паттернов траффика).

В протоколе исправлен ряд уязвимостей старого VMess, и он активно развивается - например, автор планирует добавить поддержку компрессии алгоритмом Zstd - не сколько для производительности, сколько для затруднения анализа “снаружи”. При этом, при установлении соединения (хендшейке) клиент и сервер обмениваются версией протокола и списком поддерживаемых фич, то есть при дальнейшем развитии должна сохраняться обратная совместимость. В общем и целом, на сегодняшний день это самый свежий и прогрессивный протокол.

Источник: https://habr.com/ru/articles/727868/

Интеграция

Далее я покажу на базовом примере, как можно организовать выдачу ключей для подключения через VLESS.
Допустим у вас есть телеграм бот, в котором вы генерируете ключи для ваших пользователей, ваш код выглядит примерно так.
Ниже очень упрощенный пример, если у вас уже есть бот - вы сможете адаптировать его под свою реализацию.

class MarzbanBackend:     def __init__(self):         self.session = requests.Session()         self.headers = {"accept": "application/json"}         self.base_url = S.MARZBAN_API_URL         if not self.headers.get("Authorization"):             self.authorize()     def _get(self, path: str) -> dict:         url = f"{self.base_url}/{path}"         response = self.session.request("GET", url, verify=False, headers=self.headers)         if response.status_code == 200:             return response.json()     def _post(self, path: str, data=None) -> dict:         url = f"{self.base_url}/{path}"         if not path == "api/admin/token":             data = json.dumps(data)         response = self.session.request("POST", url, verify=False, headers=self.headers, data=data)         if response.status_code == 201 or response.status_code == 200:             return response.json()     def _put(self, path: str, data=None) -> dict:         url = f"{self.base_url}/{path}"         json_data = json.dumps(data)         response = self.session.put(url, verify=False, headers=self.headers, data=json_data)         if response.status_code == 200:             logger.info(f"cmd xray PUT {path}, data: {data}")             return response.json()         else:             logger.error(f"cmd xray PUT not 200 status_code! {path}, data: {data}")     def authorize(self) -> None:         data = {             "username": S.MARZBAN_USER,             "password": S.MARZBAN_PASSWORD         }         response = self._post("api/admin/token", data=data)         token = response.get("access_token")         self.headers["Authorization"] = f"Bearer {token}"     def create_user(self, name: str) -> dict:         data = {             "username": name,             "proxies": {                 "vless": {                     "flow": "xtls-rprx-vision",                 },             },             "inbounds": {                 "vless": ["VLESS TCP REALITY"],             },             "data_limit": 15 * 1024 * 1024 * 1024,             "data_limit_reset_strategy": "day",         }         response = self._post("api/user", data=data)         return response     def get_user(self, name: str) -> dict:         response = self._get(f"api/user/{name}")         user = response.get("username")         status = response.get("status")         logger.info(f"get user: {user}, status: {status}")         return response     def disable_user(self, name: str) -> dict:         data = {             "status": "disabled"         }         response = self._put(f"api/user/{name}", data=data)         if response:             logger.info(f"Disable xray user: {name} success, {response.get('username', 'unknown username')}")             check = self.get_user(name)             if check.get("status") != data.get("status"):                 logger.error(f"After disable user {name}, user is not disabled!")             return response         else:             logger.warning(f"xray user {name} not found")             return {}     def enable_user(self, name: str) -> dict:         data = {             "status": "active"         }         response = self._put(f"api/user/{name}", data=data)         if response:             logger.info(f"Enable xray user: {name} success, {response.get('username', 'unknown username')}")             return response         else:             logger.warning(f"xray user {name} not found")             return {} 

Хотелось бы обратить ваше внимание на функции create_user() и disable_user(), рассмотрим каждую из них подробнее.

В функцию create_user() я не передаю параметр expire, так как в боте используется несколько протоколов и уже существует логика управления пользователями через включение-выключение доступа (функции enable_user(), disable_user()).
Но если у вас новый бот и вы не используете другие протоколы - управление через expire выглядит хорошим вариантом.

В функции disable_user() реализована дополнительная логика на проверку отключения в следующем виде:

time.sleep(0.25) check = self.get_user(name) if check.get("status") != data.get("status"):     logger.error(f"After disable user {name}, user is not disabled!") 

В данный момент сталкиваюсь со случаями, в которых успешно меняется статус, но в панели Marzban пользователь остается со статусом “active”.
Пока этот вариант используется для отладки, если баг будет сохраняться - можно будет сделать рекурсивный вариант внутри функции.

После создания пользователя необходимо отдать ему ссылку на подписку, которая формируется функцией create_user(), ключ: subscription_url, если вы не планируете полностью использовать API Marzban для доступа к данным сервера - то результат (данные о пользователях) лучше сохранять в своё отдельно хранилище, например postgresql, с которой взаимодействует бот.

Список проверенных хостеров

  • aeza - бонус 15% к пополнению баланса
  • veesp
  • 4vps - 20% к первому пополнению или скидка 20% на первый заказ
  • vdsina - скидка 10%
  • inferno-solutions + скидка 25% на первый платеж, промокод: artydev
  • pq-hosting

Итог

Результаты подключения протокола VLESS можете посмотреть в моём боте.
Cсылка: https://t.me/artydev_wg_payment_bot?start=xray

Также рекомендую к прочтению:

На пиво

Если данный материал оказался вам полезен - готов принять ваши копеечки :)

в крипте:
USDT (BEP20): 0xcdc3231527a1ad105d527678ccbcf5e827747e7b
ETH (ERC20): 0xcdc3231527a1ad105d527678ccbcf5e827747e7b
TON: UQAiIMLC2_j9tPlmQakdbz2Zh0rkTHH7tK2RTcO3rYAkr8QV

в рублях: https://pay.cloudtips.ru/p/2a3d8e06

Большое спасибо всем за внимание! Если вам интересны подобные рассуждения - подписывайтесь на мой канал  artydev & Co.

Ссылка на первоисточник
наверх