Pull to refresh

Comments 187

Интересная реализация, захотелось готовый пакет под OpenWRT!

Насчёт OpenWRT не знаю — у меня TomatoUSB + Entware — и там есть проблема в том, что пришлось вручную ребилдить OpenSSL, потому что Entware не поставляет libssl/libcrypto.a… Что ломает, например, OpenSSH, который хочет строго ту же версию, с которой слинкован. Нет, по хорошему надо было разворачивать кросскомпайл на компе, но мне было лениво — проще было билд делать на самом роутере =)

Спасибо за статью.
Но ядро 2.6 в 2021-м?

Откройте для себя:
1. FreshTomato — свежий томатоюсб. И как вы на него не наткнулись в сети?
2. Openwrt — монстр, свежайшее ядро 5.х. Можно собрать звездолет.

У меня как раз FreshTomato =) я имел ввиду что база TomatoUSB, не уточнял просто конкретно какая подверсия =).
С OpenWRT проблема в том, что под него нет аппаратного ускорения под broadcom-овские чипы.

А ещё прикольнее поставлять в виде коробки raspberry pi, чтобы подарить можно было :)

Этакая "антироскомнадзоровская" коробочка? =) Как сам РосКомНадзор ставит свои у провайдеров, так и мы у обычных людей =)
Проблема тут в том, что под каждого провайдера приходится адаптировать. Как ни странно, https садаптировать проще, поскольку там явно "не тот" сертификат. А вот с http каждый городит что хочет…

число провайдеров конечное (и небольшое), можно со временем собрать конфиги для каждого

С автодетектом провайдера и подтягиванием конфига с сервера конфигов под данный провайдер.

Притом соединение к серверу придется проксировать всегда, а сам сервер ставить где-то в Нидерландах, иначе заблочат

Эстония, Нидерланды, Гонконг.
В мире достаточно стран, в которых блокировки практически не применяются.
В общем случае достаточно «чёрного списка» доменов, внезапный редирект на которые — признак блокировки. Не обязательно делать индивидуальные конфиги. Поиск домена в hash table даже на несколько сотен записей должен работать очень быстро по сравнению с сетевыми задержками.

Можно сделать универсальный вариант — сравнивать тип ответа с физического порта и туннеля, всегда использовать туннель при несовпадении.
Это, кстати, решит проблему с провайдерами, которые просто блекхолят трафик без предупреждения. Таких не мало.

Ну для такого варианта кэширование уже надо рассматривать. Потому что каждый раз сверять два подключения слишком накладно))
Это будет «Программно-аппаратный комплекс защиты информации, обеспечивающий повышенную доступность услуг связи по выходу в сеть „Интернет“ к корпоративным
и иным ресурсам с целью расширения конкурентного присутствия, в условиях непрерывных и постоянно меняющихся технических и юридических помех со стороны, в том числе, третьих лиц. » (с)
UFO just landed and posted this here

Субъективно — можно сильно упростить решаемую задачу, если завернуть кеширующим резолвером (тот же dnsmasq) весь DNS-трафик за пределы родины с помошью DoH/DoT.


При этом подключение будет осуществляться непосредственно к заблокированному IP, в результате будет обычный и одинаковый для всех отлуп по TCP без таймаута (разумеется, если речь идет не про открытый http, а про tls или что-либо, что провайдеры не умеют/не считают нужным MiTM-ить).


Ну, и есть минус — заворачивание всего DNS наружу может ломать логику CDN в ряде случаев, но это почти полностью проблемы провайдера (за исключением ПО, сильно чувствительного к задержкам).

Тот же Мегафон, над которым я упражнялся выше, никак не трогает DNS трафик, и IP из DNS-а приходит вполне легитимный. Перехват осуществляется уже на базе запрашиваемого IP. Даже для linkedin.com.
Так что DoH тут бы не помог совсем никак.

Мегафон — да, но есть провайдеры, с которыми достаточно просто настроить DoT на роутере.

Это вариации на третий метод "чёрной магии", проблемы с которым обычно "сегодня работает, а завтра провайдер обновил dpi софт и всё отвалилось". Если работает DoH — вам вообще сильно повезло, это наверное вообще самое простое решение этого вопроса...

Вот если бы это упаковали в докер, то было бы вообще супер. Для dоh\dot прекрасно работает pihole или adguardhome

В принципе идея неплоха, но изначально делалось всё для достаточно маломощного устройства со старым ядром, на котором Docker не поднять (в смысле, роутера с 2.6.36, тогда как Docker требует минимум 3.10 и хотя бы 512 МБ оперативки). Ну и плюс требуется ручная адаптация под своего провайдера всё равно.
lua-struct для парсинга бинарных пакетов (в частности, поиска сертификата после ServerHello).

С версии Lua 5.3 функционал lua-struct встроен в луа в виде функций string.pack и string.unpack.


Я даже написал апгрейд для них(lua-advanced-string-pack) который позволяет читать массивы и сложные структуры.

OpenResty использует LuaJit, ограниченный версией 5.1. К сожалению string.pack/unpack в нём нет — я специально проверял — собственно первой попыткой была реализация через них. Поэтому пришлось использовать lua-struct.
UFO just landed and posted this here
Это особенности национального лобби развития Hi-Tech технологий.

Мало подобрать семена, надо еще пропалывать и поливать огород.
А так-же травить вредителей.

А так-же травить вредителей.

Вот тут с Вами кое-кто даже согласится, да… К сожалению, буквально.
Мне казалось, они давно уже сами себя выбирают
Для этого должно соблюдаться несколько условий:
1) Нормальность депутатов (любой кандидат может всячески изображать нормального до выборов, а потом «переобуться», как только его изберут)
2) Допуск этих самых «нормальных» депутатов до выборов
3) Отсутствие возможности подтасовки результатов выборов (я лично не знаю способов проверки, что бюллетени не подвергались модификации, а также не подвергалось модификации ПО и оборудование, подсчитывающее эти самые бюллетени. Если будет какой-то математически доказуемый способ по типу блокчейна — тогда другое дело)
4) Отсутствие подкупной массовки, оставляющей «нужные» голоса (путём каких-либо бонусов, угроз или шантажа)
5) Политически активное население, желающее голосовать за «нормальных депутатов» в противовес «стабильности», «духовных скреп» и прочего.
Возможно, это даже не все пункты (перечислил только те, что быстро пришли в голову). Если хотя бы один пункт будет нарушен — то вся идея выбора «нормальных депутатов» пойдёт коту под хвост, ибо перевес будет за стороной, имеющей возможность манипуляции голосами.

Может и минусов наловлю, но:
Где ваши "нормальные" депутаты от оппозиции? Всё более-менее известные, уж извините, какие-то фрики. Вот мне, обычному человеку, какая от них польза, что они толкают? Хайп и свои шкурные интересы? Приведите пример путнего законопроекта от оппозиционного депутата, который как-то повлияет/улучшит жизнь простого гражданина?

Вам какой оппозиции? Если несистемной, то можно посмотреть где-нибудь здесь. Если системной, то тут сложнее, но можно посмотреть где-нибудь здесь.

Посмотрел ваши ссылки, ну такое, если не ошибаюсь 2 было про пенсионный возраст, а остальное вообще меня никак не касается, но вот это мне понравилось 722042-7 закон о чистоте пива))))
А минусов насували как будто я написал, что Путин бог, а навальный лох))))

