Waujito / youtubeUnblock

Bypasses Deep Packet Inspection (DPI) systems that rely on SNI
GNU General Public License v3.0
661 stars 42 forks source link

OpenWrt feed #53

Open bam80 opened 1 month ago

bam80 commented 1 month ago

The next step I suppose would be creating an OpenWrt feed for easy installation/upgrade procedure.

Originally posted by @bam80 in https://github.com/Waujito/youtubeUnblock/issues/36#issuecomment-2282291296

spvkgn commented 1 month ago

Можно реализовать через GH Pages в отдельном бранче. Есть уже готовые actions для этого. Еще понадобится создать ключ для подписи пакетов и указать private ключ в настройках Actions - Secrets.

Waujito commented 1 month ago

Let's go OpenWRT repository, OpenWRT config, luci interface, youtubeUnblock hardware...

Как будто бы, репозиторий для опенврт это уже оверхед. Я не думаю, что зайти в github actions, выкачать оттуда версию программы и загрузить на роутер это сложно.

Но вот мне бы хотелось усовершенствовать поведение самой программы на роутере. К примеру, сейчас есть автоматическая установка правил только для nftables, и то она требует скачивать зависимости руками, чтобы поддерживать совместимость с версиями openwrt на iptables. Также необходимо сделать конфигурацию конф. файлами, а не аргументами, которые плохо подходят под /etc/init.d скрипты. Да и про luci я пошутил, но как будто UI интерфейс для взаимодействия вообще без консоли - очень заманчивая вещь, но luci должен взаимодействовать с конфигурационными файлами.

bam80 commented 1 month ago

@Waujito let's be on topic here, please create a separate issues for that improvements you found.

I think the feed is still good thing to have, especially if we see further releases in the future. And it shouldn't be too hard to implement.

If nobody wants to work on it, please let me know, I'll try for myself.

spvkgn commented 1 month ago

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

Увы, без создания GH аккаунта скачать там не получится. Обычно принято из Release скачивать.

Также необходимо сделать конфигурацию конф. файлами, а не аргументами, которые плохо подходят под /etc/init.d скрипты.

Можно обойтись без конфига, в OpenWrt немало пакетов где возможные аргументы перечислены в инит-скрипте.

Waujito commented 1 month ago

Увы, без создания GH аккаунта скачать там не получится. Обычно принято из Release скачивать.

Это проблема. А есть способ автоматически прикреплять все таргеты в релиз?

Можно обойтись без конфига, в OpenWrt немало пакетов где возможные аргументы перечислены в инит-скрипте.

Даже luci с этим работает?

Насчёт репозитория в целом можно его сделать. Возможно, эти ресурсы помогут: https://github.com/hnw/openwrt-packages/blob/master/.travis.yml https://github.com/tfsaggregator/aggregator-cli/blob/master/.github/workflows/build-and-deploy.yml

zabbius commented 1 month ago

@Waujito Давай я поковыряю конфиги, стартовый скрипт и все вот это?

spvkgn commented 1 month ago

Это проблема. А есть способ автоматически прикреплять все таргеты в релиз?

Можно добавить Release workflow для всех сразу (owrt, static, entware), который триггерится на push tag и аплоадить все артифакты в отдельном job, например как здесь https://github.com/spvkgn/youtubeUnblock/blob/4f9ab69b37f1ed5dfe8dace57ca05499f287094f/.github/workflows/build-openwrt.yml#L93C3-L116C32

Даже luci с этим работает?

Там через uci можно читать/править опции. Где-то тут было про это https://openwrt.org/docs/guide-developer/config-scripting

Вот как прииер, для пакета ByeDPI набросал подобное, там тоже только аргументы.

YBS-PC commented 1 week ago

Также необходимо сделать конфигурацию конф. файлами, а не аргументами

если надо, хоть просто и не эстетично, но мой конфиг файл /etc/config/youtubeUnblock

config youtubeUnblock config
    option 1 --packet-mark=524288
    option 2 --frag-sni-reverse=0
    option 3 --silent

мой инит файл /etc/init.d/youtubeUnblock

#!/bin/sh /etc/rc.common
USE_PROCD=1

START=99
STOP=01

# Openwrt procd script: https://openwrt.org/docs/guide-developer/procd-init-script-example
# The program should be put into /usr/bin/
# This file should be put into /etc/init.d/

