- PVSM.RU - https://www.pvsm.ru -
Привет! Решил представить тут небольшое и дешёвое устройство, которое на данный момент умеет:
1. Пинговать заданный IP
2. Смотреть пакеты с помощью tcpdump
3. Сканировать сеть через ARP
А главное, всё это работает полностью автономно на Raspberry PI 2 без GUI и потребляет всего 50 Мб ОЗУ!
В статье будет: описание самого устройства и идеи; описание различных приколов и багов в процессе разработки; инструкция как сделать такое самому; и вопрос знатокам, нужно ли это вообще кому-нибудь :)
В процессе разработки коммутатора на работе я столкнулся с тем, что было бы прикольно иметь небольшое настольное устройство для, например, генерации пакетов с заданными QoS метками; пакетов с таким-то VLAN'ом, или просто для просмотра "идут пакеты или нет".
Постепенно в голове начали формироваться следующие требования к устройству:
1. Дешевизна (забегая вперед, это устройство получилось в районе 20$)
2. Наличие собственного экрана (3.5 дюйма SPI экран с резистивным тач-скрином)
3. Наличие линукса на борту
4. И один или несколько портов Ethernet.
Я долго искал одноплатники с двумя портами Ethernet, но находил только дорогие, заточенные под создание собственного маршрутизатора. В итоге остановился на Raspberry pi 2B, потому что во-первых, она была в наличии, а во-вторых, не возникнет проблем с подключением экрана (думал он). Плюс, при желании добавить один порт можно просто купить дешевый переходник USB - Ethernet, открывая кучу возможностей.
Итак, что имеем сейчас в получившемся устройстве (подчеркиваю, это только proof-of-concept):
Можно пингануть другое устройство в сети.
Можно посмотреть пакеты, приходящие на интерфейс.
Можно узнать какие девайсы есть в сети. При этом устройство посылает arp-запросы на маску /24 (да, она захардкожена. PoC же), и слушает ответы, генерируя список соответствия IP-адреса MAC-адресу.
И можно посмотреть информацию о своём интерфейсе (на данный момент это просто вывод "ip address show dev eth0".
А теперь, к вопросу как это все сделать без GUI.
Их всего два. Raspberry pi 2b можно взять на авито примерно за 10 долларов; экранчик брал как в спойлере, с учетом доставки и прочего получаются те же 10$.
В качестве ОС я выбрал Raspbian lite (32х битную), без десктопного окружения, потому что зачем, когда у нас есть терминал :) Да и вторая малинка с трудом тянет полноценную графическую систему.
Итак, экран начал подключать по инструкции здесь [1]. Там всё просто, клонируем репу, запускаем ./LCD35-show, наслаждаемся. Но не тут-то было, т.к. далее стоял вопрос как откалибровать его. Не помню как именно, но тернистыми путями вышел на библиотеку [2], в которой было всё что нужно для калибровки.
Существует шикарная библиотека для быстрого написания интерфейсов на плюсах Dear ImGui. Однако существует менее известная библиотека ImTui [3], которая позволяет использовать ImGui для написания приложений в терминале с использованием ncurses.
Склонировав репу ImTui и попробовав запустить, я столкнулся со следующим: не регистрирует нажатия. Потыкавшись с линуксовыми инпутами, я решил проблему просто: линкуем себе в приложение libts, лезем в исходник imtui и добавляем обработку:
// imtui-impl-ncurses.cpp
#include "tslib.h"
...
static struct tsdev* ts;
...
ImTui::TScreen * ImTui_ImplNcurses_Init() {
...
ts = ts_setup(nullptr, 1);
}
bool ImTui_ImplNcurses_NewFrame() {
struct ts_sample samp;
int ret = ts_read(ts, &samp, 1);
if (samp.pressure > 0) { // Если давление на экран больше ноля
// и если данные от экрана "более-менее" норм
if (samp.x > 0 && samp.x < 1000 && samp.y > 0 && samp.y < 1000) {
// масштабируем и выдаем координаты нажатия
mx = (double)samp.x * 30 / 240;
my = (double)samp.y * 20 / 160;
lbut = 1;
hasInput = true;
} else {
lbut = 0;
}
} else {
lbut = 0;
}
...
}
Весь код лежит на гитхабе [6].
Был также момент с масштабированием. По умолчанию текст получался очень мелкий, было сложно что-то разглядеть. Однако драйвер к экрану не поддерживает масштабирование. Поэтому я просто задал разрешение экрана в 1.5 раза меньше, и текст увеличился. Это неидеальное решение, он получился немного размытым, надо бы больше поковырять этот момент.
Для пинга и просмотра пакетов используются команды ping и tcpdump, вывод которых перенаправляется в pipe и отображается. При этом у tcpdump есть флаг -U, который, согласно ману, означает "вывод будет записан в stdout когда закончится очередной пакет". Но это не работало! Пакеты выводились пачкой раз в секунд 10. Зато опция -l "вывод записывается в stdout по окончанию очередной строки" работала! Хотя даже в man tcpdump говорится что опции идентичны.
Залез в исходники [7]. Флаг -l вызывает setvbuf(stdout, NULL, _IOLBF, 0) где _IOLBF и означает строковую буферизацию. Флаг -U вызывает в конце каждого пакета функцию pcap_dump_flush, которая является частью API libpcap. Лезем в код libpcap [8]. Находим:
int
pcap_dump_flush(pcap_dumper_t *p)
{
if (fflush((FILE *)p) == EOF)
return (-1);
else
return (0);
}
Fflush чистит все user-space буферы, но не чистит kernel-space. При этом размер pipe обычно 4 кибибайта, а средний пакет в выводе tcpdump ~ 100 байт. Вот и получалось что он печатал пачками по ~40 пакетов. Причина найдена, поэтому идем дальше.
Был прикол с тем, что если в .bashrc прописать что-то типа
if [[ $(tty) == /dev/tty1 ]]; then
/root/TcpDumper/build/bin/TcpDumper
fi
То при открытии приложения будет чёрный экран. Я не знаю сколько бы я с этим бодался, но подсказала ChatGPT: для ncurses приложения необходима переменная среды TERM! Добавив в код выше export TERM=xterm-256color, все заработало.
С файлом .profile был ещё один мем. Когда я первый раз добавил запуск приложения сразу после запуска ОС, я по-глупости написал это вот так:
# файл /root/.profile
...
exec /root/TcpDumper/build/bin/TcpDumper
И сохранил. Решил проверить. Перезахожу по ssh. Меня встречает приложение, работает, всё хорошо. Жму Ctrl+C чтобы его закрыть и... сессия ssh закрывается. О нет. Ведь exec замещает процесс баша приложением в его аргументе, и назад в баш вернуться не было возможности. От пользователя pi пароль я забыл, команда вида ssh root@192.168.0.114 'echo privet > /root/.profile' завершается ошибкой...
Начал думать что делать. Точно, нужно просто достать sd-карточку и поменять на ней этот файл! Но есть проблема. Файловая система у малинок отформатирована в ext4, а винда такой формат не поддерживает. Другого устройства на линуксе дома нет.
Нашел под винду программу просмотра файлов с карточек ext2fsd, но она умеет их только читать, а не писать. Но у меня же есть WSL, подумал я, нашёл программу для проброса usb флешек в WSL -- usb-ipd [9]. Но она тоже отказалась монтировать флешку. Погуглив, нашел информацию [10]что нужно пересобрать ядро WSL с поддержкой нужных дров, но решил остановиться и... поспать. На завтра занёс её на работу, где проблема решилась за 10 секунд :) Можно ещё было залить на флешку образ линукса и загрузиться в live cd на ноуте, но тогда я почему-то отверг этот вариант (может просто флешки не было еще одной).
Ещё был баг, если зайти на малинку через ssh, и открыть сразу две копии приложения через openvt, то все начинает глючить. Не знаю зачем вам эта информация :)
Если вы не собираетесь повторять девайс, этот раздел можно пропустить, тут не будет ничего интересного.
Перейдите на https://www.raspberrypi.com/software [11], скачайте raspberry pi imager под вашу ОС
В Imager: выберите вашу модель Raspberry, ОС - Raspberry pi OS lite, в настройках включите удаленный доступ (ssh).
Установите выбранную ОС на sd-карточку.
Установите необходимые пакеты: apt install libts-dev cmake
Склонируйте репозиторий с драйвером дисплея: git clone https://github.com/goodtft/LCD-show.git
cd LCD-show; ./LCD35-show
Поменяйте (уменьшите) разрешение дисплея. Для этого в файле /boot/config.txt добавьте (если их нет) в конец следующие строки: framebuffer_width=240
framebuffer_height=160
reboot
Далее, необходимо выставить следующие переменные среды для работы libts: export TSLIB_FBDEVICE=/dev/fb0;
export TSLIB_TSDEVICE=/dev/input/event0
Откалибруйте дисплей: ts_calibrate
Склонируйте репозиторий:cd ~;
git clone https://github.com/Dima-Makarov/TcpDumper.git --recurse-submodules
Можно собирать и запускать:cd TcpDumper;
mkdir build;
cmake -S . -B build;
cmake --build build;
build/bin/TcpDumper
Для того, чтобы оно автоматически запускалось при старте малинки, добавьте следующие строки в ~/.profile:
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event0
if [[ $(tty) == /dev/tty1 ]]; then
export TERM=xterm-256color
openvt -f -c 1 /root/TcpDumper/build/bin/TcpDumper
fi
Также нужно сделать так, чтобы экран запускался с пользователем root. Для этого:nano /etc/systemd/system/getty@tty1.service.d/autologin.conf
В строке после слова autologin измените слово pi
на root
Выйдите из редактора:reboot
Готово!
Если появятся какие-то проблемы - смело пишите в лс, обещаю оперативно помочь.
Не зря я упомянул про адаптер USB-Ethernet в начале, ведь с ним можно сделать следующее: втыкаем его в usb, соединяем два сетевых интерфейса в bridge, и вуаля, получаем сниффер, который можем включить в разрыв между двумя устройствами и смотреть через tcpdump что они там шлют друг другу.
На поздних "малинках" есть wi-fi, и с ним можно сделать много чего интересного, и всё из того же TUI интерфейса. Как минимум - переходник "медь-воздух", wi-fi сканер, you name it.
Можно реализовать сценарии разных атак на сеть - arp spoof, mac spoof, проверить включен ли port-security на коммутаторе, попытавшись загадить ему mac-таблицу :), и прочее и прочее.
Также, через wi-fi можно реализовать управление этим устройством со смартфона, и там уже воротить все что вздумается.
Мои вопросы: заинтересован ли кто-нибудь в подобном устройстве? Какие бы фичи вам были бы полезны? Удобный ли форм-фактор, на ваш взгляд? Добро пожаловать в комменты!
Стоп он реально не оставил ссылки на свой тг канал???
Автор: Duke_nukeum
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/raspberry-pi/410209
Ссылки в тексте:
[1] здесь: https://github.com/goodtft/LCD-show
[2] библиотеку: https://github.com/libts/tslib
[3] ImTui: https://github.com/ggerganov/imtui
[4] llama.cpp: https://github.com/ggerganov/llama.cpp
[5] Whisper: https://github.com/ggerganov/whisper.cpp
[6] гитхабе: https://github.com/Dima-Makarov/TcpDumper
[7] исходники: https://github.com/the-tcpdump-group/tcpdump
[8] код libpcap: https://github.com/the-tcpdump-group/libpcap
[9] usb-ipd: https://github.com/dorssel/usbipd-win
[10] информацию : https://github.com/dorssel/usbipd-win/wiki/WSL-support#building-your-own-usbip-enabled-wsl-2-kernel
[11] https://www.raspberrypi.com/software: https://www.raspberrypi.com/software/
[12] Источник: https://habr.com/ru/articles/879182/?utm_campaign=879182&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.