У вас не было условий про «касается лично меня», вы просили про «пользу для обычного человека».

Опять же в первом случае вы скинули ссылку на инициативы несистемной, а во втором случае на законопроекты системной и вам не кажется что, инициатива и законопроект это довольно таки разные вещи? Инициатива про пешеходный переход меня вообще не касается, а законопроект о публичных мероприятиях частично, т.к на шествия и пикетирования я не хожу, а вот на публичных мероприятиях могу присутствовать.
Уж извините, что ответил с задержкой, на калыме заработался и не до интернетов было.

Если бы вы посмотрели внимательнее, то увидели бы что в некоторых инициативах там есть готовые законопроекты.

Что касается «меня не касается» то этого не было в изначальных условиях.

Несистемная оппозиция любит за чужие слова цепляться, однако за свои слова не привыкли отвечать. Значится так, вы меня сразу упрекнули "за не точность формулировки", так и вы тоже перепутали гражданскую инициативу с законопроектом) я вроде и провластный, но сдругой стороны люблю чужое мнение выслушать, но вы так его подаёте, хех.

Я ничего не путаю, просто вы не хотите читать то, что пишет вам собеседник. Открываете, например, вот эту инициативу и видите в аттаче готовый текст законопроекта.

Это хорошо, что гражданская инициатива переросла в законопроект. Но вы вообще, первое перечитайте сообщение.

Она не переросла, а сразу была представлена в виде законопроекта. Набрала сто тысяч подписей и была завернута.
UFO just landed and posted this here
PS: что мешает ресурсу бороться с ботами?
А причем тут боты? Голосовать могут только полноправные пользователи с кармой ≥ 5.
А причем тут боты? Голосовать могут только полноправные пользователи с кармой ≥ 5.

боты тоже бывают полноценными узерами

«Путние» законопроекты пишут текущие депутаты, зачем оппозиции заниматься тем же самым? (:

Да можно и без дапутатов, просто заменить их на котиков. Получится, что раньше от каждого депутата был вред, а теперь хоть пользы котик не приносит, но и не вредит. Так что получаем строгое улучшчение ситуации.

Отзыв депутата нужен.
Такая возможность создаёт другую проблему. Так можно отозвать нормальных депутатов.
Под нормальными я понимаю тех, кто против бредовых законов и обращает внимание на реальные проблемы.

Их и так снимают с должности.

UFO just landed and posted this here

Ещё одно есть условие, с которым не ясно, что делать — компетентность избирателей. Фактически получается, что большинство не способно на осознанный выбор потому, что кухарка, слесарь или программист не могут управлять государством, так как не имеют специальных знаний и следовательно не способно правильно оценить кандидатов. Некомпетентность приводит к тому, что избирателя обманут в любом случае. Не намухлюют с голосами, так обманут честным путем при помощи отработанных технологий из рекламного бизнеса. А редкое мнение понимающих все равно потонет в массе облапошенных.

Я не думаю что мне нужны какие-то специальные знания чтобы понять, хорошо управляют государством или нет. Это как с молоком — сам корову я подоить не смогу, но отличить кислое молоко от нормального смогу запросто.


Пример — в Новосибирске не вывозят мусор и не чистят снег уже десять тысяч лет, а каждую весну/осень город стабильно затапливает. Какой вывод можно из этого сделать?

Какой вывод можно из этого сделать?

что это место проклято? :-)

что это место проклято? :-)
Именно :)

Если, как с молоком, то для определения явных проблем с качеством, особых знаний не надо, но дальше надо определять, кто виноват и что делать. Виноват молочник, виноват форсмажор. Еще интересный вариант, у вас не кислое, а у соседа кислое — уже три варианта, молочник, форсмажор, сосед. Может он в холодильник не поставил, а валит на молочника, а может правду говорит, а может он безграмотный и не знает, что делать с молоком, но он требует сменить молочника. Что делать в таком случае без понимания приемов обращения с молоком. Потом, дальше, решили менять, пришел мужик — говорит, что молочник, надо как-то понять квалификацию и оценить независимость от отдельных производителей молока. Первое надо сделать умея только пить молоко. Для второго надо быть чуть ли не следователем с полномочиями проверять счета в банках и осуществлять слежку.

Если молочник доставляет мне прокисшее молоко то совершенно пополам почему и что там у него случилось. Его надо менять. А если молоко хорошее то какая разница что говорит сосед. Ему не нравится и пусть меняет.

Вот вы всё за меня ответили :) да, всё верно.


Я согласен с тем, что у представительной демократии куча минусов, но она точно лучше чем когда к выбору депутатов допускают лишь часть граждан, или вообще никого.

Если у большинства людей молоко скисает, то молочник таки виноват. Мог бы большими буквами писать, что молоко надо ставить в холодильник, например. Либо пожертвовать экологичностью и добавить консерванты, раз большинству категорически не подходит вариант хранения молока в холодильнике.

Только в случае с молочником, если он не монополист, то рынок решит проблему сам. А власть обладает монополиями во многих сферах, так что тут всё не так просто.
так обманут честным путем при помощи отработанных технологий из рекламного бизнеса

Это уже большой шаг вперёд. Какой бы не была лживой реклама, в конечном счёте вы получаете какой-то товар, который хотя бы формально соответствует заявленным характеристикам. Гораздо хуже, когда вы не получаете вообще ничего, либо прямо противоположное.
В наше время нынешняя гос. система в виде парламента уже не имеет смысла.

Она работает как «испорченный телефон» в информационном направлении Регион>Область>Москва и как «система ниппель» в обратном, материальном направлении.

Зачем нужна армия посредников в виде депутатов «выражающих суверенную волю народа» если сейчас практически у каждого есть смартфон и возможность напрямую осуществлять свою власть непосредственно как гласит 3 статья конституции.

На самом деле стране нужны не «нормальные» депутаты, а идейные ITшники для объединения воли народа и реализации честных выборов через технологию блокчейн.
По опыту блокировка может прийти и на уровне магистрального провайдера. Я так понимаю такой вариант не рассматривается?!
Никто не мешает расширить логику для отслеживания отлупа и от магистрального провайдера. Вполне можно проверять по сколько угодно большому количеству меток блокировки. Если наткнусь на такую блокировку на своём провайдере, проапдейчу и скрипт, но пока что у меня нету примера.
Чуть обновил nginx.conf, поправил зависания при ошибках соединения.

В свете того, что скоро придёт замедление вместо блокировки — ИМХО более перспективно заворачивать всё в VPN поверх HTTPS с белыми списками IP, которые туда не пойдут.

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


А весь остальной не-игровой траффик — только через VPN. Причём по возможности — self-hosted. Просто считайте, что ежемесячная стоимость работоспособного интернета выросла примерно на $5 (которые стоит сервер для VPN) — налог на РКН.

Практически готовый список префиксов есть в базе RIPE NCC и достаточно завернуть трафик до делегированных в RU мимо тоннеля.

В теории есть неплохая схема с универсальным обходом блокировок на основе geo-ip.


Если исходить из того, что все заблокированные сайты хостятся вне РФ, то можно все geo-RU адреса маршрутизировать напрямую, а зарубежные — отправлять в VPN (нужен хороший vpn по скорости и расположению)


Плюсы: маршруты не будут удлинняться; универсальность способа


Минусы: в vpn уходит много пока ещё не заблокированного и не замедленного трафика; есть единичные случаи достаточно популярных сайтов, которые давно заблокированы, но их удивительные админы продолжают хостить сайт в РФ (например lostfilm.tv)

