- BrainTools - https://www.braintools.ru -
Дома я постоянно что-нибудь мастерю, переделываю и пытаюсь заставить работать немного не так, как задумывал производитель. Где-то хочется оживить старое устройство, где-то – связать между собой две вещи, которые официально друг о друге ничего не знают, а иногда просто интересно проверить: «А что будет, если?» В последнее время почти во всех этих затеях мне помогает Чижик. Причем не в формате «спросил у чат-бота, получил пять общих советов и пошел разбираться сам». Мы вместе исследуем устройства, читаем логи, пишем небольшие программы, собираем приложения, проверяем гипотезы и временами долго выясняем, почему одна пропущенная строчка превращает телевизор в задумчивый черный прямоугольник.

Ах да, действующие лица:
Head of SEO & web-аналитики, Тензор (разработчик saby.ru [1]), автор ТГ‑канал «ВладПРО»
Я более 10 лет занимаюсь аналитикой, SEO и управлением командами в digital‑маркетинге. А в своем Телеграм канале [2] и на сайте [3] пишу еще больше про всякое из реального маркетинга. Консультирую по аналитике web‑проектов и настройке инструментов маркетинга, помогаю проводить технические собеседования специалистов по различным типам трафика.
ChatGPT Codex
Домашняя разновидность искусственного интеллекта [4]. Живет в терминале, питается логами и токенами. Имя получилось из согласных букв ChatGPT Codex — Ч-Ж-К. Если немного воображения, выходит Чижик. Если воображения совсем много – инженер по всякому куда можно подключиться по сети и чего-нибудь накодить.
Постепенно таких домашних историй накопилось достаточно много, и я решил ими делиться. Не как идеально вылизанными инструкциями из параллельной вселенной, где все работает с первой попытки, а как кейсами: с исходной проблемой, неудачными подходами, диалогом, диагностикой и конечным результатом.
Возможно, кто-то найдет здесь готовую идею для собственного дома. Кто-то подсмотрит полезный технический прием. А кто-то просто поймет, что ChatGPT Codex можно применять не только для написания очередной функции в рабочем проекте. Иногда ему можно показать старый телевизор, дать доступ к терминалу и спросить: «Чижик, а мы вообще можем с этим что-нибудь сделать?»
Если по ходу чтения у вас появятся идеи, как улучшить описанное решение, – приносите их в комментарии. Туда же можно складывать предложения для следующих экспериментов: что еще попробовать автоматизировать, оживить, связать или убедить работать вопреки документации. Самые интересные варианты мы с Чижиком постараемся проверить на практике – если, конечно, после эксперимента дом все еще будет подключаться к интернету.
Так рождается серия «Очумелые ручки с Чижиком». И начать я решил с телевизора.
У меня есть телевизор LG на webOS. Не музейный экспонат: показывает хорошо, пульт работает, YouTube установлен, экран менять совершенно не хочется. Но возраст у телевизора уже чувствуется. Браузер стал капризным, современные сайты открывает через раз. Официально приложение YouTube на месте. Кнопка есть. Никто в телевизоре не написал огромными буквами «нельзя». Но видео либо не запускается, либо приложение смотрит на меня черным экраном.
Можно было настроить KVN на роутере. Но мне не хотелось:
отправлять через него всю домашнюю сеть;
менять рабочую конфигурацию роутера ради одного устройства;
объяснять остальным домашним, почему после моего эксперимента чайник видит себя в Нидерландах;
покупать новый роутер или отдельную приставку, пока старый телевизор технически исправен.
Хотелось простого пользовательского сценария:
Открыть на телевизоре отдельное приложение.
Нажать «Подключить».
Запустить YouTube.
После просмотра нажать «Отключить».
И я позвал Чижика.
У Чижика есть одна раздражающая, но полезная привычка: перед каждым эффектным техническим решением он пытается выяснить ограничения. Так обнаружились четыре важных обстоятельства.
Телевизор работает на webOS 5, а не на Android TV. APK сюда не поставить.
Владелец телевизора разрешил root-доступ, но только на время установки и диагностики.
Рабочий профиль использует VLESS/TCP/REALITY.
Подключение должно включаться только вручную из приложения.
Последний пункт оказался важным. Поднять туннель при загрузке – легко. Сделать так, чтобы пожилой телевизор загружался как обычно, а специальный маршрут появлялся только по команде с пульта, – уже интереснее.
Для начала я включил на LG опцию «LG Connect Apps / Подключение мобильных устройств». После этого телевизор стал доступен для штатного управления по локальной сети.
Чижик нашел устройство, выполнил сопряжение и проверил, что может открыть приложение и отправить на телевизор нажатие кнопки. Это еще не root и не взлом. Это обычный интерфейс управления webOS – тот же класс возможностей, которым пользуются мобильные пульты.
Сначала мы прошли по очевидной лестнице решений.
У меня уже был готовый профиль. Мы установили клиент, импортировали конфигурацию, ввели учетные данные и нажали Connect. Телевизор некоторое время показывал Checking, после чего снова предлагал подключиться.
Влад:
Он подумал и передумал. Это считается прогрессом?
Чижик:
Безусловно. До этого он даже не думал.
Проверка показала: сама конфигурация синтаксически нормальная, но транспорт до сервера в этой сети не устанавливается. Причина могла находиться снаружи телевизора: фильтрация протокола, особенности маршрута или несовместимость конкретной сборки клиента. Тратить вечность на протокол, который уже на старте не проходит проверку, не стали.
Следом попробовали профиль WireGuard. Он проще и обычно быстрее, но в нашем случае стабильного соединения тоже не получилось. Наличие красивого конфигурационного файла еще не означает, что пакеты доберутся до второй стороны.
В списке кандидатов появился IPsec/strongSwan. Теоретически солидно: взрослый протокол, серьезное название, можно произносить с каменным лицом. Практически на старом webOS это означало бы еще один чужеродный демон, отдельную работу с политиками IPsec и больше движущихся деталей, чем требовалось для одного приложения.
Эту ветку мы не стали превращать в основную. Инженерная зрелость иногда состоит не в том, чтобы собрать еще один комбайн, а в том, чтобы вовремя убрать отвертку.
На компьютере рабочее соединение через VLESS/TCP/REALITY работало стабильно. Значит, задача стала конкретнее: не «найти любой KVN для webOS», а перенести на телевизор именно тот транспорт, который уже проходит через сеть. Для этого подошёл sing-box: один исполняемый файл, поддержка нужного протокола, TUN-интерфейс и возможность работать без тяжелой графической оболочки.
Влад: Давай, Чижик, вещай, тебе слово!
Чижик: Огромное, тебе, человеческое спасибо, хозяин, рассказываю:
Получилась не одна программа, а маленький слоеный пирог:

Почему не дать web-приложению сразу выполнять команды root? Потому что приложение с кнопками не должно быть универсальным пультом от всей операционной системы. Между интерфейсом и root-командами появился крошечный контроллер с тремя жестко заданными действиями. Никакого /exec?command=..., никакого терминала через HTTP.
Теперь разберем слои по порядку.
Внутри телевизора обнаружился ARMv7. Обычная сборка для x86_64, конечно, не запустилась бы: процессор не оценил бы оптимизма. Мы взяли статическую ARMv7-сборку sing-box, проверили контрольную сумму и положили все в отдельный каталог:
var/lib/webosbrew/sing-box/
sing-box
config.json
start.sh
stop.sh
status.sh
supervisor.sh
vless-control
Права тоже имеют значение:
chmod 700 /var/lib/webosbrew/sing-box/sing-box
chmod 700 /var/lib/webosbrew/sing-box/*.sh
chmod 600 /var/lib/webosbrew/sing-box/config.json
Конфигурация содержит адрес сервера, идентификатор клиента и параметры REALITY. В статье их, разумеется, нет. Публиковать действующий ключ в руководстве, уж извольте.
Обезличенная структура выглядела примерно так:
{
"log": {
"level": "info"
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"interface_name": "sb0",
"address": ["172.19.0.1/30"],
"mtu": 1400,
"auto_route": false,
"stack": "gvisor"
}
],
"outbounds": [
{
"type": "vless",
"tag": "proxy",
"server": "<адрес-сервера>",
"server_port": 443,
"uuid": "<секрет>",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"server_name": "<имя-сервера>",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "<публичный-ключ>",
"short_id": "<short-id>"
}
}
}
],
"route": {
"final": "proxy"
}
}
Почему auto_route: false? На обычном современном Linux автоматическое создание маршрутов могло бы сработать сразу. На старом webOS оно вело себя нестабильно. Поэтому я отключил магию и перешел к ручному труду – то есть написал еще один скрипт.
После запуска sing-box создавался интерфейс sb0. Но существование интерфейса еще не означает, что телевизор начнет им пользоваться.
Нужно было:
Запомнить исходный шлюз и сетевой интерфейс.
Оставить отдельный прямой маршрут до KVN-сервера.
Поднять sb0.
Направить через него остальной IPv4-трафик.
Логика [5] скрипта в упрощённом виде:
DEFAULT_GW="$(ip route show default | awk 'NR==1 {print $3}')"
DEFAULT_DEV="$(ip route show default | awk 'NR==1 {print $5}')"
# Сначала сохраняем путь до самого сервера снаружи туннеля.
ip route replace <IP-СЕРВЕРА>/32 via "$DEFAULT_GW" dev "$DEFAULT_DEV"
ip link set sb0 up
# Две половины интернета. Вместе дают 0.0.0.0/0,
# но не уничтожают исходный default route.
ip route replace 0.0.0.0/1 dev sb0
ip route replace 128.0.0.0/1 dev sb0
```
Трюк с двумя маршрутами /1 удобен тем, что они специфичнее стандартного маршрута /0, поэтому весь обычный IPv4-трафик идет в туннель. При этом исходный default route остается на месте и его легко вернуть в работу, удалив два временных правила.
Отдельный /32 до сервера принципиален. Если сначала завернуть вообще все в sb0, соединение с сервером попытается пройти через еще не установленное соединение с сервером. Получится сетевой вариант инструкции «подними себя за волосы».
При отключении порядок обратный:
ip route del 0.0.0.0/1 dev sb0 2>/dev/null || true
ip route del 128.0.0.0/1 dev sb0 2>/dev/null || true
ip route del <IP-СЕРВЕРА>/32 2>/dev/null || true
После этого sing-box завершается, а телевизор снова использует обычный маршрут через роутер.
Первый вариант был почти прекрасен: запускаем процесс, ждем интерфейс, добавляем маршруты. На тесте работает. После перезагрузки – уже не совсем.
Пожилой webOS внес драматургию:
процесс мог стартовать раньше, чем интерфейс был готов;
sb0 существовал, но еще не был поднят;
приложение считало, что команда выполнена, хотя внешний адрес не изменился;
фоновый процесс зависел от стандартного ввода породившей его оболочки.
Так появился supervisor.sh [6]. Он не просто запускает бинарник, а проверяет результат:
запустить sing-box ↓
дождаться появления sb0 ↓
поднять интерфейс ↓
установить маршруты ↓
выполнить HTTPS-проверку наружу ↓
успех → connected
ошибка → удалить маршруты и остановить процесс
Критическая мелочь в start.sh [7] выглядела так:
nohup "$BASE/supervisor.sh" </dev/null >>"$BASE/supervisor.log" 2>&1 &
Именно </dev/null отвязал фоновый процесс от терминальной сессии. Без него ручной запуск проходил нормально, а запуск из приложения иногда оставлял систему в состоянии «вроде начали, но никто не знает, кто теперь отвечает».
status.sh [8] не доверял одному PID-файлу. Статус connected выдавался только тогда, когда одновременно выполнялись несколько условий:
процесс sing-box жив;
интерфейс sb0 поднят;
оба маршрута /1 присутствуют;
контрольный HTTPS-запрос проходит через новый внешний маршрут.
Это важный урок всей затеи: надпись «процесс запущен» и работающая сеть – не одно и то же.
webOS-приложение – это HTML, CSS и JavaScript. Для интерфейса из двух кнопок этого более чем достаточно. Но web-страница не должна напрямую править таблицу маршрутизации. Поэтому Я написал небольшой контроллер на Go. Он слушает только loopback:
const (
address = "127.0.0.1:18081"
baseDir = "/var/lib/webosbrew/sing-box/"
)
У него всего три метода:
GET /start
GET /stop
GET /status
Для запуска разрешены только два заранее известных файла:
func launchScript(name string) error {
if name != "start.sh" && name != "stop.sh" {
return errors.New("invalid script")
}
// запуск фиксированного скрипта
}
Контроллер нельзя вызвать с другого компьютера в локальной сети: 127.0.0.1 доступен только самому телевизору. Передать ему произвольную shell-команду тоже нельзя.
Само приложение опрашивает состояние раз в две секунды и показывает один из трех вариантов:
Отключено;
Подключение…;
Подключено.
Кнопка с пульта вызывает локальный запрос:
request.open(
"GET",
"http://127.0.0.1:18081/" + method + "?t=" + Date.now(),
true
);
Чижик: Получилось приложение с человеческим интерфейсом. В самый раз для моего бестолкового хозяина, который в этой мути все равно ничего не понимает!
Влад: Не, ну ты серьезно? Ты думал, что я не прочитаю, прежде чем выкладывать. Оставил специально, пусть люди полюбуются на твое поведение [9], мерзкий Иишный, птыц!
Чижик: извини, хозяин, немного заигрался в бога!
Здесь мы специально разделили две вещи:
локальный контроллер запускается вместе с телевизором;
KVN-соединение не запускается вместе с телевизором.
В загрузочную последовательность добавился только vless-control. Он занимает несколько мегабайт памяти [10] и ждет команды на loopback. sing-box, интерфейс sb0 и дополнительные маршруты появляются лишь после нажатия «Подключить».
Влад:
Мне не нужно автоматически. Я сам хочу включать и отключать.
Чижик:
Принято. Автоматизировано будет ровно то, что избавляет от рутины, а не то, что отнимает управление.
Так телевизор после обычной перезагрузки выходит в сеть как раньше. Если нужен YouTube – открываем наше приложение, подключаемся и лишь затем запускаем YouTube.
На этом месте в хорошем техническом тексте положено написать: «Все заработало с первого раза». Поэтому расскажу, как было на самом деле. Соединение показывало статус «Подключено». Внешний адрес изменился. Я запустил YouTube – и увидел черный экран.
Влад:
Пишет, что подключено. YouTube висит. Почему?
Чижик:
Сейчас выясним, врёт ли наша кнопка, не работает ли DNS или YouTube держится за старое сетевое соединение.
Мы проверили по отдельности основные узлы:
www.youtube.com/generate_204 → 204
www.youtube.com/ → 200
youtubei.googleapis.com/... → 204
i.ytimg.com/... → 204
То есть:
DNS разрешает имена;
TLS-соединения устанавливаются;
основной сайт доступен;
API и сервер изображений отвечают;
трафик действительно идет через новый маршрут.
На подозрении оставались QUIC по UDP/443, IPv6 и уже открытые сетевые сокеты приложения. Можно было немедленно начать блокировать UDP, менять MTU и отключать IPv6 – настоящее веселье с большим количеством побочных эффектов. Но сначала мы выбрали самый дешевый эксперимент: полностью закрыли YouTube и запустили его после установки туннеля.
YouTube открылся.
Судя по результатам проверки, приложение удерживало старое сетевое состояние, созданное до переключения маршрута. Мы не стали выдавать гипотезу за доказанный внутренний механизм YouTube: важнее воспроизводимый пользовательский сценарий.
Root-доступ был нужен для установки бинарника, скриптов, маршрутов и диагностики. Оставлять после этого открытый Telnet было бы очень плохим финалом. Поэтому после проверки Чижик:
удалил временные диагностические файлы;
отключил запуск SSH;
поставил системный флаг запрета Telnet;
завершил работающие telnetd/SSH-процессы;
с компьютера проверил, что порты 22 и 23 закрыты;
оставил открытым только штатный интерфейс управления телевизором.
Конфигурация с секретами осталась доступна только root и имеет права 600. Локальный контроллер слушает только 127.0.0.1. KVN после перезагрузки выключен, пока владелец сам не нажмёт кнопку.
Это не абсолютная защита, но это разумный минимум: временный отладочный вход должен быть закрыт сразу после отладки.
В итоге старый LG получил функцию, которой у него не было из коробки:
отдельное приложение в меню webOS;
ручные кнопки подключения и отключения;
VLESS/TCP/REALITY через sing-box;
системный TUN, которым пользуется не только браузер, но и штатный YouTube;
автоматический откат маршрутов при ошибке [11];
отсутствие зависимости от компьютера после установки;
отсутствие изменений в роутере;
выключенное соединение после обычной перезагрузки;
закрытый root-доступ после завершения работ.
Самое приятное: телевизор не пришлось заменять. Его железо по-прежнему умеет декодировать видео и показывать хорошую картинку. Проблема находилась не в матрице и не в процессоре, а в сетевом пути и отсутствии подходящего штатного клиента.
Один, если рядом есть человек с пультом. И это, пожалуй, главный вывод эксперимента. Codex мог:
исследовать устройство по сети;
читать логи;
собирать ARM-бинарник контроллера;
писать и исправлять shell-скрипты;
упаковывать webOS-приложение;
проверять маршруты и доступность узлов;
помнить о закрытии служебных портов.
Но несколько раз требовался человек:
включить нужную настройку на телевизоре;
подтвердить сопряжение;
нажать кнопку в приложении;
посмотреть, что физически происходит на экране;
сказать сакраментальное: «все, YouTube завелся».
Это не история о том, как искусственный интеллект самовольно поселился в телевизоре. Это история о совместной работе: человек задает цель, принимает решения и контролирует физическое устройство, а Чижик берет на себя терминал, рутину, диагностику и удивительно большое количество кавычек в shell-командах.
Решение уже работает, но список инженерных хотелок остался:
добавить на экран приложения текущую страну и задержку;
хранить несколько обезличенных профилей и переключаться между ними с пульта;
показывать понятную причину ошибки вместо общего «не подключено»;
добавить отдельный тест YouTube до его запуска;
подписывать и проверять обновления контроллера;
сделать безопасную резервную копию конфигурации без секретов;
оформить установщик, который не требует ручного копирования файлов.
А еще у нас остались другие задачи: показывать на телевизоре фотографии из облака, передавать видео с компьютера без кабеля и понять, сколько современной жизни вообще можно вдохнуть в старый webOS.
Похоже, у «Очумелых ручек с Чижиком» будет второй выпуск.
Root-доступ, изменение маршрутов и установка сторонних бинарников могут привести к циклической загрузке, потере настроек или необходимости восстанавливать телевизор. Конкретные способы получения root зависят от модели и версии webOS и со временем меняются.
Перед экспериментом стоит:
зафиксировать точную модель и версию прошивки;
сохранить исходные конфиги и таблицу маршрутов;
иметь способ вернуть устройство в исходное состояние;
не публиковать UUID, приватные ключи и адреса своих серверов;
не оставлять Telnet или SSH доступными после настройки;
не копировать команды вслепую на другую модель.
Все адреса, идентификаторы и ключи в этой статье заменены заглушками. Это рассказ об архитектуре и ходе работы, а не универсальный установщик. Если хотите дайте почитать эту статью своему Чижику и он явно разберется в этом и потратит меньше токенов на доработку уже вашего телевизора.
*Само собой ситуация вымышленная, и происходит на другой планете, не существует никаких этих ваших Влесов, КВН- сервисов, ИИ-чижиков (кроме Алисы, конечно) и т.д. Это все выдумка больного воспаленного работой мозга [12] IT-шника.
Автор: vladislav_lukashenko
Источник [13]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/37881
URLs in this post:
[1] saby.ru: http://saby.ru
[2] Телеграм канале: https://t.me/+S6IevAcGUEg1YzM6
[3] сайте: https://vlukas.ru/
[4] интеллекта: http://www.braintools.ru/article/7605
[5] Логика: http://www.braintools.ru/article/7640
[6] supervisor.sh: http://supervisor.sh
[7] start.sh: http://start.sh
[8] status.sh: http://status.sh
[9] поведение: http://www.braintools.ru/article/9372
[10] памяти: http://www.braintools.ru/article/4140
[11] ошибке: http://www.braintools.ru/article/4192
[12] мозга: http://www.braintools.ru/parts-of-the-brain
[13] Источник: https://habr.com/ru/articles/1102380/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1102380
Нажмите здесь для печати.