start_service() {

config_load youtubeUnblock
config_get ARG1 config 1
config_get ARG2 config 2
config_get ARG3 config 3
config_get ARG4 config 4

    procd_open_instance
    procd_set_param command /usr/bin/youtubeUnblock "$ARG1" "$ARG2" "$ARG3" "$ARG4" "$ARG5"

    procd_set_param nice -20

    procd_set_param stdout 1
    procd_set_param stderr 1

    procd_close_instance
}

вроде работает /usr/bin/youtubeUnblock --packet-mark=524288 --frag-sni-reverse=0 --silent

YBS-PC commented 1 week ago

если кому то надо сделал вот такой вариант уже с отображением статуса Снимок экрана 2024-09-1 Снимок экрана 2024-09- для этого используется файл /usr/lib/lua/luci/controller/youtubeUnblock.lua

module("luci.controller.youtubeUnblock", package.seeall)

function index()
    -- Добавляем пункт меню в разделе "Services" (Службы)
    entry({"admin", "services", "youtubeUnblock"}, cbi("youtubeUnblock"), _("YouTube Unblock"), 100)
end

еще /usr/lib/lua/luci/model/cbi/youtubeUnblock.lua

local m, s, o

-- Создание модели для формы
m = Map("youtubeUnblock", translate("YouTube Unblock Settings"))

-- Создание секции
s = m:section(NamedSection, "main", "youtubeUnblock", translate("Настройки YouTube Unblock"))

-- Определение функции для получения аргументов командной строки без пути к исполняемому файлу
local function get_cmdline(pid)
    if pid and pid ~= "" then
        local cmdline = luci.sys.exec("cat /proc/" .. pid .. "/cmdline")
        if cmdline then
            -- Заменяем нулевые байты на пробелы и сжимаем несколько пробелов в один
            cmdline = cmdline:gsub("%z", " "):gsub("%s+", " ")

            -- Находим первую пробел и удаляем все до и включая его
            local _, pos = cmdline:find(" ")
            if pos then
                cmdline = cmdline:sub(pos + 1)
            end

            return cmdline
        end
    end
    return nil
end

-- Поле для отображения результата команды 'ps | grep youtubeUnblock'
o = s:option(DummyValue, "_ps_output", translate("Статус процесса YouTube Unblock"))
o.rawhtml = true
o.cfgvalue = function(self, section)
    -- Получаем PID процесса
    local pid = luci.sys.exec("pgrep -f youtubeUnblock")
    pid = pid:gsub("%s+", "") -- Удаление лишних пробелов и новых строк

    -- Проверяем, существует ли PID
    if pid and pid ~= "" then
        -- Извлекаем командную строку процесса
        local cmd_line = get_cmdline(pid)

        -- Проверяем, есть ли команда
        if cmd_line and #cmd_line > 0 then
            -- Заменяем пробелы на <br> для переноса на новую строку
            cmd_line = string.gsub(cmd_line, " ", "<br>")
            return "<div><span style='color: green;'>Процесс найден с аргументами:</span><br/><pre style='white-space: pre-wrap; word-wrap: break-word;'>" .. cmd_line .. "</pre></div>"
        else
            return "<div><span style='color: red;'>Процесс найден, но не удалось извлечь аргументы</span></div>"
        end
    else
        return "<div><span style='color: red;'>Процесс не найден</span></div>"
    end
end

-- Поле для отображения результата команды 'youtubeUnblock status'
o = s:option(DummyValue, "_ytb_status", translate("Статус YouTube Unblock"))
o.rawhtml = true
o.cfgvalue = function(self, section)
    -- Проверяем, запущен ли процесс youtubeUnblock
    local pid = luci.sys.exec("pgrep -f youtubeUnblock")
    pid = pid:gsub("%s+", "")

    if pid and #pid > 0 then
        -- Если процесс запущен, получаем его статус
        local status = luci.sys.exec("youtubeUnblock status")
        if status and #status > 0 and not status:match("не запущен") then
            return "<div><span style='color: green;'>Сервис запущен:</span><br/><pre style='white-space: pre-wrap; word-wrap: break-word;'>" .. status .. "</pre></div>"
        else
            return "<div><span style='color: red;'>Сервис запущен, но статус неизвестен</span></div>"
        end
    else
        -- Если процесс не запущен, выводим сообщение об этом
        return "<div><span style='color: red;'>Сервис не запущен</span></div>"
    end