Мой выбор это


  1. самый дешёвый vps в Европе
  2. DoH на роутере
  3. wireguard для подключения и шифрования
  4. socks5 proxy для перенаправления только конкретных ресурсов
  5. плагин для браузера для быстрого добавления/исключения ресурсов

Как выйдет релиз routeros с поддержкой wg, можно будет избавится от VPN клиента на машине и возможно что то получится придумать с проксированием на уровне роутера

Проблема в том, что ваш вариант жёстко ограничен браузером.
Давно перешёл на 7.1 из development ветки ради wg. Всё отлично работает.
Можно я замахнусь немного на холивор? =) Почему такая любовь к Wireguard? Нет, я понимаю, что OpenVPN тормознутый, но есть ещё SSTP. У него есть один сильный плюс — он для систем DPI ничем от HTTPS не отличается, тогда как у того же Wireguard и свой протокол шифрования (причём завязанный всего на один единственный вариант), и UDP, который в некоторых местах вообще может быть заблокирован (например, на особо параноидально настроенных публичных WiFi хотспотах), и фильтровать его тоже проще если вдруг чего…
Может для постоянного коннекта он и неплох, не знаю (у меня SSTP работает вполне шустро — шустрее того же OpenVPN-а), но для всего остального… Ну, не знаю.

Холивора не получится. Я вот в первый раз услышал про SSTP (что не удивительно, учитывая что он принадлежит M$, а я их продукты не люблю), но уже вполне в состоянии ответить на вопрос "почему не":


1. Есть. =) SoftEther VPN вполне нормальная реализация, которой я пользуюсь уже годами =) И OpenSource под более чем адекватной лицензией. И клиенты тоже есть.
2. Ну, это верно, под MacOS придётся собирать клиент, про iOS не знаю, но наверняка есть какой-то сторонний клиент. С другой стороны я понятия не имею, работает ли на этих устройствах из коробки Wireguard. А вот SSTP из коробки работает на Windows.
3. Сам SSTP протокол полностью открыто описан, и по сути является обёрткой над давно всем известным PPP с минимальными добавлениями и завёрнутым в HTTPS, так что ничего нового в нём нет. Ну и этак можно сказать что GitHub принадлежит MS, а значит от него тоже надо держаться стороной =) Современная MS совсем не та MS что была раньше.

SoftEther это немного другая история — он поддерживает кучу протоколов, поэтому неясно, а чего ради из них всех предпочитать именно SSTP.


WireGuard есть примерно вообще под всё: https://www.wireguard.com/install/


Волк может натянуть овечью шкуру, но останется волком.

Из-за его возможностей по прохождению там, где остальные не проходят, прикидываясь обыкновенным HTTPS трафиком, и при этом, опять таки, наличие клиентов почти подо всё (благо они преимущественно open source, а значит пересобрать не велика проблема, плюс базируются на давно известном и реализованном везде PPP) =)
Но продолжать не буду, рассуждения о волках и овечьих шкурах — это уж совсем субъективный холивор. =)

А разве при использовании SoftEther эта фича с VPN over HTTPS работает только при использовании SSTP? Мне почему-то показалось, что это фича самого SoftEther, так что полагаю ещё какие-то из поддерживаемых им протоколов должны такое уметь.

Вы правы, свой родной протокол SoftEther-а вполне себе делает примерно то же самое, но вот под него найти клиенты на что-то, кроме Windows/Linux/MacOS у вас не получится. В этом плане SSTP гораздо более распространён.
UFO just landed and posted this here
На самом деле достаточно интересный вариант, просто я с AnyConnect-ом познакомился недавно =) А документация на его протокол в открытом доступе, тоже? Или это плод реверс-инжиниринга?
UFO just landed and posted this here
Несколько отличается от SSTP, где документацию на него опубликовали непосредственно сами MS =) Как к этому сама Cisco отнеслась, не знаете?
UFO just landed and posted this here

Да отстаньте со своим вайргардом — оно хипстерская поделка и ближайшие лет пять ею и останется. А там, глядишь, что нового и изобретут

Главное достижение WireGuard — он показал, что настройка и реализация VPN могут быть очень простыми и при этом более чем эффективными. Остальным VPN (особенно будущим) теперь придётся конкурировать с учётом этого. И за это WireGuard большое спасибо. А в остальном, WireGuard или что-то другое — не так уж и важно.

OpenVPN накатывается вообще одним скриптом в два клика. Но у всех этих протоколов и правда беда с отсутствием обсфукации, а блокировки VPN уже анонсировали.

Поэтому тут или SoftEther какой, или заворачивать WireGuard (или другой протокол) в shadowsocks. Второй вариант более универсален потому что shadowsocks есть и под OpenWRT, а с SoftEther там все не так однозначно было когда я последний раз интересовался.
Там идет речь именно про блокировку конкретного VPN сервиса.
Там двояко можно прочитать:
А если начнется „цепная реакция“, и пользователи массово попытаются обходить обсуждаемую блокировку Twitter с помощью VPN-сервисов, дальше начнутся блокировки доступа уже к ним

Но с учетом того что речь идет о том, что они научились на блокировках Телеграм, а возможность блокировать конкретные VPN сервисы была уже и тогда, то мне кажется что речь идет именно о блокировке протоколов через DPI, которые установили в рамках «суверенного рунета» и сейчас применяют для замедления Twitter.

Проблема вовсе не в том, в сколько кликов оно накатывается. Проблема в тьме доступных настроек, которые временами приходится подкручивать, потому что иначе возникают разные проблемы. Проблема в том, что без вникания в настройки нет уверенности, что настроено "в два клика" оно корректно и безопасно (и зачастую оказывается, что это не так). Всё это создаёт (излишнюю, как показал WireGuard) сложность.

Всё это создаёт (излишнюю, как показал WireGuard) сложность.

я в это не верю. Потому что по Вашей логике получается, что или WireGuard работает (повезло), либо не работает и возможности починить его не будет. Хотя тут, наверное, должны быть попросту мощные инструменты диагностики. Но я все равно могут придумать какой-нибудь /высосанный из пальца, конечно же/ кейс, когда какая-нибудь настройка типа MTU сломает WG. Либо WG настоль крут, что у него внутри сложная логика "сделай мне хорошо", но если так, то мы прекрасно знаем как любая сложная логика ломается о реальность :-/

Ну, фишка в том, что он "просто работает". Магия-с. :)


На практике я сталкивался с двумя ситуациями, когда он не работал. И хотя может показаться, что это противоречит первому предложению, на самом деле это не так, или не совсем так — потому что ситуации слишком специфические.


В первой ситуации я обнаружил, что в кафе на их WiFi он не подключается, а через мобильный инет работает. Дома на WiFi проблем никогда не было. Очевидно, что тут скорее проблема в настройках инета в кафе, может там файрвол какой или ещё что-то, но разбираться с этим с телефона было слишком неудобно, так что реальную причину я не знаю (если, например, они тупо блокируют всё, кроме HTTP, то это сломает абсолютное большинство VPN, и я не склонен расценивать это как проблему "недостаточной сложности" WireGuard).


