Домашний DPI, или как бороться с провайдером его же методами

    Зачем всё это нужно?

    Долгое время я терпел ограничения РосКомНадзора и соответствующие действия провайдеров по различным ограничениям доступа к сайтам - но с определённого момента устал, и начал думать как бы сделать так, чтобы было и удобно, и быстро, и при этом с минимумом заморочек после настройки... Хочу оговориться, что цель анонимизации не ставилась.

    Какие вообще уже есть методы решения?

    Вообще, эта проблема имеет несколько решений. Кратко перечислю самые известные и их минусы:

    1. Заворачивание всего трафика в VPN-туннель либо какой-то прокси - как вариант, TOR. В случае с TOR-ом о скорости можно забыть, в остальных случаях скорость и время отклика также страдают, поскольку необходимо проксировать через удалённый сервер. Поскольку РосКомНадзор у нас действует на всей территории России, получается что весь трафик придётся проксировать через зарубежный сервер, а значит время отклика (или "пинг") будет сильно страдать. Сразу отрезается весь пласт, например, игровых приложений.

    2. "Гибридный" вариант с использованием списков. Основной трафик идёт напрямую, но часть IP-адресов перенаправляются через VPN/прокси/TOR. Списки можно забирать, например, отсюда. Минусы - приходится периодически обновлять эти списки, и какими бы они не были актуальными есть вероятность всё же наткнуться на заблокированный сайт. На самом деле, один из лучших способов для комфортного пользования интернетом без ограничений. Но можно лучше!

    3. Использование "чёрной магии", связанной с особенностями применяемого провайдерами DPI-софта. Я, в общем и целом, про "дыры" в обработке трафика (например, блокирование только на уровне DNS, или пропуск необычно сформированных пакетов), и, в частности, про GoodbyeDPI уважаемого @ValdikSS. Самый большой минус - работает далеко не везде. И чем дальше, тем хуже работает. Рост вычислительных мощностей скорее упрощает жизнь провайдерам, чем нам в этом вопросе...

    4. ...и наконец, использование DPI для обхода DPI! На самом деле этот способ является подвариантом "гибридного", но безо всяких списков. Мы анализируем пришедшие пакеты от провайдера, делаем вывод, заблокировал ли он нам что-то, и на этом основании либо пускаем дальше трафик к запросившему, либо перенаправляем трафик через VPN/прокси/TOR. Всё ещё требует конфигурации VPN/прокси/TOR, но уже не требует никаких списков, а также позволяет принимать решения на основании теоретически сколь угодно сложной логики!

    Про последний способ дальше и пойдёт речь. И поможет нам в этом NGINX.

    Во многом идея была вдохновлена Squid-овским механизмом HTTPS Peek and Splice, но его возможностей к сожалению не хватило.

    Так ведь NGINX - это веб-сервер, а не инструмент для DPI?

    NGINX - это весьма продвинутый мультипротокольный сервер, и его возможности в качестве HTTP-сервера - лишь верхушка айсберга. При этом он кроссплатформенен, имеет мало зависимостей и при этом бесконечно расширяем.

    И самым лучшим расширением NGINX является проект OpenResty - который добавляет практически ко всем аспектам NGINX-а поддержку Lua.

    Мне могут сейчас возразить, что современный NGINX поддерживает "изкаробки" возможность скриптинга на JavaScript (njs), и будет прав, но, во-первых, OpenResty гораздо более развитый проект и его API имеет гораздо больше возможностей, а во-вторых, OpenResty использует LuaJit с поддержкой FFI, что позволяет вызывать C-методы напрямую из Lua-мира - и это создаёт такую возможность для расширения, которая njs даже и не снилась. Во всяком случае пока что...

    При этом, NGINX имеет возможность проксировать и "сырой" TCP-трафик (теоретически и UDP тоже, но я реализовал "DPI" только TCP).

    О деталях реализации

    Конкретно у меня по причине отсутствия кабельного интернета дома сейчас используется 4G-интернет от Мегафона, поэтому описание будет происходить с точки зрения именно Мегафона.

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

    Прежде всего, мы поднимаем NGINX в режиме stream на каком-то порту... Пусть будет 40443. Но сам по себе nginx не знает что делать с трафиком, что туда приходит. Именно это мы и будем разруливать с помощью Lua.

    Прежде всего, мы перенаправляем весь трафик с 80 и 443 порта на этот самый 40443 порт при помощи iptables и его команды REDIRECT. Эта команда интересна тем, что прописывает в свойства сокета опцию SO_ORIGINAL_DST, в которой сохраняет оригинальный IP и порт, куда пакет изначально направлялся, до того как iptables над ним зверски поиздевался, переписав destination... Кхм, я отвлёкся. Эту информацию можно извлечь при помощи getsockopt... Правда из коробки обёртки над ним не было, так что пришлось написать простенький C-модуль для nginx.

    Теоретически можно было бы использовать TPROXY, и пропатчить NGINX для поддержки SO_TRANSPARENT сокетов, но хотелось не прибегать к прямому патчу исходников NGINX-а и обойтись модулями, поэтому REDIRECT.

    Итак, мы запрашиваем заблокированный сайт... Пусть будет, например, rutracker.org.

    ...И сразу надо определиться, по HTTP или HTTPS. Несмотря на то, что HTTP постепенно умирает, всё же есть ещё сайты, использующие его. Так что обработка HTTP реализована.

    HTTP - тут всё просто

    Итак, мы запрашиваем http://rutracker.org. И видим, что нас перенаправило на http://m.megafonpro.ru/rkn, где Мегафон услужливо сообщает, что, мол, так и так, сайт заблокирован, просим извинить, а пока посмотрите на нашу рекламу.

    Да, Мегафон просто напросто отправил 307 Temporary Redirect с Location на свой собственный сайт для отображения этого сообщения. А значит мы вполне можем отследить ровно это - 307 редирект с Location в котором http://m.megafonpro.ru/rkn.

    Для этого мы вычитываем первые данные, пришедшие от клиента (вплоть до 16 кбайт, но по факту первые пакеты весьма маленькие), перенаправляем их серверу и читаем ответ от него. Если находим в нём этот редирект - это означает сразу две вещи:

    1. Сайт блокируется, значит этот коннект надо редиректить.

    2. Запрос скорее всего не дошёл до сервера, а значит переотправять его повторно - безопасно. Это необязательно верно, но верно наверное в 99% случаев. Правда, если это неверно, и вы отправляете запросы, что-то меняющие на удалённом сервере, то тут беда... Прилетит по итогу два запроса - один - тот на который заблокирован ответ, и второй - спроксированный. И узнать мы это никак не сможем. Хорошо, что HTTP без SSL становится всё меньше, правда? =)

    Если редиректа нету, значит мы просто отправляем этот запрос дальше клиенту и дальше просто проксируем трафик, не вмешиваясь в него.

    HTTPS вплоть до TLSv1.2 - посложнее

    С SSL/TLS всё гораздо сложнее... Но есть и хорошие новости. Перед любым HTTP-запросом мы сначала должны выполнить Handshake, а значит первый пакет точно не вызовет выполнение команды на сервере в случае, если нас заблокировали, но исходный пакет таки ушёл на сервер.

    Мы запрашиваем https://rutracker.org и получаем в браузере... Ошибку. Сертификат недействительный, потому что выпущен даже не для этого домена, беда-беда...

    Анализируем сам сертификат... И что же мы видим? CN=megafon.ru. Получается, что для того, чтобы понять, что сайт блокируется, достаточно вычитать полученный от сервера сертификат, и если мы запрашиваем что угодно кроме megafon.ru, а получили сертификат с CN=megafon.ru - нас блокируют, и надо проксировать.

    Осталось только понять, как понять, куда именно мы изначально обращались, и как получить этот сертификат.

    И здесь нам поможет SNI - дело в том, что (современный, мы не говорим про эпоху IE6, она ушла и слава богу) клиент отправляет домен, к которому обращается, в составе незашифрованных данных ClientHello. Самое интересное, что эти данные умеет вычитывать даже сам NGINX из коробки - модуль ssl_preread поставляется вместе с ним. Ну а Lua-биндинги позволяют получить эту информацию и для наших целей...

    Итак, что мы делаем? Процедура во многом аналогична HTTP - мы отправляем первый пакет от клиента серверу (который как раз содержит ClientHello) и ждём от сервера ответа с сертификатом. После чего убеждаемся что SNI не megafon.ru, парсим сертификат (спасибо человеку, написавшему биндинги к OpenSSL для Lua), и принимаем решение - проксировать или нет.

    И всё было бы хорошо, если бы не TLSv1.3, который всю эту историю сильно обламывает...

    TLSv1.3 наносит ответный удар

    Во-первых, в TLSv1.3 SNI может быть зашифрованным. Хорошая новость в том, что зашифрованный SNI не расшифрует и сам провайдер, а значит он будет блокировать любые TLS-запросы к IP точно так же. Вторая особенность в том, что сертификат сервер клиенту теперь тоже отправляет в зашифрованном виде...

    Проблема усугубляется ещё и тем, что Мегафон отправляет свой сертификат как раз таки по TLSv1.3, то есть зашифрованным, в случае если клиент поддерживает TLSv1.3. А все основные браузеры сейчас его поддерживают. Проблема...

    На этом этапе я уже даже думал о том, чтобы патчить ClientHello, убирая из него поддержку TLSv1.3, осуществляя по сути атаку на downgrade до TLSv1.2, но вовремя почитал описание TLSv1.3. В нём реализовано аж ДВА механизма по предотвращению подобных даунгрейдов, поэтому вариант плохой.

    ...И здесь приходится прибегать к экстренным мерам. На самом деле этот метод я реализовал даже первым, и он по сути и является сутью метода peek and splice у Squid-а.

    Мы не можем просто взять и вычитать сертификат. Поэтому мы просто открываем свой собственный коннект к серверу и пытаемся сами совершить tls-handshake. Получаем из него сертификат с CN=megafon.ru? Значит нас блокируют. Нет? Значит всё в порядке. И нам не сильно важно какой другой - да пусть даже мы дисконнект получим. Главное, что мы не получили сертификат, который является флагом блокировки.

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

    А что дальше с заблокированным трафиком-то делать?

    Итак, мы понимаем, что сайт блокируется. Что делать? Лучшее и наиболее универсальное что я придумал - это SOCKS5 прокси. Протокол проще некуда, к нему есть удобная клиентская реализация, которую чуть доработать - и можно пользоваться. Вдобавок, SOCKS5 реализован в Tor и SSH. Поднять SOCKS5-сервер - дело пяти минут.

    Особенности некоторых сайтов и приятный бонус

    Во время тестов я натолкнулся на весьма странное поведение linkedin.com. Дело в том, что при его запросе почему-то я вообще не получал никакого ответа, коннект просто уходил в таймаут. Я решил, что если коннект таймаутится, есть смысл попробовать его тоже перенаправить через VPN - хуже точно не будет.

    Каково же было моё удивление, когда точно такое же поведение было и через VPN. Причём, с подключением через VPN IPv4 не соединялся, а по IPv6 вполне всё работало.

    Тут я вспомнил, что у SOCKS5 есть два режима подключения к удалённому хосту - по IP и по хосту. Поэтому я реализовал следующую обработку соединения (Hostname мы получаем из SNI):

    direct IP => direct Hostname => socks5 IP => socks5 Hostname

    С таймаутом на соединение в 2 секунды. В чём смысл? Если вдруг оказывается, что наша машина, на котором развёрнут NGINX оказывается IPv6-capable, а изначальный клиент нет, то мы сможем спроксировать трафик через IPv6, при том, что клиент будет думать что соединяется по IPv4. Аналогично и с прокси-сервером.

    А что насчёт производительности?

    Конкретно в моём случае, основные затраты на производительность - при первичном подключении к серверу. Но, честно говоря, даже они минимальны. После соединения потребление что CPU, что RAM остаётся почти незаметным. Конечно, Netgear R7000 достаточно мощная машинка - двухядерник с 1 GHz ядрами и 256 МБ оперативки - но он даже не нагружается на 10% во время обычного использования (активного сёрфинга, просмотра видео на YouTube). При прогоне спидтеста потребление вообще остаётся на уровне 5% CPU. Самую большую нагрузку составил как ни странно сайт по проверке замедления t.co (https://speed.gulag.link/) - вот там ядра напрягаются до 80% на одном ядре (и около 25% на другом), но при этом так и не достигают 100%.

    Итак, переходим к практике - что нам для этого потребуется?

    В качестве железа подойдёт почти что всё что угодно, на чем можно запустить Linux. В моём случае, я запускаю это всё на Netgear R7000 с ARM-процессором внутри, и кастомной прошивкой с версией ядра всего лишь 2.6.36. В общем и целом теоретически запустится на практически любом Linux-е с версией ядра хотя бы 2.6.32.

    Поскольку решение не совсем стандартное, придётся пересобирать NGINX/OpenResty из исходников. Я успешно собирал прямо на самом роутере - занимает некоторое время, но не так чтобы бесконечное.

    Конкретно нужно:

    1. OpenResty - это NGINX с LuaJit и основными Lua модулями. Я скачивал релизный тарболл из их раздела загрузок.

    2. lua-resty-openssl и его C-модуль к NGINX lua-resty-openssl-aux-module. Нужен для получения и разбора сертификатов SSL-сессий.

    3. Мой самописный C-модуль к NGINX и Lua-биндинг lua-resty-getorigdest-module для получения информации об IP и порте того, куда изначально обращался клиент.

    4. lua-struct для парсинга бинарных пакетов (в частности, поиска сертификата после ServerHello).

    5. Мой форк SOCKS5 Lua-клиента lua-resty-socks5 уважаемого @starius, которому была добавлена возможность соединяться через SOCKS5 не только по хостнейму, но и по IP-адресу.

    6. SOCKS5 прокси-сервер для проксирования заблокированного трафика - например, socks-прокси TOR-а, либо обыкновенный ssh -D. Для VPN-сервера - надо установить его на самом VPN-сервере и проксировать через него. Настройка socks-прокси выходит за рамки этой статьи.

    Также я исхожу из того, что запускаете вы это на устройстве, маршрутизирующем ваш доступ к интернету - в моём случае это роутер. Оно должно завестись в том числе и на локалхосте, но для этого придётся садаптировать правила iptables. Также, исхожу из того, что трафик от клиентов приходит с br0 устройства.

    Подготовка и сборка

    Предполагаю, что сборку осуществляем в /home/username/build. Устанавливать будем в /opt/nginxdpi

    1. Разархивируем тарболл openresty, делаем git clone всем указанным выше дополнениям. Для удобства переименовываем папку openresty-X.Y.Z.V в openresty.

    2. Переходим в /home/username/build/openresty, выполняем:

      ./configure --prefix=/opt/nginxdpi --with-cc=gcc \
      --add-module=/home/username/build/lua-resty-openssl-aux-module \
      --add-module=/home/username/build/lua-resty-openssl-aux-module/stream \
      --add-module=/home/username/build/lua-resty-getorigdest-module/src

    3. Выполняем make -j4 && make install, ждём пока всё соберётся...

    4. После сборки копируем:

    cp -r /home/username/build/lua-resty-getorigdest-module/lualib/* /opt/nginxdpi/lualib/ 
    cp -r /home/username/build/lua-resty-openssl/lib/resty/* /opt/nginxdpi/lualib/resty/
    cp -r /home/username/build/lua-resty-openssl-aux-module/lualib/* /opt/nginxdpi/lualib/
    cp /home/username/build/lua-resty-socks5/socks5.lua /opt/nginxdpi/lualib/resty/
    cp /home/username/build/lua-struct/src/struct.lua /opt/nginxdpi/lualib/

    Готово! Можно приступать к конфигурированию.

    Конфигурация

    Вся логика содержится в следующем конфигурационном файле:

    nginx.conf
    user root;
    worker_processes auto;
    
    events {
        worker_connections 1024;
    }
    
    stream {
        preread_buffer_size 16k;
        server {
            listen 30443 so_keepalive=on;
            tcp_nodelay on;
            #error_log /opt/nginxdpi/cfg/error.log info;
            error_log off;
    
            lua_socket_connect_timeout 2s;
            
            resolver 192.168.3.1;
    
            ssl_preread on;
            content_by_lua_block {
                local prefer_hosts = false;
                local prefer_socks_hosts = true;
                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 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
    
                if (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 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 = "HTTP/1.1 307 Temporary Redirect\r\nLocation: http://m.megafonpro.ru/rkn";
                            local match_len = string.len(match);
                            local extract = data:sub(1, match_len);
                            if (match == extract) 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
                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 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
                            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);
                            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
                            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
    
                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 (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");
            }
        }
    }
    

    Можно было бы наверное разделить lua код от конфига, но мне было немного лень =)

    Замените 192.168.120.1 и 45213 на хост и порт вашего SOCKS5-сервера!

    Также замените 192.168.3.1 на IP-адрес DNS-сервера, которым вы хотите резолвить хосты.

    Размещаем его в /opt/nginxdpi/cfg/nginx.conf

    Создаём файл /opt/nginxdpi/cfg/start.sh со следующим содержимым:

    start.sh
    #!/bin/sh
    /opt/nginxdpi/bin/openresty -c /opt/nginxdpi/cfg/nginx.conf
    iptables -t nat -A PREROUTING -i br0 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 30443
    iptables -t nat -A PREROUTING -i br0 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 30443

    Обратите внимание, что br0 - это интерфейс локальной сети, с которого подключаются клиенты!

    Даём start.sh права на выполнение chmod +x /opt/nginxdpi/cfg/start.sh, и наконец запускаем всё это добро (от рута! В принципе теоретически может заработать и без рута, но я не пробовал...):

    /opt/nginxdpi/cfg/start.sh

    После этого весь ваш HTTP и HTTPS трафик будет проксироваться через этот сервер.

    Что можно сделать ещё?

    На самом деле есть несколько вещей, которые можно доработать, разной степени сложности.

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

    Во-вторых, пока что совершенно не поддерживается IPv6. Добавить поддержку на самом деле несложно... С другой стороны, как правило IPv6 трафик сейчас фильтруется редко (если вообще где-то фильтруется).

    В-третьих, опять таки не поддерживается UDP. И если на текущем этапе это не столь критично (мало что по UDP сейчас блокируется), то с развитием HTTP3/QUIC эта проблема будет гораздо более критичной. Правда как проксировать QUIC я пока понятия не имею, да и DTLS отличается от TLS... Там будет хватать своих проблем. Это, наверное, самая сложная задача.

    И в завершение...

    На самом деле этот механизм можно использовать и для полноценного DPI. По сути мы получаем полноценную TCP-сессию, которую можем инспектировать "на лету" - достаточно, по сути, пропатчить pipe-функцию. С другой стороны, смысла в анализе сырых данных после завершения SSL-handshake нынче мало, а зашифрованного трафика становится только больше...

    Этот же метод в принципе позволяет и записывать трафик - закон Яровой исполнять, например. Надеюсь я не открыл сейчас ящик Пандоры...

    ...вдруг кому-то из провайдеров этот метод позволит сэкономить на DPI-софте и уменьшить цену тарифов? Кто знает.

    Скажу честно, местами мне было лень обрабатывать ошибки, поэтому возможно странное поведение. Если обнаружите какие-то ошибки пишите, попробую поправить - но в принципе я сижу через этот DPI сейчас сам, и проблем особых не заметил (а те что заметил - пофиксил).

    Желаю удачи в адаптации под своих провайдеров!

    Комментарии 172

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

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

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

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

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

          0
          Для обхода DPI в Linux есть github.com/bol-van/zapret
          можно пробовать поднять на роутере

          по классификации автора статьи это п.3
          +7

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

            +7

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

              0

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

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

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

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

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

                    0
                    Ну для такого варианта кэширование уже надо рассматривать. Потому что каждый раз сверять два подключения слишком накладно))
                • НЛО прилетело и опубликовало эту надпись здесь
                    0

                    Mitm с бантиком :-) брать такие подарки только у тех, от кого нет секретов :-)

                    +1

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


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


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

                      +4

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

                        +1

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

                          +2

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

                      +2

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

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

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


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

                          +1
                          OpenResty использует LuaJit, ограниченный версией 5.1. К сожалению string.pack/unpack в нём нет — я специально проверял — собственно первой попыткой была реализация через них. Поэтому пришлось использовать lua-struct.
                          +54
                          Чем люди только не заморачиваются, лишь бы не выбирать нормальных депутатов.
                            +10
                            Это особенности национального лобби развития Hi-Tech технологий.
                              +4

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

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

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

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

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

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

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

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

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

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

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

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

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

                                                      +2
                                                      Она не переросла, а сразу была представлена в виде законопроекта. Набрала сто тысяч подписей и была завернута.
                                            –3

                                            Разделю вашу славу, отхвачу тоже в карму.
                                            Обычно минусят наоборот когда имеешь ввиду что Мутин лoх, Навальный пох. Но вы просто написали правду, что нормальный ≠ депутат. Это не сопоставимые вещи для страны и тоже задевает чувства верующих, ботов.
                                            PS: что мешает ресурсу бороться с ботами?

                                              +3
                                              PS: что мешает ресурсу бороться с ботами?
                                              А причем тут боты? Голосовать могут только полноправные пользователи с кармой ≥ 5.
                                                –1
                                                А причем тут боты? Голосовать могут только полноправные пользователи с кармой ≥ 5.

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

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

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

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

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

                                              +3
                                              Если хотя бы один пункт будет нарушен — то вся идея выбора «нормальных депутатов» пойдёт коту под хвост


                                              У вас слишком большой набор излишне категоричных и нереальных условий, которые заблокируют любую активность. Эдак все так и будут по домам сидеть, в лучшем случае займутся «теорией малых дел» ради чистых дворов и тротуаров. И в Минске, говорят, очень чисто и опрятно. Но, судя по слитым видосикам, резиновую дубинку в спортзале всё равно облизывать приходится.

                                              Почти по всем пунктам я категорически не согласен:

                                              1 — Это не важно. В странах в которых политики отвечают перед избирателями и боятся что люди их не перевыберут такое происходит. Вот прям на днях Скотт наш Мэнли приводил в пример бывшего главу НАСА Джима Брайнстана, который переобувался. И ничего, все по Джиму скучают, Commercial Crew Program более чем работает. И работают политики потом уже не только с оглядкой на административный ресурс, как сейчас. И вообще, «другых пейсателей у мэня для вас нэт!» (с). Не будем же мы ждать пока наступит «полдень 22 век» чтобы начать ходить на выборы?

                                              2 — На данном этапе это не важно, сгодятся и вечно занимающие второе место. Когда гегемон лишается большинства они неожиданно начинают наглеть (и помнят как они получили такую возможность). Когда прошлый раз такое произошло на местах, этого хватило чтобы гегемон начал возмущаться что они «недоговороспособные». А если такое, да в госдуме?

                                              3 — Пока у нас не введут голосование через госуслуги или инициативу предложенную «партией прямой демократии», кажется она же «партия танчиков», то махинации возможны только в масштабах «выслужиться перед начальником добрав 4%» (см. Екатерина Шульман например). Не, можно конечно и начать жестить, но тогда учителя начинают с мешками из окон школ вылазить. Такое нельзя не заметить, а дальше см. пункт 5. Ну, а если у нас введут блокчейн как на тех выборах где «наблюдателем за хэшами» был Венедиктов, то тогда да, ой, привет диджитал избирательная автократия.

                                              4 — Таким способом можно добрать единицы процентов в условиях когда см. пункт 5.

                                              5 — А вот это реальная проблема. Люди безразличны, ленивы, выучили беспомощность, готовы голосовать за спойлеров потому что «не люблю я коммунистов» (а потом голоса делятся пропорционально между победителями), не готовы защищать независимых кандидатов потому что страшно или «потому что они фрики» (см. чувака ниже который ждёт примеры предвыборных законопроектов, как будто это на данный момент важнее тупо конкуренции и представительности) и т.д.
                                                0

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

                                                  +3

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


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

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

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

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

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

                                                        +1

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

                                                          0

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


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

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

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

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

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

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

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

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

                                                            +2

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


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

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

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


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


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


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

                                                                +2

                                                                $ host lostfilm.tv
                                                                lostfilm.tv has address 185.85.121.13


                                                                $ whois 185.85.121.13 | grep country
                                                                country: SC

                                                              +1

                                                              Мой выбор это


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

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

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

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


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

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


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


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

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

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

                                                                                +1
                                                                                Вы правы, свой родной протокол SoftEther-а вполне себе делает примерно то же самое, но вот под него найти клиенты на что-то, кроме Windows/Linux/MacOS у вас не получится. В этом плане SSTP гораздо более распространён.
                                                                                +1
                                                                                Из-за его возможностей по прохождению там, где остальные не проходят, прикидываясь обыкновенным HTTPS трафиком, и при этом, опять таки, наличие клиентов почти подо всё (благо они преимущественно open source, а значит пересобрать не велика проблема, плюс базируются на давно известном и реализованном везде PPP) =)
                                                                                Рекомендую посмотреть еще в сторону AnyConnect/OpenConnect — там тот же PPP поверх HTTPS, тоже есть клиенты под все что только можно, но при этом кроме TLS он при доступности может подключать в качестве транспорта еще DTLS, что в некоторых случаях очень хорошо повышает производительность.
                                                                                  0
                                                                                  На самом деле достаточно интересный вариант, просто я с AnyConnect-ом познакомился недавно =) А документация на его протокол в открытом доступе, тоже? Или это плод реверс-инжиниринга?
                                                                                    0
                                                                                    Как я понял, изначально реверс-инжиниринг, в результате чего его опубликовали и начали развивать отдельно, при этом стараясь не ломать обратную совместимость.
                                                                                      0
                                                                                      Несколько отличается от SSTP, где документацию на него опубликовали непосредственно сами MS =) Как к этому сама Cisco отнеслась, не знаете?
                                                                                        0
                                                                                        Не, не знаю.
                                                                                        Но ведущий разработчик самого сервера работает в Redhat, так что, думаю, с юридической чистотой там все нормально.
                                                                                +1

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

                                                                                  +3

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

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

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

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

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

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

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

                                                                                            +1

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


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


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


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

                                                                                              0
                                                                                              если, например, они тупо блокируют всё, кроме HTTP, то это сломает абсолютное большинство VPN, и я не склонен расценивать это как проблему «недостаточной сложности» WireGuard
                                                                                              Если они блокируют все, кроме HTTP, то у них вообще большая часть современного интернета работать не будет, а если они блокируют все, кроме HTTP и HTTPS, то великолепно без каких-либо проблем будут работать HTTPS-based VPN протоколы, типа уже упомянутых SoftEther, SSTP и OpenConnect.
                                                                                                0

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

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

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


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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

                                                                                                    0

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

                                                                                                      0

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

                                                                                                  +1
                                                                                                  Поскольку РосКомНадзор у нас действует на всей территории России, получается что весь трафик придётся проксировать через зарубежный сервер

                                                                                                  Это не обязательно, есть дата-центры в России, которые не фильтруют трафик. У меня на таком сервере поднят 3proxy, трафик в него идет через плагин SwitchyOmega браузера (все сайты за исключением некоторых работают напрямую, а нужные через прокси).

                                                                                                  Однако, если приходится часто посещать разные заблокированные сайты, то переключать туда / сюда прокси будет неудобно и Ваш вариант несомненно будет удобнее.
                                                                                                    +1
                                                                                                    Однако, если приходится часто посещать разные заблокированные сайты, то переключать туда / сюда прокси будет неудобно

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

                                                                                                      0
                                                                                                      Да, я понимаю это (этим и пользуюсь). Речь о том, когда приходится постоянно посещать разные сайты (которые еще не добавлены в плагине). Когда посещаете условные 10 заблокированных сайтов, SwitchyOmega отлично подходит под эти цели.
                                                                                                      +2
                                                                                                      Это дело такое, сегодня не блокируют, а завтра могут и начать. Может, даже не сам датацентр, а магистральный провайдер, к которому они подключены.
                                                                                                      Да и в любом случае при заворачивании 100% трафика в VPN пинг страдает в 99% случаев (есть ситуации при которых он может улучшиться к некоторым хостам, я практиковал это, но для этого надо специально строить цепочку серверов и арендовать с расчётом под конкретное приложение — в общем речь не о General Purpose).
                                                                                                      Ваш вариант — это скорее один из подвариантов варианта 2 «гибридного» со списками. Просто списки формируете вы вручную =)
                                                                                                        +1
                                                                                                        Работаю с двумя дата-центрами, с момента введения фильтрации проблем не возникало. Один из них достаточно известный и крупный дата-центр России. Но то, что могут начать блокировать в любой момент — это верно.

                                                                                                        Заворачивать весь трафик в VPN действительно плохая идея, пинг и скорость ощутимо проседают, даже если сервер под VPN стоит рядом. Поэтому для себя использую описанный гибридный вариант с проксированием нужных сайтов, за счет 3proxy и близкого расположения сервера разница с прямым открытием на глаз незаметна :)
                                                                                                          +2

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

                                                                                                            0
                                                                                                            Боюсь, здесь не всё так просто. У меня есть подозрение, что у моего местного провайдера строит шейпер трафика в зависимости от его типа. Если делать тест через HTTP, скорость хорошая, если что-то качать по FTP, либо через VPN, скорость очень сильно падает.
                                                                                                              +1

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

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

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

                                                                                                              Сначала пользовал ShadowSocks, но через него коряво работали торренты (ко мне нельзя было подключиться), перешел на обычный роутинг всего трафика. Для того чтобы погонять в контру полчасика можно и выключить, особых неудобств не отмечено.
                                                                                                                0
                                                                                                                Меня вот задолбало постоянно включать/выключать =) При подключении/отключении отваливаются все коннекты, а у меня вечно открыто с пяток SSH-сессий =) У меня аналогичный сэтап, только VPS в Нидерландах за 26.6 USD в год, и тоже SoftEther (который я к слову дорабатывал чтобы он IPv6 поддерживал не только по своему протоколу или OpenVPN, но и по SSTP тоже).
                                                                                                                  0
                                                                                                                  А вот такой вам хитрый вопрос, который я уже задавал человеку продвигающему Yggdrasil через I2P: разработчики подсистемы АСБИ ТСПУ, устанавливаемого сейчас у всех провайдеров заверяет что сигнатурное определение трафика позволит видеть буквально всё и блокировать на этих самых ТСПУ.
                                                                                                                  Что прикажете с этим делать?))
                                                                                                                    +2
                                                                                                                    SoftEther/SSTP/OpenConnect внешне совершенно неотличимы от обычного HTTPS, сигнатурный анализ там бессилен.
                                                                                                                    Их вполне можно отлавливать active-probing'ом, но против этого тоже есть методы защиты.
                                                                                                                      +4
                                                                                                                      заверяет что сигнатурное определение трафика позволит видеть буквально всё
                                                                                                                      — Доктор, больше 3-х раз в неделю с женой не получается.
                                                                                                                      — Дед, а лет тебе сколько?
                                                                                                                      — 85.
                                                                                                                      — Дед, ну это же превосходно!
                                                                                                                      — Да? А мой сосед говорит, что с женой ежедневно, а ему 95!
                                                                                                                      — Ну так и вы говорите!
                                                                                                                      0
                                                                                                                      Любопытно. А где можно скачать получившийся модифицированный вариант? Прошу ссылку.
                                                                                                                        0
                                                                                                                        Все мои изменения интегрированы в основную кодовую базу SoftEther, просто соберите master-ветку из github.com/SoftEtherVPN/SoftEtherVPN
                                                                                                                          0
                                                                                                                          А он умеет всем показывать «web https сайт с котиками», а своему клиенту — SSTP?
                                                                                                                            +1
                                                                                                                            Насколько я помню, по-нормальному сейчас такое не умеет ни один VPN-сервер, нужно колхозить.
                                                                                                                            Вариант один — использовать нокер (но это не всегда удобно и не всегда надежно), вариант два — с помощью haproxy проверять клиентский сертификат и разруливать по его наличию, вариант три — дождаться повсеместного внедрения ECH и разруливать по доменному имени (но это видимо еще не скоро), вариант четыре — особая магия, с которой я сейчас экспериментирую, если получится, запилю статью.
                                                                                                                              +1
                                                                                                                              На самом деле вообще-то SoftEther позволяет статичный сайт поднять вроде. Была где-то документация на эту тему, там надо папку создать, в неё закинуть файлы и они будут вместо стандартного отклика отдаваться, если я правильно помню.
                                                                                                                                0
                                                                                                                                Интересно было бы увидеть мануал, беглый поиск результатов не дал.
                                                                                                                                И не менее важный вопрос — что именно оно выдаст, если пробовать подключиться к серверу не просто браузером, а именно VPN-клиентом, пусть и без корректных реквизитов. Потому что если оно выдает «сайт с котиками» только при попытке открыть через браузер, то умному active-prober'у сервер сдаст себя с потрохами.
                                                                                                                                  0
                                                                                                                                  Реквизиты то передаются по PPP инкапсулированному в HTTPS-запросы/ответы, так что там-то понятное дело что будет понятно что это VPN. Это, конечно, если про SSTP говорить. Впрочем с OpenConnect-ом тоже, похоже, что всё не так просто, он там тоже отдаёт вполне стандатные пакеты перед авторизацией (или для неё).
                                                                                                                                  При большом желании можно финализировать TLS тем же NGINX-ом, легитимных клиентов пускать дальше как прокси, а нелегитимных — отдавать что угодно, хоть котиков, хоть собачек.
                                                                                                                                    0
                                                                                                                                    Ну вот собственно все упирается в вопрос, как надежно, невидимо со стороны и не ломая совместимость с клиентским софтом определять легитимность клиента. Вариант раз — по клиентскому сертификату (честно говоря не помню, шлют ли в TLS клиенты по умолчанию сертификат сразу при хендшейке если он у них есть, или же сервер должен запрашивать его сам — в первом случае все ок, а во втором случае уже подозрительно).
                                                                                                                                    Вариант два — по каким-то секретным хедерам/сигнатурам/урлу/etc. первого запроса, и далее целиком зеркалить stream на прокси, но Nginx, судя по всему такое ниасилит, а вот Haproxy, кажется, может, но надо тестировать.
                                                                                                                                      0
                                                                                                                                      Ну почему не осилит-то =) Вопрос скорее чего именно мы хотим добиться. Узнать что сертификат клиент переслал — с TLSv1.3 точно не получится, в TLSv1.2 ещё можно отследить, примерно так же как я вычитываю здесь серверный, можно также вычитать и клиентский.
                                                                                                                                      Особым запросом — это нечто вроде «port knocking», вполне можно сделать так, чтобы по дефолту NGINX финализировал TLS, но если получает какой-то спецзапрос — то добавляет ИП адрес который этот запрос отправил в список и далее весь трафик проксирует напрямую VPN-у.
                                                                                                                                      Но это всё конечно требует поддержки с клиентской стороны.
                                                                                                                                        0
                                                                                                                                        Но это всё конечно требует поддержки с клиентской стороны.

                                                                                                                                        Ну вот например все клиенты OpenConnect позволяют после последнего слэша в урле подключения к серверу написать любой мусор, вполне себе передают этот мусор на сервер, а сервер его вполне себе игнорирует и в итоге устанавливает соединение с клиентом. То есть используя урл типа «server.domain/someSecretString» вполне себе можно было бы отделять своих от чужих именно по знанию этого someSecretString, который будет передаваться уже в зашифрованном виде и никто о нем не узнает.
                                                                                                                                        Вот только тут проблема в том, чтоя не нашел способа заставить Nginx после подпадания первого запроса под какое-то условие начинать его тупо stream'ить не разбираясь на какой-нибудь бэкенд. А в противном случае он по-прежнему анализирует каждый запрос при хендшейке, в итоге натыкается на метод CONNECT, и отваливается, потому что не умеет в него. А вот возможности Haproxy для этого выглядят многообещающе, но все руки не доходят попробовать написать конфиг и протестировать.

                                                                                                                                        нечто вроде «port knocking», вполне можно сделать так, чтобы по дефолту NGINX финализировал TLS, но если получает какой-то спецзапрос — то добавляет ИП адрес который этот запрос отправил в список и далее весь трафик проксирует напрямую VPN-у.
                                                                                                                                        Я подобное делал с разруливанием на уровне файервола: github.com/uprt/labean После получения специального запроса, для заданного IP на заданное время (например, 30 секунд) входящие подключения на 443 порт перекидываются не на Nginx, а на VPN-сервер. Правда, во-первых это неудобно (руками каждый раз дергать curl перед подключением), а во-вторых, если active prober'а стоит за тем же NAT'ом что и клиент, то отправляя запрос с того же IP точно так же попадет куда не надо. Хотя, можно докрутить туда скриптик, который будет смотреть, установилось ли подключение, и сразу же удалять правило, но это еще надо обдумать на тему целесообразности всего этого.
                                                                                                                                          0
                                                                                                                                          На самом деле под NGINX есть модуль поддержки CONNECT, насколько я помню =) Ну либо можно наколхозить свой посредством всё того же OpenResty и Lua.
                                                                                                                                            0
                                                                                                                                            Главное чтобы понимание этого «CONNECT» у Nginx совпадало с понимаем Ocserv, а то всякое может быть :)
                                                                                                                                            С Lua — да, вариант, может сработать.
                                                                                                                              0
                                                                                                                              sslh
                                                                                                                                0
                                                                                                                                Нет. sslh делает тот же самый сигнатурный анализ хендшейка, а SSTP/OpenConnect/Softether в этом плане не отличается от обычного HTTPS вообще никак, и sslh просто не распознает корректно тип конкретного соединения (и это хорошо, ведь если бы мог sslh, то то же самое мог бы и сторонний DPI).
                                                                                                                      +1

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

                                                                                                                        +1
                                                                                                                        блокируют только на конечных пользователях
                                                                                                                        Не всегда. Иногда можно наткнуться на фильтрацию у магистралов.
                                                                                                                        У меня с одного из российских VPS-хостеров периодически (но без какой-либо закономерности) не открываются Linkedin и Rutracker, например.
                                                                                                                          +2
                                                                                                                          Скажите это МТС, которая фильтрует транзитный трафик.

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

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


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


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


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


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

                                                                                                                              +1

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

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

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


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

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

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

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

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

                                                                                                                                      image
                                                                                                                                        0
                                                                                                                                        Неверно, блокировка дйствует только на уровне местных провайдеров, мтс, билайна, мегафона…
                                                                                                                                        Если поднять свой сервер в ДЦ, например, в МСК, то все блокировки будут обходиться.
                                                                                                                                        Не всегда. Иногда можно наткнуться на фильтрацию у магистралов.
                                                                                                                                        У меня с одного из российских VPS-хостеров периодически (но без какой-либо закономерности) не открываются Linkedin и Rutracker, например.
                                                                                                                                        0
                                                                                                                                        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
                                                                                                                                          0
                                                                                                                                          Ощущение будто у вас 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.
                                                                                                                                          0

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

                                                                                                                                            0

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

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

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

                                                                                                                                                  0

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

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

                                                                                                                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                                                                                  Самое читаемое