end

-- Поле ввода для параметра $YtbUb_PARAM
o = s:option(Value, "YtbUb_PARAM", translate("Параметры для YouTube Unblock"))
o.placeholder = translate("Введите параметр для YouTube Unblock")
o.datatype = "string"
o.description = translate("Введите параметр для YouTube Unblock, который будет передан в команду.")
o.cfgvalue = function(self, section)
    local value = Value.cfgvalue(self, section)
    return value
end
o.template = "cbi/tvalue"
o.width = "100%"

-- Поле ввода для IP-адресов
o = s:option(Value, "quic_drop_ip", translate("IP клиента для сброса QUIC пакетов"))
o.placeholder = translate("Введите IP-адрес или несколько IP-адресов, разделенных пробелами")
o.datatype = "string"
o.description = translate("Введите IP-адреса для блокировки QUIC трафика.")
o.template = "cbi/tvalue"
o.width = "100%"

-- Кнопка для применения настроек
o = s:option(Button, "_apply", translate("Применить"))
o.inputtitle = translate("Применить изменения")
o.inputstyle = "apply"
o.description = translate("Примените изменения для перезапуска службы YouTube Unblock и настройки блокировки IP.")
o.write = function(self, section)
    -- Получаем параметры
    local ytb_param = self.map:get(section, "YtbUb_PARAM")
    local quic_ips = self.map:get(section, "quic_drop_ip")

    -- Если значение IP пустое, устанавливаем его в 0
    if not quic_ips or #quic_ips == 0 then
        quic_ips = "0"
    end

    -- Формируем конфигурационный файл
    local config_content = string.format(
        "config youtubeUnblock 'main'\n\toption YtbUb_PARAM '%s'\n\toption quic_drop_ip '%s'\n",
        ytb_param or "",  -- Убедитесь, что параметр не равен nil
        quic_ips or ""    -- Убедитесь, что IP-адреса не равны nil
    )

    -- Записываем конфигурацию в файл
    local file = io.open("/etc/config/youtubeUnblock", "w")
    if file then
        file:write(config_content)
        file:close()
    end

    -- Очищаем старые правила
    luci.sys.call("sed -i '/insert rule inet fw4 forward ip saddr/d' /usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft")

    -- Если IP не указаны, устанавливаем пустое значение
    if quic_ips == "0" then
        luci.sys.call("uci set youtubeUnblock.main.quic_drop_ip='0'")
    else
        local ips = quic_ips:gsub("%s+", " "):gmatch("%S+")
        for ip in ips do
            local cmd = string.format("echo 'insert rule inet fw4 forward ip saddr %s udp dport 443 counter drop' >> /usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft", ip)
            luci.sys.exec(cmd)  -- Выполняем команду
        end
    end

    -- Применяем изменения UCI
    luci.sys.call("uci commit youtubeUnblock")

    -- Перезапуск служб
    luci.sys.call("service youtubeUnblock stop && service youtubeUnblock disable")
    luci.sys.call("sed -i 's/mangle_forward/mangle_postrouting/' /usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft")
    luci.sys.call("service youtubeUnblock enable && service youtubeUnblock start")
    luci.sys.call("service firewall restart")
end