Во второй ситуации было интереснее — периодически подвисало VPN-соединение, и помогал только его перезапуск. Здесь уже это происходило в обычных условиях между двумя стационарными серверами (но находящимися в разных странах). Я частично выяснил в чём проблема: пакет от клиента приходит на сервер, сервер на него отвечает, но вот этот ответ уже до клиента не доходит. Причём наблюдается эта проблема только для этой пары портов отправителя/получателя и возникает после передачи довольно большого объёма данных. Отправка с другого порта сервера пакета на порт клиента — проходит. Соответственно, после перезапуска VPN меняется порт клиента, и проблема уходит. ISP клиента говорит, что никакой фильтрации у них которая могла бы это вызвать — у него нет. Соответственно, я пока грешу на какой-то ISP по дороге и/или баг вроде этого: Как мы раскрыли 24-летний баг в ядре Linux. В целом, на проблему самого WireGuard это так же не похоже.

UFO just landed and posted this here

Разумеется, я имел в виду HTTP+HTTPS. И да, упомянутые работать будут. Только вот они намного менее распространены нежели OpenVPN или IPSec, которые тоже в таких условиях не смогут работать не смотря на всю свою сложность.

IPSEC IKEv2 — работает из коробки везде
А есть книжка — настраиваем IKEv2 без SMS и регистрации за 21 день? :)
На моём андроиде, кстати, его из коробки нет.
На моём андроиде, кстати, его из коробки нет.

не верю :-) даже на самом китайском андроиде есть IKEv2 или какой-нибудь IPsec. Проверьте, пожалуйста, еще раз


настраиваем IKEv2 без SMS и регистрации за 21 день?

хорошая шутка, оценил

не верю :-) даже на самом китайском андроиде есть IKEv2 или какой-нибудь IPsec. Проверьте, пожалуйста, еще раз

Не буду делать скриншот, но есть:
PPTP, L2TP, L2TP/IPSec PSK, L2TP/IPSec RSA, IPSec XAuth PSK, IPSec XAuth RSA, IPSec Hybrid RSA.
Именно IKEv2 нету. Пользуюсь как раз «каким-нить» IPSec

Старые версии Android шли без IKEv2. Насколько могу понять по исходникам, в AOSP вообще только в 9 версии добавили IKEv2.

У меня в девятке IKEv2 тоже отсутствует. Впрочем strongswan вполне себе это исправляет.
Я только на микротике его могу :)
Если нет то надо ставить клиент (на моём есть :) )
Как вспоминается попытка разобраться в strongswan, в середине выясняется, что надо пилить конфиги под libreswan, потом повисает в воздухе пара лишних зависимостей…

Или опенвпн — удостоверяющий центр подними, ключей нагенери, конфигов наделай. Некоторые простые варианты конфига в актуальных версиях уже не работают — требуют усиления TLS, это дополнительно ключи делать.

Wireguard — конфиг в десяток строчек и несколько команд для установки почти под чем угодно (microtik ждём).

А по простоте поднятия вообще SSH SOCKS прокси рулит, но нужна ручная работа для установки соединения.
Wireguard — конфиг в десяток строчек и несколько команд для установки почти под чем угодно (microtik ждём).

да-да-да, удачи его настроить, когда wireguard обновит шифры и клиент со "старым" wg не сможет работать работать с "новым" wg.
Тот же IPsec решает проблему тем, что он есть везде в каком-бы то ни было виде и можно подобрать набор совместимых параметров, но это же и проблема, т.к. его нужно подбирать иногда, а это превращается в научный тык.


История с энфорсингом свежих версий (как сейчас с TLS) хороша только тем, чтобы держать разработчиков софта "в тонусе" и не происходило https://en.wikipedia.org/wiki/Protocol_ossification

согласен, что IPsec решает. Проблема в удобстве настройки.
В маршрутизаторе делается при помощи стандартного функционала, но вот поднять весь стэк на голом линуксе задачка достаточно развлекательная.

Опять же — уже больше год вполне себе успешно живу с Wireguard, ничего не отваливалось. что я сделал не так?

Более того, со своим бэкграундом я слишком сильно долго настраивал WG, потому что искал дополнительную информацию, что и как там реализовано, потому что НУ НЕ МОЖЕТ БЫТЬ ТАК ПРОСТО, Я ЧТО-ТО УПУСКАЮ!

Я вот не понял, это что, извращённый аргумент из серии "не исключено, что вам придётся когда-нибудь в будущем помучаться с этим простым инструментом, поэтому давайте вместо этого продолжать мучиться сегодня со сложным"?

Писал в поддержку MikroTik просьбу/предложение добавить в качестве туннеля соединение по ssh. Не ответили. А было бы удобно.
Отвечу про SSTP. У него главный недостаток — TCP. Для туннелей это очень неправильно. HOL, потери пакетов и всё такое. В целом жить можно, но если связь не очень хорошая, то начинают сильно эскалироваться проблемы. Ну и накладные расходы из-за этого выше.
Читал, что проблема сильно переоценена, и TCP вполне способен самосадаптироваться для таких условий.
… Но втихую надеюсь на HTTP3/QUIC, что его тоже будут пропускать везде, и вот тогда и туннели можно будет тоже пустить маскируясь под него =)
Он концептуально не может некоторые вещи сделать. Представьте разговор по условному Скайпу. Потерялся пакет — ну и фиг с ним, собеседник чуть хрюкнул, а тут поставится всё на паузу, пока повторный не придёт. Т.е. все ситуации, где UDP вводят ради скорости, ценой допустимых потерь — начинают вести себя плохо.
Тут можно ещё добавить, что в одном TCP-потоке множество соединений и страдать будут все.
А вот если реально плохая связь, то там может очень сильно всё нарастать (ретрансмиты внутри и снаружи туннеля).
Но вот то, что снаружи это фактически HTTPS (хотя и с неестественным профилем трафика) — это огромный плюс. Ну и второй плюс, что из-за этого, это самый стабильный VPN, пролезающий через любые наты.

А с HTTP3, боюсь, что к тому времени в России просто запретят UDP, как нежелательный протокол :)
Для туннелей это очень неправильно

неправильно, но проблема как будто преувеличена. Вы ведь про TCP meltdown problem?
Есть и критика раздувания проблемы — http://samag.ru/archive/article/603

Ну, автор статьи тоже радует :) А если в такой туннель завернуть ICMP, то и мониторинг внешних ресурсов также будет стабильнее. Давайте заменим один протокол другим, чтобы было стабильнее. А может сразу тогда использовать другой?
В общем, у автора свое видение проблемы, а тесты у него уж очень прямолинейные.
Единственным минусом такого подхода является то, что в случае, если Мегафон начнёт поддерживать eSNI, то коннекты к его сайту будут проксироваться, но пока что SNI у него вполне незашифрованный.

eSNI, к слову, уже deprecated (из Firefox даже уже и выпилили), будущее за ECH, где ClientHello шифруется целиком.
Это принципиально расклада не меняет, на самом деле. В любом случае ни мы, ни провайдер не получаем информацию о хосте, к которому клиент подключается, и придётся проверять собственным TLS-Handshake-ом. И анализировать полученный сертификат — или даже, быть может, те данные которые он пытается отправить внутри TLS-а.
Эх… Во всей этой ситуации с блокировками провайдер по факту тоже сторона пострадавшая. Это я про заголовок.
Тем не менее, не слышно громкого возмущения провайдеров, они покорно вставляют себе швабру в задний проход и лишь иногда слабо пищат, когда черенок особенно сучковат.

