- BrainTools - https://www.braintools.ru -

Очумелые ручки с Чижиком, выпуск №1: как мы поселили KVN прямо в старый телевизор LG

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

Очумелые ручки с Чижиком, выпуск №1: как мы поселили KVN прямо в старый телевизор LG - 1

Ах да, действующие лица:

Очумелые ручки с Чижиком, выпуск №1: как мы поселили KVN прямо в старый телевизор LG - 2

Влад Лукашенко

Head of SEO & web-аналитики, Тензор (разработчик saby.ru [1]), автор ТГ‑канал «ВладПРО»

Я более 10 лет занимаюсь аналитикой, SEO и управлением командами в digital‑маркетинге. А в своем Телеграм канале [2] и на сайте [3] пишу еще больше про всякое из реального маркетинга. Консультирую по аналитике web‑проектов и настройке инструментов маркетинга, помогаю проводить технические собеседования специалистов по различным типам трафика.

Очумелые ручки с Чижиком, выпуск №1: как мы поселили KVN прямо в старый телевизор LG - 3

Чижик

ChatGPT Codex

Домашняя разновидность искусственного интеллекта [4]. Живет в терминале, питается логами и токенами. Имя получилось из согласных букв ChatGPT Codex — Ч-Ж-К. Если немного воображения, выходит Чижик. Если воображения совсем много – инженер по всякому куда можно подключиться по сети и чего-нибудь накодить.

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

Возможно, кто-то найдет здесь готовую идею для собственного дома. Кто-то подсмотрит полезный технический прием. А кто-то просто поймет, что ChatGPT Codex можно применять не только для написания очередной функции в рабочем проекте. Иногда ему можно показать старый телевизор, дать доступ к терминалу и спросить: «Чижик, а мы вообще можем с этим что-нибудь сделать?»

Если по ходу чтения у вас появятся идеи, как улучшить описанное решение, – приносите их в комментарии. Туда же можно складывать предложения для следующих экспериментов: что еще попробовать автоматизировать, оживить, связать или убедить работать вопреки документации. Самые интересные варианты мы с Чижиком постараемся проверить на практике – если, конечно, после эксперимента дом все еще будет подключаться к интернету.

Так рождается серия «Очумелые ручки с Чижиком». И начать я решил с телевизора.

Вместо вступления: телевизор еще хороший, а интернет в нем уже не очень

У меня есть телевизор LG на webOS. Не музейный экспонат: показывает хорошо, пульт работает, YouTube установлен, экран менять совершенно не хочется. Но возраст у телевизора уже чувствуется. Браузер стал капризным, современные сайты открывает через раз. Официально приложение YouTube на месте. Кнопка есть. Никто в телевизоре не написал огромными буквами «нельзя». Но видео либо не запускается, либо приложение смотрит на меня черным экраном.

Можно было настроить KVN на роутере. Но мне не хотелось:

  • отправлять через него всю домашнюю сеть;

  • менять рабочую конфигурацию роутера ради одного устройства;

  • объяснять остальным домашним, почему после моего эксперимента чайник видит себя в Нидерландах;

  • покупать новый роутер или отдельную приставку, пока старый телевизор технически исправен.

Хотелось простого пользовательского сценария:

  1. Открыть на телевизоре отдельное приложение.

  2. Нажать «Подключить».

  3. Запустить YouTube.

  4. После просмотра нажать «Отключить».

И я позвал Чижика.

У Чижика есть одна раздражающая, но полезная привычка: перед каждым эффектным техническим решением он пытается выяснить ограничения. Так обнаружились четыре важных обстоятельства.

  • Телевизор работает на webOS 5, а не на Android TV. APK сюда не поставить.

  • Владелец телевизора разрешил root-доступ, но только на время установки и диагностики.

  • Рабочий профиль использует VLESS/TCP/REALITY.

  • Подключение должно включаться только вручную из приложения.

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

Серия первая: телевизор нашёлся, лёгких путей не нашлось

Для начала я включил на LG опцию «LG Connect Apps / Подключение мобильных устройств». После этого телевизор стал доступен для штатного управления по локальной сети.