-- Поле с подсказками
local help = s:option(DummyValue, "_help", "Доступные флаги")
help.rawhtml = true
help.template = "cbi/tvalue" -- Используем шаблон для отображения текстовой области
help.value = [[
--sni-domains=<список доменов> | all: Задаёт список доменов для обработки через SNI.
    По умолчанию: googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com
--exclude-domains=<список доменов>: Исключает указанные домены из обработки, полезно, если используете --sni-domains=all.
--queue-num=<номер очереди>: Номер netfilter очереди, по умолчанию 537.
--fake-sni={0|1}: Включает фальсификацию SNI для отправки нескольких пакетов с ClientHello. По умолчанию 1.
--fake-sni-seq-len=<длина>: Определяет количество фальшивых пакетов ClientHello. По умолчанию 1.
--faking-strategy={randseq|ttl|tcp_check|pastseq}: Стратегия подделки пакетов. По умолчанию pastseq.
    randseq: Устанавливает случайную последовательность/подтверждение.
    ttl: Пакет будет отброшен после --faking-ttl=n узлов. TTL предпочтительнее, но может вызвать проблемы, если неправильно настроен.
    pastseq: Похож на randseq, но последовательность основана на пакете, отправленном ранее.
    tcp_check: Поддельный пакет будет отброшен с недопустимой контрольной суммой. Может системами DPI (TSPU).
--faking-ttl=<ttl>: Устанавливает TTL для фальшивых SNI сообщений. По умолчанию 8.
--fake-seq-offset: Смещение последовательности для фальшивых пакетов. По умолчанию 10000.
--frag={tcp,ip,none}: Стратегия фрагментации. По умолчанию tcp.
--frag-sni-reverse={0|1}: Отправляет фрагменты ClientHello в обратном порядке. По умолчанию 1.
--frag-sni-faked={0|1}: Отправляет фальшивые пакеты рядом с ClientHello. По умолчанию 0.
--frag-middle-sni={0|1}: Разделяет пакет посередине данных SNI. По умолчанию 1.
--frag-sni-pos=<позиция>: Определяет позицию разделения пакета SNI. По умолчанию 1.
--quic-drop: Блокирует все QUIC пакеты для YouTube. Не затрагивает другие UDP пакеты.
--fk-winsize=<размер окна>: Определяет размер окна для фрагментированных TCP пакетов. Может замедлить подключение.
--synfake={1|0}: Включает отправку данных в SYN-пакетах для обхода блокировок. По умолчанию 1.
--synfake-len=<длина>: Определяет длину фальшивого пакета SYN. По умолчанию 0 (отправить весь фальшивый пакет).
--sni-detection={parse|brute}: Способ обнаружения SNI. По умолчанию parse.
--seg2delay=<задержка>: Задержка перед отправкой второй части пакета.
--silent: Отключает подробные сообщения.
--trace: Включает максимальный уровень отладки.
--no-gso: Отключает поддержку GSO для больших пакетов Google Chrome.
--no-ipv6: Отключает поддержку IPv6.
--threads=<число потоков>: Количество потоков для работы программы. По умолчанию 1.
--packet-mark=<метка>: Используйте для изменения метки пакетов, если она конфликтует с другими системами.
]]
help.wrap = "off" -- Отключаем перенос, чтобы текст выглядел аккуратно
help.rows = 33    -- Устанавливаем высоту поля
help.readonly = true -- Делаем поле только для чтения

-- Установка CSS стилей для поля с подсказками
help.template = "cbi/tvalue"
help.width = "100%" -- Установка ширины поля с подсказками

return m

Последняя строка ответа youtubeUnblock status не отображается - не знаю почему (если кто то улучшит, было бы хорошо) еще echo -e "config youtubeUnblock 'main'\n\toption YtbUb_PARAM ''\n\toption quic_drop_ip ''" | tee /etc/config/youtubeUnblock

и для инита sed -i 's/START=[0-9][0-9]/START=99/' /etc/init.d/youtubeUnblock sed -i 's/STOP=[0-9][0-9]/STOP=01/' /etc/init.d/youtubeUnblock sed -i '/procd_set_param command/d' /etc/init.d/youtubeUnblock sed -i '/start_service/a\n config_load youtubeUnblock\n config_get ARGS main YtbUb_PARAM\n' /etc/init.d/youtubeUnblock sed -i '/procd_open_instance/a\tprocd_set_param command /usr/bin/youtubeUnblock $ARGS' /etc/init.d/youtubeUnblock

YBS-PC commented 1 week ago

не знаю что означает последнее сообщение в статусе сервиса "Вероятно, запущен другой экземпляр youtubeUnblock с тем же номером очереди.", но вроде все работает. Может автор подскажет что это и как исправить?

youtubeUnblock status
youtubeUnblock
Bypasses deep packet inspection systems that relies on SNI

Using TCP segmentation
Fake SNI will be sent before each target client hello
Fragmentation Client Hello will be reversed
Past seq faking strategy will be used
GSO is enabled
IPv6 is enabled
Queue 537 started
mnl_cb_run: Operation not permitted
Probably another instance of youtubeUnblock with the same queue number is running
Thread 0 exited with status -1
Waujito commented 1 week ago

Probably another instance of youtubeUnblock with the same queue number is running

То и значит) Где то болтается ещё один демон youtubeUnblock. Поищите его ps -e | grep youtube