Автор, не пробовал то же самое сделать на envoy? Его механизм фильтров как будто аналогичен nginx и учитывая, что envoy написан буквально недавно и уже активно используется в высокопроизводительных service mesh — возможно будет хорошим выбором. Я даже читал, что к нему можно модули на wasm делать, но это не точно 


Правда, если это неверно, и вы отправляете запросы, что-то меняющие на удалённом сервере, то тут беда… Прилетит по итогу два запроса — один — тот на который заблокирован ответ, и второй — спроксированный.

если все-таки влезть в L7 каким-то образом (ну, не знаю — свой сертификат сделать и полноценный DPI), то можно будет разделить идемпотентные запросы от неидемпотентных...

Эта проблема актуальна только для HTTP, с HTTPS у нас такой проблемы нет — мы на стадии хэндшейка перехватываем, а значит непосредственно сам запрос ещё не отправляем.
А в HTTP в принципе можно вычитать метод и отфильтровать не-GET/OPTIONS и вместо него отправить тот же GET / (или OPTIONS, что вообще то даже лучше, но тут я не берусь предсказать поведение провайдерского DPI, может и пропустить, или ответить как-то нестандартно… Надо пробовать) сохранив все остальные заголовки для проверки… Но это такое.

Насчёт envoy — честно, не слышал, посмотрю на досуге как-нибудь.

Оффтопик, но что касается envoy лично меня смущает большое количество CVE — не хочется завязывать критичные элементы инфраструктуры на настолько дырявый софт.

В nginx тоже будто cve не бывает? Тем более в случае openresty? Ну, смешно же

Ну, включая в nginx поддержку njs или openresty надо отдавать себе отчёт, что безопасность от этого пострадает. Впрочем, конкретно в openresty реальная уязвимость пока только одна, а вот в njs — беда, да.

UFO just landed and posted this here
Однако, если приходится часто посещать разные заблокированные сайты, то переключать туда / сюда прокси будет неудобно

Так SwitchyOmega умеет правила, можно шаблоны задать и прокси/прямое подключение для них

UFO just landed and posted this here
Это дело такое, сегодня не блокируют, а завтра могут и начать. Может, даже не сам датацентр, а магистральный провайдер, к которому они подключены.
Да и в любом случае при заворачивании 100% трафика в VPN пинг страдает в 99% случаев (есть ситуации при которых он может улучшиться к некоторым хостам, я практиковал это, но для этого надо специально строить цепочку серверов и арендовать с расчётом под конкретное приложение — в общем речь не о General Purpose).
Ваш вариант — это скорее один из подвариантов варианта 2 «гибридного» со списками. Просто списки формируете вы вручную =)
UFO just landed and posted this here

Если он стоит рядом, и они ощутимо проседают — Вы что-то не так настроили, потому что в нормальных условиях этого происходить не должно. Попробуйте взять тот же WireGuard, он достаточно быстрый, жрёт мало ресурсов, и его практически невозможно "настроить" (т.е. его сложно настроить некорректно :)), и проверьте с ним. Плюс неплохо убедиться, что сервер на котором стоит VPN не перегружен другими задачами.

UFO just landed and posted this here

Ну тогда надо использовать описанный в статье вариант, с маскировкой VPN-трафика под HTTPS.

Попробуйте SSTP в качестве VPN-а. Как раз идеальный вариант для обхода подобных шейперов…
UFO just landed and posted this here
Не так уж и ощутимо. Например, в моем случае VPN в Европе дает примерно такой же пинг до ресурсов в Европе и США и +20 мс к Москве (для меня это только 30% прироста к пингу без VPN и в целом не критично, т.к. я не играю). Скорость из 100 мбит вытягивает 80, при том что используется не самый шустрый OpenVPN.
Количество таких ДЦ сокращается от года к году, видимо по мере выяснения их существования со стороны РКН. Впрочем, с учетом «суверенного интернета» это скоро неактуально будет, т.к. механизм блокировок меняется на что-то подобное китайскому. В proxy они этим оборудованием уже лазят, Twitter работает медленно и через proxy (через VPN естественно нормально).
Пару недель назад приняли поправки как раз для таких случаев.
Технические изыскания одобряю, но решение в целом сложноватое.

В бытность пребывания на территории РФ все решилось швейцарским VPN за 3 бакса в месяц, в качестве софта был SoftEther.

Сначала пользовал ShadowSocks, но через него коряво работали торренты (ко мне нельзя было подключиться), перешел на обычный роутинг всего трафика. Для того чтобы погонять в контру полчасика можно и выключить, особых неудобств не отмечено.
Меня вот задолбало постоянно включать/выключать =) При подключении/отключении отваливаются все коннекты, а у меня вечно открыто с пяток SSH-сессий =) У меня аналогичный сэтап, только VPS в Нидерландах за 26.6 USD в год, и тоже SoftEther (который я к слову дорабатывал чтобы он IPv6 поддерживал не только по своему протоколу или OpenVPN, но и по SSTP тоже).
А вот такой вам хитрый вопрос, который я уже задавал человеку продвигающему Yggdrasil через I2P: разработчики подсистемы АСБИ ТСПУ, устанавливаемого сейчас у всех провайдеров заверяет что сигнатурное определение трафика позволит видеть буквально всё и блокировать на этих самых ТСПУ.
Что прикажете с этим делать?))
UFO just landed and posted this here
заверяет что сигнатурное определение трафика позволит видеть буквально всё
— Доктор, больше 3-х раз в неделю с женой не получается.
— Дед, а лет тебе сколько?
— 85.
— Дед, ну это же превосходно!
— Да? А мой сосед говорит, что с женой ежедневно, а ему 95!
— Ну так и вы говорите!
Любопытно. А где можно скачать получившийся модифицированный вариант? Прошу ссылку.
А он умеет всем показывать «web https сайт с котиками», а своему клиенту — SSTP?
UFO just landed and posted this here
На самом деле вообще-то SoftEther позволяет статичный сайт поднять вроде. Была где-то документация на эту тему, там надо папку создать, в неё закинуть файлы и они будут вместо стандартного отклика отдаваться, если я правильно помню.
UFO just landed and posted this here
Реквизиты то передаются по PPP инкапсулированному в HTTPS-запросы/ответы, так что там-то понятное дело что будет понятно что это VPN. Это, конечно, если про SSTP говорить. Впрочем с OpenConnect-ом тоже, похоже, что всё не так просто, он там тоже отдаёт вполне стандатные пакеты перед авторизацией (или для неё).
При большом желании можно финализировать TLS тем же NGINX-ом, легитимных клиентов пускать дальше как прокси, а нелегитимных — отдавать что угодно, хоть котиков, хоть собачек.
UFO just landed and posted this here
Ну почему не осилит-то =) Вопрос скорее чего именно мы хотим добиться. Узнать что сертификат клиент переслал — с TLSv1.3 точно не получится, в TLSv1.2 ещё можно отследить, примерно так же как я вычитываю здесь серверный, можно также вычитать и клиентский.
Особым запросом — это нечто вроде «port knocking», вполне можно сделать так, чтобы по дефолту NGINX финализировал TLS, но если получает какой-то спецзапрос — то добавляет ИП адрес который этот запрос отправил в список и далее весь трафик проксирует напрямую VPN-у.
Но это всё конечно требует поддержки с клиентской стороны.
UFO just landed and posted this here
На самом деле под NGINX есть модуль поддержки CONNECT, насколько я помню =) Ну либо можно наколхозить свой посредством всё того же OpenResty и Lua.
UFO just landed and posted this here
UFO just landed and posted this here