Чижик нашел устройство, выполнил сопряжение и проверил, что может открыть приложение и отправить на телевизор нажатие кнопки. Это еще не root и не взлом. Это обычный интерфейс управления webOS – тот же класс возможностей, которым пользуются мобильные пульты.

Сначала мы прошли по очевидной лестнице решений.

Попытка №1: OpenKVN

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

Влад:

Он подумал и передумал. Это считается прогрессом?

Чижик:

Безусловно. До этого он даже не думал.

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

Попытка №2: WireGuard

Следом попробовали профиль WireGuard. Он проще и обычно быстрее, но в нашем случае стабильного соединения тоже не получилось. Наличие красивого конфигурационного файла еще не означает, что пакеты доберутся до второй стороны.

Короткое свидание со strongSwan

В списке кандидатов появился IPsec/strongSwan. Теоретически солидно: взрослый протокол, серьезное название, можно произносить с каменным лицом. Практически на старом webOS это означало бы еще один чужеродный демон, отдельную работу с политиками IPsec и больше движущихся деталей, чем требовалось для одного приложения.

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

Подсказка пришла с компьютера

На компьютере рабочее соединение через VLESS/TCP/REALITY работало стабильно. Значит, задача стала конкретнее: не «найти любой KVN для webOS», а перенести на телевизор именно тот транспорт, который уже проходит через сеть. Для этого подошёл sing-box: один исполняемый файл, поддержка нужного протокола, TUN-интерфейс и возможность работать без тяжелой графической оболочки.

Что в итоге построил Чижик

Влад: Давай, Чижик, вещай, тебе слово!

Чижик: Огромное, тебе, человеческое спасибо, хозяин, рассказываю:

Получилась не одна программа, а маленький слоеный пирог:

Очумелые ручки с Чижиком, выпуск №1: как мы поселили KVN прямо в старый телевизор LG - 4

Почему не дать web-приложению сразу выполнять команды root? Потому что приложение с кнопками не должно быть универсальным пультом от всей операционной системы. Между интерфейсом и root-командами появился крошечный контроллер с тремя жестко заданными действиями. Никакого /exec?command=..., никакого терминала через HTTP.

Теперь разберем слои по порядку.

Шаг 1. Подбираем бинарник под телевизор

Внутри телевизора обнаружился 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 оно вело себя нестабильно. Поэтому я отключил магию и перешел к ручному труду – то есть написал еще один скрипт.

Шаг 2. Маршрутизация

После запуска sing-box создавался интерфейс sb0. Но существование интерфейса еще не означает, что телевизор начнет им пользоваться.

Нужно было:

  1. Запомнить исходный шлюз и сетевой интерфейс.

  2. Оставить отдельный прямой маршрут до KVN-сервера.

  3. Поднять sb0.

  4. Направить через него остальной 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 завершается, а телевизор снова использует обычный маршрут через роутер.

Шаг 3. Почему одного start.sh оказалось мало

Первый вариант был почти прекрасен: запускаем процесс, ждем интерфейс, добавляем маршруты. На тесте работает. После перезагрузки – уже не совсем.

Пожилой 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-запрос проходит через новый внешний маршрут.

Это важный урок всей затеи: надпись «процесс запущен» и работающая сеть – не одно и то же.

Шаг 4. Делаем кнопку, которой можно доверять

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], мерзкий Иишный, птыц!

Чижик: извини, хозяин, немного заигрался в бога!

Шаг 5. Автозапуск

Здесь мы специально разделили две вещи:

  • локальный контроллер запускается вместе с телевизором;

  • 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: важнее воспроизводимый пользовательский сценарий.

Шаг 6. Убираем за собой

Root-доступ был нужен для установки бинарника, скриптов, маршрутов и диагностики. Оставлять после этого открытый Telnet было бы очень плохим финалом. Поэтому после проверки Чижик:

  1. удалил временные диагностические файлы;

  2. отключил запуск SSH;

  3. поставил системный флаг запрета Telnet;

  4. завершил работающие telnetd/SSH-процессы;

  5. с компьютера проверил, что порты 22 и 23 закрыты;

  6. оставил открытым только штатный интерфейс управления телевизором.

Конфигурация с секретами осталась доступна только 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

www.BrainTools.ru

Rambler's Top100