Я тут вроде бы сделал красивый сервис с настройками. Единственное, что сейчас не работает - если сделать luci.sys.call("/etc/init.d/youtubeUnblock restart") по кнопке, может возникнуть ошибка Bad Gateway и Wed Sep 11 20:22:03 2024 daemon.err uhttpd[4937]: Command failed: ubus call service delete { "name": "youtubeUnblock" } (Not found). Не сталкивались?

YBS-PC commented 1 week ago

daemon.err uhttpd[4937]: Command failed: ubus call service delete { "name": "youtubeUnblock" } (Not found)

Не сталкивался с таким

Где то болтается ещё один демон youtubeUnblock

oWRT:~# ps | grep youtube 3541 root 1128 S< /usr/bin/youtubeUnblock --packet-mark=524288 --frag-sni-reverse=0 --silent 6563 root 1680 S grep youtube вроде не болтается нигде. Без silent в логах (firewall перезагружается после применения настроек)

Thu Sep 12 00:01:05 2024 daemon.err uhttpd[6369]: [info] luci: accepted login on / for root from 192.168.2.2
Thu Sep 12 00:01:08 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:08 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: youtubeUnblock
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: Bypasses deep packet inspection systems that relies on SNI
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]:
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: Using TCP segmentation
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: Fake SNI will be sent before each target client hello
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: Past seq faking strategy will be used
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: GSO is enabled
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: IPv6 is enabled
Thu Sep 12 00:01:16 2024 daemon.info youtubeUnblock[6718]: Queue 537 started
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[1] (Reject-IPv6) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[2] (Allow-IGMP) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[3] (Allow-IPTV-IGMPPROXY) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[4] (Allow-IPTV-ALL) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[5] (Allow-Ping) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[6] (Allow-DHCPv6) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[7] (Allow-MLD) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[8] (Allow-ICMPv6-Input) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[9] (Allow-ICMPv6-Forward) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[16] (xbox_12-30_17-30) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @rule[19] (emin-pc_12-30_17-30) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Section @redirect[15] (DNS_to_Brume) is disabled, ignoring section
Thu Sep 12 00:01:17 2024 daemon.err uhttpd[6369]: [!] Automatically including '/usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft'
Thu Sep 12 00:01:18 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:18 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:21 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:21 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:27 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:01:27 2024 daemon.err uhttpd[6369]: Thread 0 exited with status -1
Thu Sep 12 00:03:45 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: content-autofill.googleapis.com
Thu Sep 12 00:04:05 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: optimizationguide-pa.googleapis.com
Thu Sep 12 00:04:05 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: www.youtube.com
Thu Sep 12 00:04:05 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: i.ytimg.com
Thu Sep 12 00:04:07 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr3---sn-q4flrne7.googlevideo.com
Thu Sep 12 00:04:07 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr3---sn-q4flrne7.googlevideo.com
Thu Sep 12 00:04:07 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr3---sn-q4flrne7.googlevideo.com
Thu Sep 12 00:04:07 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr3---sn-q4flrne7.googlevideo.com
Thu Sep 12 00:04:08 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: accounts.youtube.com
Thu Sep 12 00:04:08 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: www.gstatic.com
Thu Sep 12 00:04:08 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: jnn-pa.googleapis.com
Thu Sep 12 00:04:08 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr3---sn-q4flrne7.googlevideo.com
Thu Sep 12 00:04:09 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr3---sn-q4flrne7.googlevideo.com
Thu Sep 12 00:04:10 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr2---sn-85po5iuxaxjvh-bg8l.googlevideo.com
Thu Sep 12 00:04:10 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr1---sn-85po5iuxaxjvh-bg8l.googlevideo.com
Thu Sep 12 00:04:10 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr10---sn-n8v7kn76.googlevideo.com
Thu Sep 12 00:04:11 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr1---sn-85po5iuxaxjvh-bg8l.googlevideo.com
Thu Sep 12 00:04:11 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr1---sn-85po5iuxaxjvh-bg8l.googlevideo.com
Thu Sep 12 00:04:14 2024 daemon.info youtubeUnblock[6718]: Target SNI detected: rr11---sn-n8v7znzl.googlevideo.com

Я тут вроде бы сделал красивый сервис с настройками.

Буду ждать значит вашу реализацию

Waujito commented 1 week ago

3541 root 1128 S< /usr/bin/youtubeUnblock --packet-mark=524288 --frag-sni-reverse=0 --silent

Так вот же он. Из-за него не запускается еще один инстанс анблока. Два не могут одновременно существовать