Роскомнадзор хоть и действует по всей России, блокируют только на конечных пользователях, Так что ВПН в русском дц. прокатит. Ну это конечно, если вас не парит чио они льют ваш трафик куда-то ещё :)

UFO just landed and posted this here
Скажите это МТС, которая фильтрует транзитный трафик.

Если ресурс заблокирован в РФ, но хостится в РФ и аплинком имеет МТС (такие существуют), то он будет недоступен из любой точки мира.
На российском VPS-хостере (название не буду называть) во времена ковровой блокировки Телеграма мой тестовый сайт не чекался через securityheaders.com (расположенном на DigitalOcean), сброшено соединение с сервером (остальные сайты, расположенные за пределами РФ, чекались нормально, и наоборот — другие чекеры нормально видели сайт). Так что тут даже входящие соединения за каким-то макаром у них могут блокироваться, если исходят из запрещённых сетей.
Если находим в нём этот редирект — это означает сразу две вещи:
Сайт блокируется, значит этот коннект надо редиректить.

Если по запросу получаем ответ о редиректе, то это может быть не блокировкой, а законным ответом сайта о перенаправлении клиента на другую страницу этого же сайта.


Такое встречается нередко.


Заходишь, бывает, на главную страницу сайта какой-нибудь конторы, а он редиректит тебя на какую-нибудь свою внутреннюю страницу типа /news/


Или у сайта могут быть зеркала. Заходишь на одно из зеркал, а оно перенапраляет тебя на основной домен сайта.


Ну и так далее.

Поэтому я проверяю на location — куда именно редиректит. Если на роскомнадзоровскую заглушку, чей адрес заведомо известен — это блок, если нет — это легитимный трафик.

Использую даже не vps, а хостинг провайдера, есть возможность подключения к ssh, 28 евро в год получается и хостинг и прокси все в одном. На клиенте, bitvise ssh client с возможностью socks5, для скачивания torrent файлов за глаза. Ранее была настройка на списках, ип и т.д. но надоело постоянно обновлять, то стили не грузятся потому что на другом домене то еще что то. Сейчас один браузер для всего, а один для торрентов.

Некоторые shared-хостинги выделяют учётку ssh на своём сервере под пользователя, не рутовую само собой. В принципе её можно использовать для запуска своего ПО при большом желании...

shared-хостинги — это narod.ru и подобные?

Как там можно у них запустить своё ПО через ssh? Просто залить приложение через scp и запустить? И оно запустится без проблем? Но, для сокетов (для прокси и подобного) нужны ведь будут именно рутовые права.
А чем это вы тут занимаетесь? На запрещённые сайты что-ли лазиете?

Идея отличная.


Списки выкидывать совсем, думаю не стоит. Они могут пригодиться хотя бы для кэширования результатов проверки.

Вполне можно дописать кэшер результатов =) Lua вполне имеет возможность писать в файлы =) В комплекте с OpenResty вдобавок есть ещё cjson библиотека для сериализации в json.
Кэш «положительных» результатов проверки может помочь с тем, чтобы не тестировать повторно доступ к сайту, про который секунду назад уже получили результат.

Кстати, если провайдер начнёт просто дропать непонятное HTTPS соединение на адрес из реестра? Такой вариант предусмотрен? Всё равно ведь большинство не будет читать заглушку на сайте с поддельным сертификатом.
Сейчас скрипт сделан таким образом, что при неудачном соединении к удалённому хосту он автоматом переключает на проксированный, мол «лучше попробовать проксировать чем совсем никак». Как раз этот кейс покрывает.
> Поскольку РосКомНадзор у нас действует на всей территории России, получается что весь трафик придётся проксировать через зарубежный сервер

Неверно, блокировка дйствует только на уровне местных провайдеров, мтс, билайна, мегафона…

Если поднять свой сервер в ДЦ, например, в МСК, то все блокировки будут обходиться. Я себе так и сделал — взял дешёвый VPS с CentOS (минимальные ресурсы), поставил туда проксю — ей хватает, прописал Primary DNS cloudflare — они одни из самых быстрых, как Secondary DNS — OpenNet DNS, они ничего не блокируют и поддерживают несколько доп.зон, например .lib (в этой зоне открываются флибуста, рутрекер).
Подключение к проксе — по белым IP чтобы чужие не лазили. И всё работает весьма быстро. Вот пример:

image
UFO just landed and posted this here
Evengard что-то пошло не так, куда смотреть?
*10 lua entry thread aborted: runtime error: content_by_lua(nginx.conf:357):45: bad argument #2 to 'connect' (number expected, got nil)
stack traceback:
coroutine 0:
[C]: in function 'connect'
content_by_lua(nginx.conf:357):45: in function 'socket_connect_dest'
content_by_lua(nginx.conf:357):85: in main chunk, client: 127.0.0.1, server: 0.0.0.0:30443
Ощущение будто у вас getorigdest модуль не подтянулся, и вы не получили информацию об исходном IP-адресе и порте подключения.
Такое ещё может произойти если вы пытаетесь подключиться к серверу напрямую, а не путём iptables-правила REDIRECT.
Напишите
ngx.log(ngx.INFO, tostring(dest_addr));
ngx.log(ngx.INFO, tostring(dest_port));

после
local dest_port = tonumber(dests[2]);

Если там nil — то у вас не подтянулась таки информация об исходном destination.

Так, — чукча ничего не понимает, когда забабахаете готовое решение, — просьба ответить на этот комментарий)

А на wsl работать будет? А то я боюсь роутер окирпичить.

WSL2 потянет, а вот первый WSL честно говоря не уверен. И проблема не столько в самом NGINX, сколько в iptables.
Я так и не понял, чем вас VPN не устраивает?
Насчет скорости так отличные скорости и пинг, если правильно подберешь сервер.
У меня даже некоторые сайты через VPN быстрее работают.
Раньше и у меня проблемыбыли и тормоза с VPN, когда я пользовался общедоступными простыми вариантами. Но нашел прогу SoftEther VPN Client Manager теперь пролем нет.
А еслиб мне это на постоянке надо было, так оплатил бы платные варианты, там еще лучше.

Почти ничего не понял, но прочитал с удовольствием. СПАСИБО

А как думаете автор статьи возможно ли сделать блокировку рекламы на роутере, пай ходе не предлагать плохо блокирует.

TLS-сессию мы просматривать не можем (если только сертификат не подменять, но это не выход с учётом pinning-а), но блокировать рекламные IP/домены в принципе можно.
Интересно, сколько пройдет времени прежде чем роскомндазор заблокирует данную статью?)

Как вариант при запуске делать запрос на заведомо блокируемый ресурс, чтобы определить с каким конкретно сертификатом приходит редирект у данного провайдера.
Так скрипт будет самостоятельно адаптироваться к другим провайдерам использующим тот же принцип блокировки с редиректом.

Маленький лайфхак — на самом деле, необязательно использовать VPN и/или серверы в Европе, почти на всех VDS/VPS в России нет блокировки трафика. Берём, например, Y.cloud (у них серверы в Екатеринбурге и вроде в Москве есть) ставим wireguard с резолвом (dns-o-https) через nextdns (пробовал pihole — nextdns проще администрировать и процессорное время не занимает), подрубаем это все добро к keenetic (или любому другому роутеру с wireguard) и радуемся открытому интернету без рекламы. Задержка +~ 3-6ms к вашей, скорость 200+ Мбит/сек. Один минус — стоимость ~500 рублей в месяц (25%CPU). Но на рынке есть VPS и за 80 рублей в месяц с серверами в Москве, который тоже прекрасно работает.

Получается, что для того, чтобы понять, что сайт блокируется, достаточно вычитать полученный от сервера сертификат

чаще мне встречается отсылка фальшивого TCP RST, вызывающая разрыв соединения:


$ curl -v https://rutracker.org
*   Trying 2a03:42e0::214:443...
* Connected to rutracker.org (2a03:42e0::214) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* OpenSSL SSL_connect: Connection reset by peer in connection to rutracker.org:443 
* Closing connection 0
curl: (35) OpenSSL SSL_connect: Connection reset by peer in connection to rutracker.org:443 

будет ли решение работать в таком случае?

В моей версии (которая чуть проапдейчена относительно этой) есть автоматический фоллбэк на альтернативный канал при разрыве основного, чуть позже могу скинуть луа-код последней версии.

Я ещё провайдера поменял, с мегафона на билайн, так что чуть изменилась логика обработки редиректов и сертификатов, а заодно кэширование добавил.

Обновлённый lua-код
local prefer_hosts = false
local prefer_socks_hosts = true

local intercept_domains = {".t.co", ".twimg.com", ".twitter.com", ".twttr.com"}

local cached_domains = ngx.shared.domains
local host = nil

local socket = ngx.req.socket(true)
socket.socktype = "CLIENT"
local god = require("resty.getorigdest")
local dest = god.getorigdest(socket)
local sni_name = ngx.var.ssl_preread_server_name
ngx.log(ngx.DEBUG, dest)
ngx.log(ngx.DEBUG, sni_name)
local openssl = require("resty.openssl")
openssl.load_modules()
local ngx_re = require("ngx.re")
local cjson = require("cjson")
local socks5 = require("resty.socks5")
local struct = require("struct")

local dests = ngx_re.split(dest, ":")
local dest_addr = dests[1]
local dest_port = tonumber(dests[2])

local connect_type_last = nil

local socket_create_with_type = function(typename)
    local target = ngx.socket.tcp()
    target.socktype = typename
    return target
end

local socket_connect_dest = function(target)
    local ok = nil
    local err = nil
    if (prefer_hosts == true and host ~= nil) then
        ok, err = target:connect(host, dest_port)
        connect_type_last = "host"
        if (err ~= nil) then
            local socktype = target.socktype
            target = socket_create_with_type(socktype)
            ok, err = target:connect(dest_addr, dest_port)
            connect_type_last = "ip"
        end
    else
        ok, err = target:connect(dest_addr, dest_port)
        connect_type_last = "ip"
        if (err ~= nil and host ~= nil) then
            local socktype = target.socktype
            target = socket_create_with_type(socktype)
            ok, err = target:connect(host, dest_port)
            connect_type_last = "host"
        end
    end
    if (ok == nil and err == nil) then
        err = "failure"
    end
    return target, err
end

local intercept = false
local connected = false
local isCached = false
local upstream = socket_create_with_type("UPSTREAM")

local bufsize = 1024 * 16
local peek, err, partpeek = socket:receiveany(bufsize)

if (peek == nil and partpeek ~= nil) then
    peek = partpeek
elseif (err ~= nil) then
    ngx.log(ngx.WARN, err)
end

local domainIntercept = false
if (sni_name ~= nil) then
    for _, v in pairs(intercept_domains) do
        local domain = "." .. sni_name
        local match = domain:sub(-string.len(v)) == v
        if (match == true) then
            domainIntercept = true
            ngx.log(ngx.DEBUG, sni_name .. " intercepted based on rule " .. v)
            --                      host = sni_name;
            break
        end
    end
end

if (domainIntercept == true) then
    intercept = true
elseif
    (dest_port == 80 or ngx.re.match(peek, "(^GET \\/)|(HTTP\\/1\\.0[\\r\\n]{1,2})|(HTTP\\/1\\.1[\\r\\n]{1,2})") ~= nil)
 then
    local http_host_find, err =
        ngx.re.match(peek, "[\\r\\n]{1,2}([hH][oO][sS][tT]:[ ]?){1}(?<host>[0-9A-Za-z\\-\\.]+)[\\r\\n]{1,2}")
    local http_host = nil
    if (http_host_find ~= nil and http_host_find["host"] ~= false) then
        http_host = http_host_find["host"]
    end

    if (http_host ~= nil and host == nil) then
        host = http_host
    end

    local cached = nil
    if (host ~= nil) then
        cached = cached_domains:get(host)
    end
    if (cached ~= nil) then
        ngx.log(ngx.INFO, "retrieved cached interception info: intercept=" .. tostring(cached))
        intercept = cached
        isCached = true
    else
        local err = nil
        upstream, err = socket_connect_dest(upstream)

        if (err ~= nil) then
            intercept = true
        else
            local ok, err = upstream:send(peek)
            if (err ~= nil) then
                ngx.log(ngx.WARN, err)
            end
            local data, err, partdata = upstream:receiveany(bufsize)
            if (data == nil and partdata ~= nil) then
                data = partdata
            elseif (err ~= nil) then
                ngx.log(ngx.WARN, err)
            end
            if (data ~= nil) then
                local match = "\r\nLocation: http://blackhole.beeline.ru/"
                local matched = data:find(match, 1, true)
                if (matched ~= nil) then
                    upstream:close()
                    upstream = socket_create_with_type("UPSTREAM")
                    intercept = true
                else
                    connected = true
                    local ok, err = socket:send(data)
                    if (err ~= nil) then
                        ngx.log(ngx.WARN, err)
                    end
                    peek = nil
                end
            end
        end
    end