YBS-PC commented 1 week ago

3541 root 1128 S< /usr/bin/youtubeUnblock --packet-mark=524288 --frag-sni-reverse=0 --silent

Так вот же он. Из-за него не запускается еще один инстанс анблока. Два не могут одновременно существовать

я не пытаюсь запустить еще один. этот запущен и все.

youtubeUnblock status
youtubeUnblock
Bypasses deep packet inspection systems that relies on SNI

Using TCP segmentation
Fake SNI will be sent before each target client hello
Fragmentation Client Hello will be reversed
Past seq faking strategy will be used
GSO is enabled
IPv6 is enabled
Queue 537 started
mnl_cb_run: Operation not permitted
Probably another instance of youtubeUnblock with the same queue number is running
Thread 0 exited with status -1

это сразу после перезагрузки роутера. Даже снес все и установил чисто отсюда новую develop версию без каких либо настроек и все равно это сообщение (возможно внутренне что-то) - ну и ладно, вроде не мешает. Оказывается проблема была в этом local status = luci.sys.exec("youtubeUnblock status") что запускало новый демон youtubeUnblock с опцией status. исправил на service youtubeUnblock status

YBS-PC commented 1 week ago

luci.sys.call("/etc/init.d/youtubeUnblock restart")

У меня там есть и disable/enable и stop/start и таких ошибок не было. luci.sys.call("service youtubeUnblock stop && service youtubeUnblock disable") luci.sys.call("service youtubeUnblock enable && service youtubeUnblock start") luci.sys.call("service firewall restart") И это все и другие команды выполняются при нажатии кнопки. Может попробуете так или что-то из этого

Waujito commented 1 week ago

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

YBS-PC commented 1 week ago

Ок. Ждем значит полноценную luci реализацию. Удачи. И в реадми может надо исправить --faking-strategy={randseq|ttl|tcp_check|pastseq} This flag determines the strategy of fake packets invalidation. Defaults to randseq вроде по умолчанию pastseq, а не randseq

YBS-PC commented 6 days ago

немного доработал /usr/lib/lua/luci/model/cbi/youtubeUnblock.lua. Просто пусть будет , если кому то поможет

local m, s, o

-- Создание модели для формы
m = Map("youtubeUnblock", translate("YouTube Unblock Settings"))

-- Создание секции
s = m:section(NamedSection, "main", "youtubeUnblock", translate("Настройки YouTube Unblock"))

-- Определение функции для получения аргументов командной строки без пути к исполняемому файлу
local function get_cmdline(pid)
    if pid and pid ~= "" then
        local cmdline = luci.sys.exec("cat /proc/" .. pid .. "/cmdline")
        if cmdline then
            -- Заменяем нулевые байты на пробелы и сжимаем несколько пробелов в один
            cmdline = cmdline:gsub("%z", " "):gsub("%s+", " ")

            -- Находим первую пробел и удаляем все до и включая его
            local _, pos = cmdline:find(" ")
            if pos then
                cmdline = cmdline:sub(pos + 1)
            end

            return cmdline
        end
    end
    return nil
end

-- Поле для отображения результата команды 'ps | grep youtubeUnblock'
o = s:option(DummyValue, "_ps_output", translate("Статус процесса YouTube Unblock"))
o.rawhtml = true
o.cfgvalue = function(self, section)
    -- Получаем PID процесса
    local pid = luci.sys.exec("pgrep -f youtubeUnblock")
    pid = pid:gsub("%s+", "") -- Удаление лишних пробелов и новых строк

    -- Проверяем, существует ли PID
    if pid and pid ~= "" then
        -- Извлекаем командную строку процесса
        local cmd_line = get_cmdline(pid)

        -- Проверяем, есть ли команда
        if cmd_line and #cmd_line > 0 then
            -- Заменяем пробелы на <br> для переноса на новую строку
            cmd_line = string.gsub(cmd_line, " ", "<br>")
            return "<div><span style='color: green;'>Процесс найден с аргументами:</span><br/><pre style='white-space: pre-wrap; word-wrap: break-word;'>" .. cmd_line .. "</pre></div>"
        else
            return "<div><span style='color: red;'>Процесс найден, но не удалось извлечь аргументы</span></div>"
        end
    else
        return "<div><span style='color: red;'>Процесс не найден</span></div>"
    end
end

-- Поле для отображения результата команды 'youtubeUnblock status'
o = s:option(DummyValue, "_ytb_status", translate("Статус YouTube Unblock"))
o.rawhtml = true
o.cfgvalue = function(self, section)
    -- Проверяем, запущен ли процесс youtubeUnblock
    local pid = luci.sys.exec("pgrep -f youtubeUnblock")
    pid = pid:gsub("%s+", "")

    if pid and #pid > 0 then
        -- Если процесс запущен, получаем его статус
        local status = luci.sys.exec("service youtubeUnblock status")
        status = status:match("%S+") -- Извлекаем первый статус из вывода

        if status == "running" then
            -- Если статус "running", выводим зелёный цвет для ответа
            return "<pre style='color: green; font-size: 16px; font-weight: bold; white-space: pre-wrap; word-wrap: break-word;'>Сервис запущен</pre>"
        elseif status == "stopped" then
            -- Если статус "stopped", выводим красный цвет для ответа
            return "<pre style='color: red; font-size: 16px; font-weight: bold; white-space: pre-wrap; word-wrap: break-word;'>Сервис остановлен</pre>"
        else
            -- Для других статусов выводим текст с неизвестным статусом
            return "<pre style='color: orange; font-size: 16px; font-weight: bold; white-space: pre-wrap; word-wrap: break-word;'>Статус неизвестен</pre>"
        end
    else
        -- Если процесс не запущен, выводим сообщение об этом
        return "<pre style='color: red; white-space: pre-wrap; word-wrap: break-word;'>Сервис не запущен</pre>"
    end
end

-- Поле ввода для параметра $YtbUb_PARAM
o = s:option(Value, "YtbUb_PARAM", translate("Параметры для YouTube Unblock"))
o.placeholder = translate("Введите параметр для YouTube Unblock")
o.datatype = "string"
o.description = translate("Введите параметр для YouTube Unblock, который будет передан в команду.")
o.cfgvalue = function(self, section)
    local value = Value.cfgvalue(self, section)
    return value
end
o.template = "cbi/tvalue"
o.width = "100%"

-- Поле ввода для IP-адресов
o = s:option(Value, "quic_drop_ip", translate("IP клиента для сброса QUIC пакетов"))
o.placeholder = translate("Введите IP-адрес или несколько IP-адресов, разделенных пробелами")
o.datatype = "string"
o.description = translate("Введите IP-адрес или несколько IP-адресов, разделенных пробелами для блокировки QUIC трафика.")
o.template = "cbi/tvalue"
o.width = "100%"

-- Кнопка для применения настроек
o = s:option(Button, "_apply", translate("Применить"))
o.inputtitle = translate("Применить изменения")
o.inputstyle = "apply"
o.description = translate("Примените изменения для перезапуска службы YouTube Unblock и настройки блокировки IP.")
o.write = function(self, section)
    -- Получаем параметры
    local ytb_param = self.map:get(section, "YtbUb_PARAM")
    local quic_ips = self.map:get(section, "quic_drop_ip")

    -- Если значение IP пустое, устанавливаем его в 0
    if not quic_ips or #quic_ips == 0 then
        quic_ips = "0"
    end

    -- Формируем конфигурационный файл
    local config_content = string.format(
        "config youtubeUnblock 'main'\n\toption YtbUb_PARAM '%s'\n\toption quic_drop_ip '%s'\n",
        ytb_param or "",  -- Убедитесь, что параметр не равен nil
        quic_ips or ""    -- Убедитесь, что IP-адреса не равны nil
    )

    -- Записываем конфигурацию в файл
    local file = io.open("/etc/config/youtubeUnblock", "w")
    if file then
        file:write(config_content)
        file:close()
    end

    -- Очищаем старые правила
    luci.sys.call("sed -i '/insert rule inet fw4 forward ip saddr/d' /usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft")

    -- Если IP не указаны, устанавливаем пустое значение
    if quic_ips == "0" then
        luci.sys.call("uci set youtubeUnblock.main.quic_drop_ip='0'")
    else
        local ips = quic_ips:gsub("%s+", " "):gmatch("%S+")
        for ip in ips do
            local cmd = string.format("echo 'insert rule inet fw4 forward ip saddr %s udp dport 443 counter drop' >> /usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft", ip)
            luci.sys.exec(cmd)  -- Выполняем команду
        end
    end

    -- Применяем изменения UCI
    luci.sys.call("uci commit youtubeUnblock")

    -- Перезапуск служб
    luci.sys.call("service youtubeUnblock stop && service youtubeUnblock disable")
    luci.sys.call("sed -i 's/mangle_forward/mangle_postrouting/' /usr/share/nftables.d/ruleset-post/537-youtubeUnblock.nft")
    luci.sys.call("service youtubeUnblock enable && service youtubeUnblock start")
    luci.sys.call("service firewall restart")