elseif (dest_port == 443 or sni_name ~= nil) then
    local serv_host = nil

    if (sni_name ~= nil and host == nil) then
        host = sni_name
    end

    local cached = nil
    if (host ~= nil) then
        cached = cached_domains:get(host)
    end
    if (cached ~= nil) then
        ngx.log(ngx.INFO, "retrieved cached interception info: intercept=" .. tostring(cached))
        intercept = cached
        isCached = true
    else
        local err = nil
        upstream, err = socket_connect_dest(upstream)
        ngx.log(ngx.DEBUG, err)

        if (err ~= nil) then
            intercept = true
        else
            local ok, err = upstream:send(peek)
            if (err ~= nil) then
                ngx.log(ngx.WARN, err)
            end

            -- Parsing the ServerHello packet to retrieve the certificate
            local offset = 1
            local data = ""
            local size = 0
            local servercert = nil
            upstream:settimeouts(2000, 60000, 1000)
            while (servercert == nil) do
                if (size == 0 or offset >= size) then
                    local data2, err, partdata = upstream:receiveany(bufsize)
                    if (data2 ~= nil) then
                        data = data .. data2
                    elseif (data2 == nil and partdata ~= nil and partdata:len() > 0) then
                        data = data .. partdata
                    elseif (err ~= nil) then
                        ngx.log(ngx.WARN, err)
                        break
                    end
                    size = data:len()
                    ngx.log(ngx.DEBUG, "UPSTREAM received for ServerHello certificate retrieval! " .. size)
                end
                ngx.log(ngx.DEBUG, offset)
                if (offset < size) then
                    local contenttype, version, length, subtype = struct.unpack(">BHHB", data, offset)
                    if (contenttype ~= 22) then
                        -- We got something other than handshake before we retrieved the cert, probably the server is sending the cert encrypted, fallback to legacy cert retrieval
                        break
                    elseif (subtype ~= 11) then
                        offset = offset + 5 + length
                    else
                        local suboffset = offset + 5
                        local _, _, _, _, certslength, _, firstcertlength = struct.unpack(">BBHBHBH", data, suboffset)
                        -- We need only the first cert, we don't care about the others in the chain
                        local firstcert = data:sub(suboffset + 1 + 3 + 3 + 3, firstcertlength)
                        servercert = firstcert
                    end
                end
            end
            upstream:settimeouts(2000, 60000, 60000)

            local cert = nil
            if (servercert ~= nil) then
                cert = openssl.x509.new(servercert, "DER")
                ngx.log(ngx.DEBUG, "Cert retrieved from ServerHello peeking")
            else
                -- We employ a legacy method of gathering the certificate, involving connecting to the server and doing a SSL handshake by ourselves
                ngx.log(ngx.DEBUG, "LEGACY CERT RETRIEVE")
                local serv = socket_create_with_type("TLSCHECK")
                local err = nil
                serv, err = socket_connect_dest(serv)

                ngx.log(ngx.DEBUG, err)
                local session, err = serv:sslhandshake(false, sni_name, false, false)
                if (err ~= nil) then
                    ngx.log(ngx.DEBUG, err)
                    -- We fallback to proxying in case if we failed to connect due to timeout or reset (we are blackholed)
                    intercept = true
                else
                    ngx.log(ngx.DEBUG, err)
                    local sslsess, err = openssl.ssl.from_socket(serv)
                    ngx.log(ngx.DEBUG, err)
                    if (sslsess ~= nil) then
                        cert = sslsess:get_peer_certificate()
                        ngx.log(ngx.DEBUG, "Cert retrieved from secondary handshake")
                    end
                end
                serv:close()
            end

            -- Parsing the certificate
            if (cert ~= nil) then
                local sub = cert:get_subject_name()
                local alt = cert:get_subject_alt_name()

                for k, obj in pairs(sub) do
                    ngx.log(ngx.DEBUG, k .. " " .. cjson.encode(obj))

                    if (serv_host == nil and k == "CN" and obj.blob:find("*", 1, true) == nil) then
                        serv_host = obj.blob
                    end

                    if
                        (k == "CN" and obj.blob == "megafon.ru" and
                            (sni_name == nil or sni_name:find("megafon.ru", 1, true) == nil))
                     then
                        ngx.log(ngx.DEBUG, k .. " " .. obj.blob)
                        upstream:close()
                        upstream = socket_create_with_type("UPSTREAM")
                        intercept = true
                    end
                end
                for k, obj in pairs(alt) do
                    ngx.log(ngx.DEBUG, k .. " " .. cjson.encode(obj))

                    if (serv_host == nil and k == "DNS" and obj:find("*", 1, true) == nil) then
                        serv_host = obj
                    end
                end
            end

            if (serv_host ~= nil and host == nil) then
                host = serv_host
            end

            if (intercept ~= true) then
                connected = true
                local ok, err = socket:send(data)
                if (err ~= nil) then
                    ngx.log(ngx.WARN, err)
                end
                peek = nil
            end
        end
    end
end

if (connected == false and intercept == false) then
    local err = nil
    upstream, err = socket_connect_dest(upstream)

    if (err ~= nil) then
        intercept = true
        upstream = socket_create_with_type("UPSTREAM")
    end
end

if (isCached == false and domainIntercept == false) then
    ngx.log(ngx.DEBUG, "Saving cached data: host=" .. host .. ", intercept=" .. tostring(intercept))
    cached_domains:set(host, intercept)
end

if (intercept == true) then
    local ok, err = upstream:connect("192.168.120.1", 45213)
    ngx.log(ngx.DEBUG, err)
    ok, err = socks5.auth(upstream)
    ngx.log(ngx.DEBUG, err)

    local ok = nil
    local err = nil
    if (prefer_socks_hosts == true and host ~= nil) then
        ok, err = socks5.connect(upstream, host, dest_port)
        connect_type_last = "socks_host"
        if (err ~= nil) then
            upstream = socket_create_with_type("UPSTREAM")
            upstream:connect("192.168.120.1", 45213)
            ok, err = socks5.auth(upstream)
            ok, err = socks5.connect_ip(upstream, dest_ip, dest_port)
            connect_type_last = "socks_ip"
        end
    else
        ok, err = socks5.connect_ip(upstream, dest_addr, dest_port)
        connect_type_last = "socks_ip"
        if (err ~= nil and host ~= nil) then
            upstream = socket_create_with_type("UPSTREAM")
            upstream:connect("192.168.120.1", 45213)
            ok, err = socks5.auth(upstream)
            ok, err = socks5.connect(upstream, host, dest_port)
            connect_type_last = "socks_host"
        end
    end
    ngx.log(ngx.DEBUG, err)
end

upstream:setoption("keepalive", true)
upstream:setoption("tcp-nodelay", true)
upstream:setoption("sndbuf", bufsize)
upstream:setoption("rcvbuf", bufsize)

ngx.log(
    ngx.INFO,
    "RESULT: " ..
        tostring(host) ..
            "/" ..
                dest_addr ..
                    ":" .. dest_port .. " intercept:" .. tostring(intercept) .. " connecttype:" .. connect_type_last
)

local ok = false

if (peek ~= nil and peek:len() > 0) then
    ok, err = upstream:send(peek)
    if (err ~= nil) then
        ngx.log(ngx.WARN, err)
    end
else
    ok = true
end

local pipe = function(src, dst)
    while true do
        local data, err, partial = src:receiveany(bufsize)

        local errs = nil
        local ok = false
        if (data ~= nil) then
            ok, errs = dst:send(data)
        elseif (data == nil and partial ~= nil) then
            ok, errs = dst:send(partial)
        elseif (err == "closed") then
            ngx.log(ngx.WARN, src.socktype .. ":" .. err)
            return
        elseif (err ~= nil and err ~= "timeout") then
            ngx.log(ngx.WARN, src.socktype .. ":" .. err)
        end

        if (errs == "closed") then
            ngx.log(ngx.WARN, dst.socktype .. ":" .. errs)
            return
        elseif (errs ~= nil) then
            ngx.log(ngx.WARN, dst.socktypeerr .. ":" .. errs)
        end
    end
end

if (ok ~= false) then
    local co_updown = ngx.thread.spawn(pipe, upstream, socket)
    local co_downup = ngx.thread.spawn(pipe, socket, upstream)

    ngx.thread.wait(co_updown, co_downup)
end

upstream:close()
ngx.flush(true)
socket:shutdown("send")

Вот как во всём этом разобраться не IT - специалисту???...

А как быть если провайдерский DPI отсылает TCP FIN, ACK пакет сразу после ClientHello? Никаких TCP RST или поддельных сертификатов.
На ум приходит что надо как-то выделять соединение в отдельный поток и следить за идущим пакетом после ClientHello. Задача непростая.

Была идея отслеживать этот пакет по TTL, но очевидно что это не решает проблемы на 100%. Будет много лжесрабатываний.

На самом деле код у меня отслеживает закрытие соединения, и безусловно направляет тогда связь по альтернативному каналу прозрачно.

Моя вариант решения на Микротике.

Sign up to leave a comment.

Articles

Change theme settings