end

-- Поле с подсказками
local help = s:option(DummyValue, "_help", "Доступные флаги")
help.rawhtml = true
help.template = "cbi/tvalue" -- Используем шаблон для отображения текстовой области
help.value = [[
--sni-domains=<список доменов> | all: Задаёт список доменов для обработки через SNI.
    По умолчанию: googlevideo.com,ggpht.com,ytimg.com,youtube.com,play.google.com,youtu.be,googleapis.com,googleusercontent.com,gstatic.com,l.google.com
--exclude-domains=<список доменов>: Исключает указанные домены из обработки, полезно, если используете --sni-domains=all.
--queue-num=<номер очереди>: Номер netfilter очереди, по умолчанию 537.
--fake-sni={0|1}: Включает фальсификацию SNI для отправки нескольких пакетов с ClientHello. По умолчанию 1.
--fake-sni-seq-len=<длина>: Определяет количество фальшивых пакетов ClientHello. По умолчанию 1.
--faking-strategy={randseq|ttl|tcp_check|pastseq}: Стратегия подделки пакетов. По умолчанию pastseq.
    randseq: Устанавливает случайную последовательность/подтверждение.
    ttl: Пакет будет отброшен после --faking-ttl=n узлов. TTL предпочтительнее, но может вызвать проблемы, если неправильно настроен.
    pastseq: Похож на randseq, но последовательность основана на пакете, отправленном ранее.
    tcp_check: Поддельный пакет будет отброшен с недопустимой контрольной суммой. Может системами DPI (TSPU).
--faking-ttl=<ttl>: Устанавливает TTL для фальшивых SNI сообщений. По умолчанию 8.
--fake-seq-offset: Смещение последовательности для фальшивых пакетов. По умолчанию 10000.
--frag={tcp,ip,none}: Стратегия фрагментации. По умолчанию tcp.
--frag-sni-reverse={0|1}: Отправляет фрагменты ClientHello в обратном порядке. По умолчанию 1.
--frag-sni-faked={0|1}: Отправляет фальшивые пакеты рядом с ClientHello. По умолчанию 0.
--frag-middle-sni={0|1}: Разделяет пакет посередине данных SNI. По умолчанию 1.
--frag-sni-pos=<позиция>: Определяет позицию разделения пакета SNI. По умолчанию 1.
--quic-drop: Блокирует все QUIC пакеты для YouTube. Не затрагивает другие UDP пакеты.
--fk-winsize=<размер окна>: Определяет размер окна для фрагментированных TCP пакетов. Может замедлить подключение.
--synfake={1|0}: Включает отправку данных в SYN-пакетах для обхода блокировок. По умолчанию 1.
--synfake-len=<длина>: Определяет длину фальшивого пакета SYN. По умолчанию 0 (отправить весь фальшивый пакет).
--sni-detection={parse|brute}: Способ обнаружения SNI. По умолчанию parse.
--seg2delay=<задержка>: Задержка перед отправкой второй части пакета.
--silent: Отключает подробные сообщения.
--trace: Включает максимальный уровень отладки.
--no-gso: Отключает поддержку GSO для больших пакетов Google Chrome.
--no-ipv6: Отключает поддержку IPv6.
--threads=<число потоков>: Количество потоков для работы программы. По умолчанию 1.
--packet-mark=<метка>: Используйте для изменения метки пакетов, если она конфликтует с другими системами.
]]
help.wrap = "off" -- Отключаем перенос, чтобы текст выглядел аккуратно
help.rows = 33    -- Устанавливаем высоту поля
help.readonly = true -- Делаем поле только для чтения

-- Установка CSS стилей для поля с подсказками
help.template = "cbi/tvalue"
help.width = "100%" -- Установка ширины поля с подсказками

return m
Waujito commented 5 days ago

И так, я наконец сделал поддержку для luci и заодно uci. Уже доступна в development release.

Всем спасибо за участие! Жду ваш фидбек :)