Шукати в цьому блозі

субота, 29 серпня 2026 р.

Автомонтування Google Drive через rclone на Debian + GNOME: історія для однієї філіжанки кави

Захотілося простого: підключити Google Drive як звичайну папку в файловій системі, і щоб воно саме піднімалось при вході в систему, без танців з бубном щоразу. Здавалося б, rclone mount — і готово. Виявилось трохи цікавіше.

Крок 1. rclone і конфіг, якого нема

Перша спроба:

rclone mount gdrive: ~/GDrive --daemon

У відповідь:

Failed to create file system for "gdrive:": didn't find section in config file

Логічно — remote gdrive в конфізі просто не існував. Створити порожній файл командою rclone config touch теж не рятує: файл є, секції нема.

Рішення: інтерактивний майстер rclone config. Він сам генерує правильну секцію в ~/.config/rclone/rclone.conf і проводить через OAuth-авторизацію в браузері — 2FA при цьому обробляється звичайним способом, через сам Google, rclone до неї жодного стосунку не має. На машині з GUI (а в мене GNOME) достатньо погодитись на Use auto config? (y) — rclone підійме локальний вебсервер і сам відкриє браузер для логіну.

Крок 2. Автозапуск при логіні — перша перешкода: D-Bus

Щоб не монтувати вручну щоразу, оформив systemd user-юніт:

[Unit]
Description=RClone mount Google Drive
AssertPathIsDirectory=%h/GDrive
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/rclone mount gdrive: %h/GDrive \
    --vfs-cache-mode writes \
    --config=%h/.config/rclone/rclone.conf
ExecStop=/bin/fusermount -u %h/GDrive
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target

І одразу вперся в:

Failed to connect to user scope bus via local transport: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined

Спробував виставити loginctl enable-linger, спробував вручну експортувати змінні — не допомагало. Причина виявилась банальною і трохи соромною: у .bashrc завалявся старий

alias systemctl='sudo systemctl'

А sudo за замовчуванням очищує середовище процесу. Тобто щойно виставлені XDG_RUNTIME_DIR і DBUS_SESSION_BUS_ADDRESS до команди просто не доходили — sudo їх зрізав ще до старту systemctl. Найприкріше, що для керування власними user-юнітами (systemctl --user) права root взагалі не потрібні.

Рішення: викликати бінарник напряму, оминаючи alias:

/usr/bin/systemctl --user daemon-reload
/usr/bin/systemctl --user enable --now rclone-gdrive.service

І заразом не завадить loginctl enable-linger <user> — щоб user-сесія (і user-юніти) піднімались навіть без активного графічного логіну.

Крок 3. Сервіс стартує і одразу падає

Failed to create file system for "gdrive:": didn't find section in config file

Та сама помилка, що й на самому початку — але тепер конфіг точно існував. Загадка розкрилась при прямому запуску команди в терміналі (без --daemon, щоб бачити живий вивід):

/usr/bin/rclone mount gdrive: ~/GDrive --vfs-cache-mode writes --config=/home/olden/.config/rclone/rclone.conf

Та сама помилка. Але варто було спробувати з великої літери:

/usr/bin/rclone mount GDrive: ~/GDrive --vfs-cache-mode writes --config=/home/olden/.config/rclone/rclone.conf

— і диск підключився. rclone чутливий до регістру назви remote, а в конфізі секція виявилась записана як [GDrive], а не [gdrive], як я вважав. Дрібниця, яка коштувала половини вечора.

Виправив у юніті:

sed -i 's/rclone mount gdrive:/rclone mount GDrive:/' ~/.config/systemd/user/rclone-gdrive.service

Крок 4. Порожня папка після, здавалося б, вдалого монтування

Сервіс піднявся, systemctl --user status показував active (running), а ls ~/GDrive — порожньо. При тому ручний запуск хвилиною раніше показував повний список файлів.

Причина — накладені (stale) точки монтування. Я тестував ручний запуск rclone mount просто в терміналі, потім намагався його відмонтувати через fusermount3 -u, але процес до кінця не прибрався. Коли systemd підняв новий rclone mount поверх недомонтованого старого шару, ядро показувало нову, ще порожню точку.

Розібратись допомогла така послідовність:

/usr/bin/systemctl --user stop rclone-gdrive.service
fusermount3 -u ~/GDrive          # повторити кілька разів, якщо треба
pkill -f "rclone mount"          # добити зомбі-процеси
ps aux | grep rclone             # переконатись, що чисто
/usr/bin/systemctl --user start rclone-gdrive.service

Після цього ls ~/GDrive нарешті показав реальні файли.

Підсумок: робочий юніт

[Unit]
Description=RClone mount Google Drive
AssertPathIsDirectory=%h/GDrive
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/rclone mount GDrive: %h/GDrive \
    --vfs-cache-mode writes \
    --config=%h/.config/rclone/rclone.conf
ExecStop=/bin/fusermount -u %h/GDrive
Restart=on-failure
RestartSec=10

[Install]
WantedBy=default.target
loginctl enable-linger $USER
/usr/bin/systemctl --user daemon-reload
/usr/bin/systemctl --user enable --now rclone-gdrive.service

(Type=notify теж мав шанс спрацювати — версія rclone тут доволі свіжа, — але коли шукаєш причину падіння, простіше тимчасово спростити до Type=simple, щоб виключити зайву змінну з рівняння.)

Висновки на майбутнє

  • Alias на sudo systemctl і systemctl --user — погана комбінація. Sudo зрізає середовище, а --user-юнітам права root взагалі не потрібні.
  • rclone чутливий до регістру назв remote. gdrive: і GDrive: — це два різні (точніше, один існуючий і один неіснуючий) remote.
  • Перед діагностикою systemd-юніта корисно спершу прогнати ту саму команду вручну в терміналі — так помилка видно одразу, без прошарку journalctl.
  • Stale FUSE-монтування — підступна штука: systemctl status може казати active (running), а точка монтування при цьому виявиться порожньою, бо накладена на недомонтований попередній шар. pkill -f + чистий stop/start знімає це надійно.

Дрібниця на дрібниці, але кожна — окрема пастка, у яку легко провалитись саме тому, що симптом (одна й та сама помилка «not found in config file») мав дві геть різні причини на різних етапах.

середа, 13 травня 2026 р.

Дублювання репозиторію на GitHub

Якось часто останнім часом доводиться робити дублювання власних репозиторіїв на GitHub. Залишу за дужками питання "чому?", але додам до нотатків "як?".

Створюємо новий репозиторій.

На GitHub -> "New repository". Даємо йому назву. "Create repository" (не ініціалізуємо його файлами).

Клонуємо старий репозиторій як дзеркало

git clone --mirror https://github.com/посилання/на_старий_репозиторій.git

Переходимо в директорію

cd назва_старого_репозиторію.git

Відправляємо дані в новий репозиторій

git push --mirror git@github.com:посилання/на_новий_репозиторій.git

Видаляємо директорію

cd ..
rm назва_старого_репозиторію.git

вівторок, 26 серпня 2025 р.

CloudFlare Client на MikroTIK (RouterOS)

Перше, що нам знадобиться це wgcf — is an unofficial, cross-platform CLI for Cloudflare Warp. Якщо ліниво збирати вручну то можна взяти готовий реліз під свою платформу. У мене wgcf_2.2.29_linux_amd64:

$ wget -O wgcf https://github.com/ViRb3/wgcf/releases/download/v2.2.29/wgcf_2.2.29_linux_amd64
$ chmod +x wgcf

Створимо конфігурацію для CloudFlare:

$ ./wgcf register --accept-tos --name HomeVPN

При цьому буде створено файл wgcf-account.toml, який містиме первинну конфігурацію.

В тому випадку якщо вже маємо ліцензію з оплаченим акаунтом (проте це не обов'язкова умова) можна оновити конфігурацію використовуючи наявний ключ.

./wgcf update --license-key QB………………-……………………-……………30H

Проте майте на увазі, що до одного акаунта може бути прив'язано не більше п'яти пристроїв. Якщо їх більше — виконання wgcf завершиться з помилкою.

Все, що нам залишилося це згенерувати текстовий файл конфігурації, щоб використовувати в подальшому наведені в ньому значення:

$ ./wgcf generate
2025/08/26 07:58:59 Using config file: wgcf-account.toml
2025/08/26 07:59:00 Successfully generated WireGuard profile: wgcf-profile.conf

Тепер ми маємо wgcf-profile.conf:

$ cat wgcf-profile.conf
[Interface]
PrivateKey = AGX……………………………………………………………………………………………………1g=
Address = 172.…….….…/32, 2606:…………:………:…………:…………:…………:…………:…………/128
DNS = 1.1.1.1, 1.0.0.1, 2606:4700:4700::1111, 2606:4700:4700::1001
MTU = 1280
[Peer]
PublicKey = bmX…………………………………………………………………………………………………gyo=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = engage.cloudflareclient.com:2408

В першу чергу нас цікавитиме параметр PrivateKey.

Можемо приступити до налаштування MikroTIK. Створюємо інтерфейс клієнта:

/interface wireguard add listen-port=13231 mtu=1290 name=cloudflare-warp private-key="AGX……………………………………………………………………………………………………1g="

Налаштовуємо peer-параметри, всі значення беремо з wgcf-profile.conf:

/interface wireguard peers add allowed-address=0.0.0.0/0,::/0 endpoint-address=engage.cloudflareclient.com endpoint-port=2408 interface=cloudflare-warp name=cloudflare-peer public-key="bmX…………………………………………………………………………………………………gyo="
Ну і далі доволі стандартні кроки:
/interface list add comment=Internet name=INTERNET
/interface list member add interface=cloudflare-warp list=INTERNET
/ip firewall nat add action=masquerade chain=srcnat out-interface=cloudflare-warp
/routing table add disabled=no fib name=to-cloudflare
/ip address add address=172.…….….…/30 interface=cloudflare-warp
/ipv6 address add address=2606:…………:………:…………:…………:…………:…………:…………/128 advertise=no interface=cloudflare-warp
/ip route add dst-address=0.0.0.0/0 gateway=172.…….….1 routing-table=to-cloudflare
/ip firewall address-list add address=192.168.88.254 comment=og-home list=TO-CF-SRC
/ip firewall mangle add action=mark-connection chain=prerouting connection-mark=no-mark dst-address-list=TO-CF-SRC in-interface-list=LAN new-connection-mark=CF-conn
/ip firewall mangle add action=mark-connection chain=prerouting connection-mark=no-mark in-interface-list=LAN new-connection-mark=CF-conn src-address-list=TO-CF-SRC
/ip firewall mangle add action=mark-routing chain=prerouting connection-mark=CF-conn in-interface-list=LAN new-routing-mark=to-cloudflare
Ну от начебто і все. Всі інші налаштування — на власний самак ;)

вівторок, 18 лютого 2025 р.

Обмеження швидкості на етапі видачі ip-адреси DHCP-сервером в MikroTIK

Час від часу було необхідно обмежити швидкість тим чи іншим клієнтам локальної мережі, які отримують адресу по DHCP.

Що робили?

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

/queue simple add burst-limit=200M/200M burst-threshold=2M/2M burst-time=5s/5s max-limit=198M/198M name=lan queue=pcq-upload-src/pcq-download-dst target=bridge-local total-queue=pcq-dst-src

По-друге, фіксували за mac-адресою ту чи іншу ip-адресу. По-третє, створювали чергу, яку через parent підв'язували до створеної черги локальної мережі і обмежували швидкість для саме цієї ip-адреси.

Така схема робоча, але не дуже зручна, коли треба обмежити швидкість, скажемо так, масово.

Припустимо купуємо у провайдера 100 мегабіт. У нас 10 робочих місць. Задача - кожному роздати по 10 мегабіт.

Звісно можна зафіксувати адреси, а можна…

Варіант 1. Старе рішення.

Перший варіант, який приходить на думку: обійти таблицю leases і під кожну виділену ip-адресу створити відповідне правило в черзі. Це вирішується якось так (позичено і перероблено з форуму MikroTIK):

/ip dhcp-server lease
:foreach x in=[find] do={
 
    # grab variables for use below
    :local leaseaddr ([get $x address])
    :local leasemacaddr [get $x mac-address]
    :local leasehostname [get $x host-name]
    :local leasename [get $x comment]
    :local queuecomment

    :local minlimit 192.168.100.20
    :local maxlimit 192.168.100.100
 
    :local leaseinqueue false
 
    /queue simple
    :foreach y in=[find] do={
 
        #grab variables for use below
        :local queuetargetaddr [get $y target]
        :set queuecomment [get $y comment]
 
        # Isolate information  from the comment field (MAC, Hostname)
        :local queuemac [:pick $queuecomment 4 21]
        :local queuehostname [:pick $queuecomment 22 [:len $queuecomment]]
 
        # If MAC from lease matches the queue MAC then refresh the queue item
        :if ($queuemac = $leasemacaddr) do={
            # build a comment field
            :set queuecomment ("dtq," . $leasemacaddr . "," . $leasehostname)

            set $y target=$leaseaddr comment=$queuecomment
            :if ($leasename != "") do= {
                set $y name=($leasename . " (" . $leasemacaddr . ")")
            } else= {
                :if ($leasehostname != "") do= {
                    set $y name=($leasehostname . " (" . $leasemacaddr . ")")
                } else= {
                    set $y name=$leasemacaddr
                }
            }
            :set leaseinqueue true
        } else= {
            # if ip exists for this lease but mac is different then update mac/hostname and reset counter
            :if ($queuetargetaddr = $leaseaddr) do={
                # build a comment field
                :set queuecomment ("dtq," . $leasemacaddr . "," . $leasehostname)
 
                set $y comment=$queuecomment
                reset-counters $y
                :if ($leasename != "") do= {
                    set $y name=($leasename . " (" . $leasemacaddr . ")")
                } else= {
                    :if ($leasehostname != "") do= {
                        set $y name=($leasehostname . " (" . $leasemacaddr . ")")
                    } else= {
                        set $y name=$leasemacaddr
                    }
                }
                :set leaseinqueue true
            }
        }
    }
 
    # There was not an existing entry so add one for this lease
    :if ($leaseinqueue = false) do={
        # build a comment field
        :set queuecomment ("dtq," . $leasemacaddr . "," . $leasehostname)
        # build command
        :local cmd "/queue simple add parent=lan target=$leaseaddr max-limit=100M/100M comment=$queuecomment"
        :if ($leasename != "") do={ 
            :set cmd "$cmd name=\"$leasename ($leasemacaddr)\"" 
        } else= {
            :if ($leasehostname != "") do={
                :set cmd "$cmd name=\"$leasehostname ($leasemacaddr)\""
            } else= {
                :set cmd "$cmd name=\"$leasemacaddr\""
            }
        }
 
        # If within the range is executed
        :if ($leaseaddr >= $minlimit && $leaseaddr <= $maxlimit) do={
            :execute $cmd
        }
    }
}
 
# Cleanup Routine - remove dynamic entries that no longer exist in the lease table
/queue simple
:foreach z in=[find] do={
    :local queuecomment [get $z comment]
    :local queue1stpart [:pick $queuecomment 0 3]
    :local queue2ndpart [:pick $queuecomment 4 21]
    :if ( $queue1stpart = "dtq") do={
        :if ( [/ip dhcp-server lease find mac-address=$queue2ndpart] = "") do={
            :log info ("DTQ: Removing stale entry for MAC Address - " . $queue2ndpart)
            remove $z
        }
    }
}

Це дійсно працює. Цей скрипт можна додати в Scheduler і насолоджуватися його роботою. Звісно за необхідності варто змінити на свій смак встановлення локальної змінної cmd.

Цей метод працює на будь-яких версіях RouterOS (правда на дуже старих не перевіряв, але має працювати, бо тут нічого складного і специфічного немає.

Явним недоліком є саме необхідність використання Scheduler, щоб підтримувати черги в актуальному стані.

Про те є інший, більш елегантний метод. Більш легкий метод.

Варіант 2. Lease Script.

В WinBox (або в WebFig, кому як подобається) переходимо в IP → DHCP Server. Відкриваємо налаштування свого DHCP. Переходимо у вкладку Script. Тут у нас велике поле для Lease Script, який буде виглядати приблизно так:

:local queueName "lan-$leaseActIP-$leaseActMAC";
:if ($leaseBound = "1") do={
    :log info "DHCP Lease START: $queueName"
    :local hostName [/ip dhcp-server lease get [find where active-mac-address=$leaseActMAC && active-address=$leaseActIP] host-name]
    /queue simple add burst-limit=50M/50M burst-threshold=1M/1M burst-time=5s/5s max-limit=49M/49M total-burst-limit=50M total-burst-threshold=1M total-burst-time=5s total-limit-at=48M total-max-limit=49M total-queue=pcq-dst-src name=$queueName parent=lan target=($leaseActIP . "/32") comment="$leaseActIP [ $leaseActMAC ] $hostName";
} else={
    :log info "DHCP Lease STOP: $queueName"
    /queue simple remove $queueName
}

І все. Скрипт викликається DHCP-сервером коли він «видає» або «забирає» ip-адресу. Відповідним чином встановлюється змінн $leaseBound, коли сервер видає адресу вона дорівнює "1".

Звісно, що тут можна додати й інші умови, інші виключення, тощо. Можна зробити й іншу структуру самих черг. Але, сподіваюся, що все й без того прозоро й зрозуміло. Користуймося.

пʼятниця, 20 вересня 2024 р.

Як зробити так щоб Linux віддавав перевагу IPv4 адресації, а не IPv6?

Багато провайдерів в Україні ще не надають користувачам IPv6. В принципі, в повсякденні, користувачі цього не помічають. Але є випадки коли все-ж-таки треба отримувати доступ до тих чи інших IPv6 ресурсів. В таких випадках доводиться користуватися Hurricane Electric’s IPv6 tunnel.

З помічених недоліків такого підходу можу визначити два. По-перше, це не дуже швидко. Але це не скарга, бо врешті-решт це безкоштовне рішення. І за це рішення можна лише подякувати. А по-друге, хоч все й чудово працює, але подекуди виникають певні труднощі, коли ресурси на кшталт Google починають активно перевіряти тебе "Підтвердьте, що ви не робот".

Підозрюю, що це виникає саме тому, що за замовчуванням Linux, як в принципі і більшість операційних систем, віддає перевагу саме IPv6. Але чи можна змінити таку поведінку і, в тому випадку коли ресурс має IPv4 та IPv6 адресацію, віддавати перевагу IPv4?

Поведінка за замовчуванням: getaddrinfo та RFC 3484

Виклик getaddrinfo(3) може повернути декілька відповідей. Відповідно до RFC 3484 ці відповіді мають бути відсортовані таким чином, щоб відповідь із найвищим показником успіху була першою у списку. RFC надає алгоритм для сортування.

Цей алгоритм сортування за замовчуванням і набір правил, що стоять за ним, призводять до того, що IPv6 завжди має перевагу перед IPv4:

…
EXAMPLES
       The default table according to RFC 3484 would be specified with the following configuration file:

           label  ::1/128       0
           label  ::/0          1
           label  2002::/16     2
           label ::/96          3
           label ::ffff:0:0/96  4
           precedence  ::1/128       50
           precedence  ::/0          40
           precedence  2002::/16     30
           precedence ::/96          20
           precedence ::ffff:0:0/96  10
…

Це визначає підмережі IPv6 та їхній пріоритет. IPv4 фактично є вбудованою підмножиною IPv6, і ::ffff:0:0/96 вказує 32-розрядну мережу, яка і є IPv4 (подивіться на шпаргалку RIPE щодо префіксів адрес IPv6, щоб дізнатися більше). Це означає, що, наприклад, адреса IPv6 ::ffff:192.168.0.2 і адреса IPv4 192.168.0.2 ідентичні.

Усвідомлюючи це, тепер ми розуміємо, чому перевага буде надаватися адресам IPv6, і бачимо, як можемо легко підвищити пріоритет для IPv4. Просто перетворимо пріоритет 10 на щось на зразок 100, що є вищим за будь-що інше.

Застосування конфігурації

Щоб застосувати конфігурацію, просто відредагуємо або створимо файл /etc/gai.conf і встановимо стандартну конфігурацію зі зміненим пріоритетом для IPv4:

label  ::1/128       0
label  ::/0          1
label  2002::/16     2
label ::/96          3
label ::ffff:0:0/96  4
precedence  ::1/128       50
precedence  ::/0          40
precedence  2002::/16     30
precedence ::/96          20
precedence ::ffff:0:0/96  100

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

Переконаємося, що все працює

Простий спосіб перевірки – просто побачити, який тип IP-адреси використовується під час запиту того чи іншого веб-сайту. В цьому прикладі надсилаємо запит до my.ip.fi через IPv4, потім через IPv6, а потім використовуючи типове значення:

$ SITE=my.ip.fi; curl -4 ${SITE} && curl -6 ${SITE} && curl ${SITE}
176.104.xxx.xxx
2001:470:64xx:xxxx:xxxx:xxxx:98b7:29cc
176.104.xxx.xxx

За замовчуванням тепер IPv4 🎉

четвер, 4 липня 2024 р.

Налаштування WireGuard-сервера на Mikrotik

Раніше я був поверхнево написав про Встановлення з'єднання wireguard між Mikrotik та Linux (Debian), але є нюанс… тоді була задача поєднати швиденько Linux-хост з Mikrotik-ом, але досконало вивчати нюанси було ліньки 😢

Але от нещодавно відбулася подія яка примусила більш докладно підійти до процесу: злетів офісний vpn-сервер на базі Debian і було прийнято рішення перенести конфігурацію на RB3011. Окрім того, що було піднято сервіси L2TP/IPSec та інші, також захотілося більш докладно підійти до WireGuard…

Що сказати, незважаючи на те, що MikroTIK молодці і доволі докладно підходять до написання документації, але не все, що хочеться там є. Доводиться притягати весь попередній досвід щоб розібратися що до чого і як. Звісно, можливо, десь є більш докладне документування (я переконаний, що є), але ж то було б не настільки цікавим процесом.

Що хотілося? Хотілося створити багато клієнтів, які б підключалися по wireguard і отримували через організований тунель доступ до ресурсів та до Інтернет.

Спочатку думалося, що можна створити один wireguard інтерфейс і до нього купу малу peer-ів, але… але щось в мене пішло не так. Нормально в такій схемі захотів працювати тільки перший peer, всі хто підключалися після нього чомусь пасли задніх, хоча трафік від них в wireguard-інтерфейсі через torch я бачив. Пляски з бубном не допомогали… можливо бубен був не тієї конструкції, можливо щось інше, але прийшов врешті-решт до схеми яка не те що запрацювала, а запрацювала майже ідеально.

Далі по кроках.

По-перше, під кожного клієнта створюємо окремий wireguard-інтерфейс. При цьому слухати будемо різні порти.

/interface wireguard
add listen-port=12001 mtu=1420 name=wireguard1
add listen-port=12005 mtu=1420 name=wireguard5
add listen-port=12009 mtu=1420 name=wireguard9
add listen-port=13231 mtu=1420 name=wireguard13

Далі до кожного інтерфейса додамо адресу в мережі /30, в якій молодшу адресу й надаму інтерфейсу:

/ip address
add address=192.168.77.1/30 interface=wireguard1
add address=192.168.77.5/30 interface=wireguard5
add address=192.168.77.9/30 interface=wireguard9
add address=192.168.77.13/30 interface=wireguard13

Далі для кожного інтерфейса створимо peer-а:

/interface wireguard peers
add allowed-address=0.0.0.0/0 client-address=192.168.77.2/30 client-endpoint=NA.NB.NC.ND client-keepalive=20s interface=wireguard1 is-responder=yes name=peer-2 private-key=auto
add allowed-address=0.0.0.0/0 client-address=192.168.77.6/30 client-endpoint=NA.NB.NC.ND client-keepalive=20s interface=wireguard5 is-responder=yes name=peer6  private-key=auto
add allowed-address=0.0.0.0/0 client-address=192.168.77.10/30 client-endpoint=NA.NB.NC.ND client-keepalive=20s interface=wireguard9 is-responder=yes name=peer-10 private-key=auto
add allowed-address=0.0.0.0/0 client-address=192.168.77.14/30 client-endpoint=NA.NB.NC.ND client-keepalive=20s interface=wireguard13 is-responder=yes name=peer-10 private-key=auto

Тут NA.NB.NC.ND це ip-адреса серверної частини WireGuard.

В принципі все, що стосується налаштування саме серверної частини WireGuard ми фактично зробили. Ми створили клієнтів яким дозволили через тунель весь трафік (тобто не тільки приватні мережі, а й вихід до Інтернет).

Подивитися конфігурацію для налаштування клієнта, а також і QR-код, можна, наприклад, так:

/interface/wireguard/peers show-client-config number=[find interface=wireguard1 ]

або ж через winbox.

Тепер пару слів про налаштування файрволу. Звісно, що у кожного може бути своє бачення, але поділюся своїм. Весь файрвол, безумовно, наводити не стану, лише ту частину яка стосується саме WireGuard.

/interface list
add name=WIREGUARD
/interface list member
add interface=wireguard1 list=WIREGUARD
add interface=wireguard5 list=WIREGUARD
add interface=wireguard9 list=WIREGUARD
add interface=wireguard13 list=WIREGUARD
/ip firewall address-list
add address=192.168.77.0/24 list=WIREGUARD
/ip firewall filter
add action=accept chain=input in-interface-list=WIREGUARD
add action=jump chain=input in-interface-list=INTERNET jump-target=wireguard
add action=fasttrack-connection chain=forward connection-state=established,related hw-offload=yes
add action=accept chain=forward connection-state=established,related
add action=accept chain=forward in-interface-list=WIREGUARD out-interface-list=LAN
add action=accept chain=forward in-interface-list=WIREGUARD out-interface-list=INTRANET
add action=accept chain=forward in-interface-list=WIREGUARD out-interface-list=INTERNET
add action=accept chain=wireguard dst-port=12001 protocol=udp
add action=accept chain=wireguard dst-port=12005 protocol=udp
add action=accept chain=wireguard dst-port=12009 protocol=udp
add action=accept chain=wireguard dst-port=12013 protocol=udp
/ip firewall nat
add action=masquerade chain=srcnat out-interface-list=LAN src-address-list=WIREGUARD
add action=masquerade chain=srcnat out-interface-list=INTRANET src-address-list=WIREGUARD
add action=masquerade chain=srcnat out-interface-list=INTERNET src-address-list=WIREGUARD

Ідея, сподіваюся, є прозорою і зрозумілою, тому розжовувати що тут до чого, ну от не хочу.

От і все. В такій конфігурації клієнти (peer-и) чудово працюють паралельно, не заважаючи один одному.

Звісно, що порти та назви інтерфейсів кожен може взяти і обізвати так як йому зручно. Мені було зручно щоб був збіг з останнім октетом приватної адреси… якщо ж не вистачить то буде якось інакше.

Про налаштування кліантів на Android писати не стану там все не просто, а дуже просто: скануєте qr-код і все працює!

З очевидних недоліків такої конфігурації - дуже багато інтерфейсів і адрес, які треба прописати. Тому там де можна було введено list-и.

Очевидний плюс: простота налаштування клієнта - в переважній більшості все зводиться до простого сканування qr-кода.

вівторок, 23 квітня 2024 р.

dpkg-deb: error: archive '…skip….deb' uses unknown compression for member 'control.tar.zst', giving up

 За останні декілька днів вже два рази зіткнувся з помилкою "unknown compression for member" при встановленні deb-пакетів. Один раз це відбулося в Linux-контейнері FydeOS, другий раз в Debian Bullseye (11.9). І так, я цілком усвідомлюю, що є новіша версія Debian і там такої помилки не буде. Але що робити якщо є?

Було знайдено наступний "рецепт" (на прикладі apache-netbeans_21-1_all.deb):

$ mkdir apache-netbeans_21-1
$ cd apache-netbeans_21-1/
$ ln -s ../apache-netbeans_21-1_all.deb .
$ ar x apache-netbeans_21-1_all.deb
$ zstd -d < control.tar.zst | xz > control.tar.xz
$ zstd -d < data.tar.zst | xz > data.tar.xz
$ rm apache-netbeans_21-1_all.deb
$ ar -m -c -a sdsd apache-netbeans_21-1_all.deb debian-binary control.tar.xz data.tar.xz
$ rm debian-binary control.tar.xz data.tar.xz control.tar.zst data.tar.zst
$ sudo dpkg -i apache-netbeans_21-1_all.deb

субота, 6 квітня 2024 р.

Key is stored in legacy trusted.gpg keyring, see the DEPRECATION section in apt-key(8) for details

 Дано:

$ apt update
В кеші:1 http://raspbian.raspberrypi.org/raspbian bookworm InRelease
В кеші:2 http://archive.raspberrypi.org/debian bullseye InRelease                                                    
В кеші:3 https://download.docker.com/linux/raspbian bullseye InRelease                                               
Зчитування переліків пакунків... Виконано           
Побудова дерева залежностей... Виконано
Зчитування інформації про стан... Виконано   
1 package can be upgraded. Run 'apt list --upgradable' to see it.
W: http://raspbian.raspberrypi.org/raspbian/dists/bookworm/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

"Ліки":

$ apt-key list | grep -A4 "trusted.gpg$"
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg
--------------------
pub   rsa2048 2012-04-01 [SC]
      A0DA 38D0 D76E 8B5D 6388  7281 9165 938D 90FD DD2E
uid           [невідома] Mike Thompson (Raspberry Pi Debian armhf ARMv6+VFP) <mpthompson@gmail.com>

$ sudo apt-key export 90FDDD2E | sudo gpg --dearmor -o /tmp/raspi.gpg
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).

$ file /tmp/raspi.gpg
/tmp/raspi.gpg: OpenPGP Public Key Version 4, Created Sun Apr  1 21:02:33 2012, RSA (Encrypt or Sign, 2048 bits); User ID; Signature; OpenPGP Certificate

$ sudo apt-key del 90FDDD2E
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
OK

$ sudo mv /tmp/raspi.gpg /etc/apt/trusted.gpg.d/

$ apt update
В кеші:1 http://archive.raspberrypi.org/debian bullseye InRelease
В кеші:2 https://download.docker.com/linux/raspbian bullseye InRelease                                              
В кеші:3 http://raspbian.raspberrypi.org/raspbian bookworm InRelease                                                
Зчитування переліків пакунків... Виконано        
Побудова дерева залежностей... Виконано
Зчитування інформації про стан... Виконано   
1 package can be upgraded. Run 'apt list --upgradable' to see it.

пʼятниця, 29 березня 2024 р.

Enable additional developer mode features: root file system write permission

 

Last Update: 2024-03-12

The following guide or recipe requires shell access to your FydeOS installation, therefore “developer mode” is assumed to be enabled.

In FydeOS, if you need to modify system files or perform custom operations, you must first disable root file system verification. This step is taken for security reasons, aimed at preventing system stability and security issues that could arise from unauthorized modifications. Here are the detailed instructions:

  1. Press Control + Alt + T on your FydeOS desktop to open the terminal.
  2. Type shell and hit Enter to access the shell environment.
  3. Enter sudo -i to get root permissions.
  4. Execute /usr/sbin/crossystem_mode-switch.sh disable-rootfs-verification to turn off root file system verification.
  5. Reboot your device.

середа, 27 березня 2024 р.

Налаштовуємо netfilter в Linux для виявлення потенційно небажаного трафіка

 Хочу поділится одним "рецептом", який алгоритм роботи якого вже доволі давно було опробовано на RouterOS і от лише нещодавно переписано під netfilter.

В чому полягає ідея?

До того як з'єднання буде встановлено у стан established перевірити потік трафіку, скажемо так, на періодичність доступу. Адже, давайте скажемо чесно, доступ до наших ресурсів (до нашого хоста) з тих чи інших адрес в Інтернет, на порти, на яких не задіяно жодних сервісів, завжди виглядає як не небажаним то підозрілим.

Що ми робимо? Ми організовуємо set-и з timeout-ами. Ці timeout-и можуть бути виставлені в доволі різні значення, але ідея полягає саме в тому, щоб обмежити доступ до хоста, якщо хтось доволі сильно знахабніє у встановлений час. Set-ів може бути багато, може бути мало, в прикладі їх наведено 16. За аналогією можна зробити 10, а можна зробити й 20, тут вже лише фантазія обмежує.

Від лірики до практики.

sudo nft add table ip scanDetector

Створимо "списки довіри". Хтось може обізвати whitelist, але я обізвав trusted та ignore, так вже історично склалося.

sudo nft add set ip scanDetector trusted { type ipv4_addr\; flags interval\; auto-merge\; comment \"Truster ip and net\" \; }
sudo nft add element ip scanDetector trusted { 192.168.1.0/24, 195.38.16.2, 195.38.16.8 }

sudo nft add set ip scanDetector ignore { type ipv4_addr\; flags interval\; auto-merge\; comment \"Ignore ip and net\" \; }
sudo nft add element ip scanDetector ignore { 0.0.0.0, 127.0.0.0/8 }

Тепер створимо set-и у створеній нами таблиці scanDetector:
sudo nft add set ip scanDetector level15 { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 15\" \; timeout 1m \; }
sudo nft add set ip scanDetector level14 { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 14\" \; timeout 2m \;  }
sudo nft add set ip scanDetector level13 { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 13\" \; timeout 3m \;  }
sudo nft add set ip scanDetector level12 { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 12\" \; timeout 4m \;  }
sudo nft add set ip scanDetector level11 { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 11\" \; timeout 5m \;  }
sudo nft add set ip scanDetector level10 { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 10\" \; timeout 10m \;  }
sudo nft add set ip scanDetector level9  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 9\" \;  timeout 15m \;  }
sudo nft add set ip scanDetector level8  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 8\" \;  timeout 20m \; }
sudo nft add set ip scanDetector level7  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 7\" \;  timeout 30m \; }
sudo nft add set ip scanDetector level6  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 6\" \;  timeout 40m \; }
sudo nft add set ip scanDetector level5  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 5\" \;  timeout 50m \; }
sudo nft add set ip scanDetector level4  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 4\" \;  timeout 1h \; }
sudo nft add set ip scanDetector level3  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 3\" \;  timeout 1h10m \; }
sudo nft add set ip scanDetector level2  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 2\" \;  timeout 1h20m \; }
sudo nft add set ip scanDetector level1  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 1\" \;  timeout 1h30m \; }
sudo nft add set ip scanDetector level0  { type ipv4_addr\; flags dynamic\; comment \"SynScan Level 0\" \;  timeout 3h \; }
sudo nft add set ip scanDetector scan    { type ipv4_addr\; flags dynamic\; comment \"Scan Detect\" \;      timeout 31d \; }
"Повісимо" hook і дамо йому priority нижчий за той в якому робимо всі інші перевірки з контролю доступу:
sudo nft add chain ip scanDetector input { type filter hook input priority -50 \; }
Ну й нарешті правила, які контролюють всі пакети, які ще не пройшли перевірки, тобто мають state new, а не established, тощо:
do nft add rule scanDetector input ct state new ip saddr @trusted counter log return
sudo nft add rule scanDetector input ct state new ip saddr @ignore counter log return
sudo nft add rule scanDetector input ct state new ip saddr != @scan    ip saddr @level0  add @scan    { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level0  ip saddr @level1  add @level0  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level1  ip saddr @level2  add @level1  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level2  ip saddr @level3  add @level2  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level3  ip saddr @level4  add @level3  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level4  ip saddr @level5  add @level4  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level5  ip saddr @level6  add @level5  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level6  ip saddr @level7  add @level6  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level7  ip saddr @level8  add @level7  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level8  ip saddr @level9  add @level8  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level9  ip saddr @level10 add @level9  { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level10 ip saddr @level11 add @level10 { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level11 ip saddr @level12 add @level11 { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level12 ip saddr @level13 add @level12 { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level13 ip saddr @level14 add @level13 { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level14 ip saddr @level15 add @level14 { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr != @level15                   add @level15 { ip saddr } counter
sudo nft add rule scanDetector input ct state new ip saddr @scan update @scan { ip saddr } counter log prefix \"[nft] scandetect-input-drop \" drop
sudo nft add rule scanDetector input              ip saddr @scan update @scan { ip saddr } counter log prefix \"[nft] scandetect-input-another-drop \" drop
Тобто, безумовно пропускаємо трафак з хостів та мереж, які було додано в set-и trusted та ignore.  Хости в списки level15…level0 додаються поступово. І це нормально. Не кожен хто до нас "стукає" може бути зловмисником. Але якщо стукає ну дуже вже нахабно то рано чи пізно він потрапить в список scan. Так, в set scan потрапляють лише і виключно ті хости, які були ну ду-у-у-у-уже нахабними. А вибратися з set-у scan не так вже й просто, бо якщо виявляється new-пакет з хоста, що вже є в set-і scan то час його перебування в списку оновлюється на початковий, той, що задано параметром timeout.
От такий от рецепт з блокування доступу.

Масштабуємо рішення на доступ до docker-контейнерів.

Все це добре, але щоб контролювати транзитний трафік hook на input нам не дуже підходить. То додаємо hook на forward:
sudo nft add chain ip scanDetector forward { type filter hook forward priority -50 \; }
Ну, а далі треба пройтися по інтерфейсах, на яких "живуть" docker-контейнери і на них "підвісити" правила. Для цього можна скористатися переглядом або всіх netfilter-правил:
sudo nft list ruleset
або ж лише тієї частки в яких задано chain DOCKER, в моєму випадку це:
sudo nft list table filter
То ж сформуємо правила:
for IFACE in $( sudo nft list table filter | sed '/chain DOCKER {/,/^$/!d;/^$/,$d' | awk '$4~/^oifname$/ { print $5 }' | tr -d \" | sort -u ); do
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr @trusted counter log return
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr @ignore counter log return
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @scan    ip saddr @level0  add @scan    { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level0  ip saddr @level1  add @level0  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level1  ip saddr @level2  add @level1  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level2  ip saddr @level3  add @level2  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level3  ip saddr @level4  add @level3  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level4  ip saddr @level5  add @level4  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level5  ip saddr @level6  add @level5  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level6  ip saddr @level7  add @level6  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level7  ip saddr @level8  add @level7  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level8  ip saddr @level9  add @level8  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level9  ip saddr @level10 add @level9  { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level10 ip saddr @level11 add @level10 { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level11 ip saddr @level12 add @level11 { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level12 ip saddr @level13 add @level12 { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level13 ip saddr @level14 add @level13 { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level14 ip saddr @level15 add @level14 { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr != @level15                   add @level15 { ip saddr } counter
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE} ct state new ip saddr @scan update @scan { ip saddr } counter log prefix \"[nft] scandetect-forward-drop \" drop
    sudo nft add rule scanDetector forward iifname != ${IFACE} oifname ${IFACE}              ip saddr @scan update @scan { ip saddr } counter log prefix \"[nft] scandetect-forward-another-drop \" drop
done
Все, всі правила в table scanDetector сформовано. Заданий priority для chain нижчий за той, що задано hook-ами в table filter, відповідно й всі ці перевірки будуть виконуватися раніше. І лише після цих перевірок пакети потралятимуть на перевірку в table filter.

Подивитися на те, що вийшло

Всі set-и та правила:

sudo nft list table scanDetector

Подивитися на вміста set-у scan:

sudo nft list table scanDetector | sed '/set scan {/,/^$/!d;/^$/,$d'

Кількість елементів у set-і scan:

sudo nft list table scanDetector | sed '/set scan {/,/^$/!d;/^$/,$d' | egrep expires | awk -v RS='[[:space:]]+' '/expires/' | wc -l

Які підводні камені?

Ну, наприклад, одних з неприємних моментів, при застосуванні лише цих правил, може бути блокування зовнішніх клієнтів, наприклад, web-сервісів, які можуть бути розташовані на хосту. Вірішеється це доволі просто, теж з set-ами, але це тема для зовсім іншої статті.

неділя, 24 березня 2024 р.

Встановлення VirtualBox на Debian 12 (bookworm)

Без зайвих слів, покроково:

  1. wget -O- -q https://www.virtualbox.org/download/oracle_vbox_2016.asc | sudo gpg --dearmour -o /usr/share/keyrings/oracle_vbox_2016.gpg
  2. echo "deb [arch=amd64 signed-by=/usr/share/keyrings/oracle_vbox_2016.gpg] http://download.virtualbox.org/virtualbox/debian bookworm contrib" | sudo tee /etc/apt/sources.list.d/virtualbox.list
  3. sudo apt update
  4. sudo apt install virtualbox-7.0
  5. wget https://download.virtualbox.org/virtualbox/$( vboxmanage -v | cut -dr -f1 )/Oracle_VM_VirtualBox_Extension_Pack-$( vboxmanage -v | cut -dr -f1 ).vbox-extpack
  6. sudo vboxmanage extpack install Oracle_VM_VirtualBox_Extension_Pack-7.0.14.vbox-extpack
    vboxmanage list extpacks
  7. groups ${USERNAME}
    sudo usermod -a -G vboxusers ${USERNAME}

четвер, 11 січня 2024 р.

Альтернатива poweroff та reboot в Linux

Так чи інакше, всі сучасні, більш-менш просунуті в консолі користувачі Linux знають про команди:

$ sudo reboot
$ sudo poweroff

Косматі діді з бородами можуть згадати про магічні заклинання через команду shutdown, як то, в сачасній інтерпретації:

$ sudo shutdown -r -t now
$ sudo shutdown -P -t now

Але для справжніх джедаїв є інший шлях!

Якщо "не хочуть" працювати а ні reboot, а ні poweroff то…

Перезавантажуємо хост з Linux на борту:

# echo 1 > /proc/sys/kernel/sysrq
# echo b > /proc/sysrq-trigger

Те саме, тільки перед перезавантаженням робимо аналог sync

# echo 1 > /proc/sys/kernel/sysrq
# echo s > /proc/sysrq-trigger
# echo b > /proc/sysrq-trigger

Ну, а наступні магічні закляття просто вимикають хост:

# echo 1 > /proc/sys/kernel/sysrq
# echo о > /proc/sysrq-trigger

Як при цьому ще й зробити sync, пропоную здогадатися самостійно ;)

пʼятниця, 5 січня 2024 р.

Не відкриваються jar-файли у Midnight Commander в Debian

Дуже, дуже дратувало те, що після того як в netbeans було зібрано jar-файл, mc відмовлявся його відкривати та переглядати і видавав помилку.

Як це завжди буває, все вирішилося не просто, а надто просто. В mc переходимо в розділ меню Command  Edit extension file (або ж дивимося файл ~/.config/mc/mc.ext) і бачимо, що про розширення jar просто "забули".

Ну… буває. Нічого страшного. Просто десь після zip додаємо jar:

# zip
shell/i/.zip
        Open=%cd %p/uzip://
        View=%view{ascii} /usr/lib/mc/ext.d/archive.sh view zip

# jar
shell/i/.jar
        Open=%cd %p/uzip://
        View=%view{ascii} /usr/lib/mc/ext.d/archive.sh view zip

# zoo
shell/i/.zoo
        Open=%cd %p/uzoo://
        View=%view{ascii} /usr/lib/mc/ext.d/archive.sh view zoo

Все! Тепер jar-файли почали відкриватися по Enter.

четвер, 28 грудня 2023 р.

binfmts для exe-файлів

В попередній статті я частково вже зачепив тему binfmts.

Що це за приблуда, що це за звір такий?

update-binfmts — maintain registry of executable binary formats

Тобто в Debian (та й інших дистрибутивах Linux) ми можемо запускати бінарні файли на виконання, навіть якщо це не ELF. Просто для цього треба навчити Linux їх запускати.

Для початку можна подивитися на вже встановлені зв'язки. Виглядатиме це приблизно так:

$ sudo update-binfmts --display
cli (enabled):
     package = mono-runtime
        type = magic
      offset = 0
       magic = MZ
        mask = 
 interpreter = /usr/bin/cli
    detector = /usr/lib/cli/binfmt-detector-cli
jar (enabled):
     package = oracle-java16
        type = magic
      offset = 0
       magic = PK\x03\x04
        mask = 
 interpreter = /usr/lib/jvm/java-16-oracle/lib/jexec
    detector = 
python2.7 (enabled):
     package = python2.7
        type = magic
      offset = 0
       magic = \x03\xf3\x0d\x0a
        mask = 
 interpreter = /usr/bin/python2.7
    detector = 
python3.9 (enabled):
     package = python3.9
        type = magic
      offset = 0
       magic = \x61\x0d\x0d\x0a
        mask = 
 interpreter = /usr/bin/python3.9
    detector = 

Як бачимо то тут встановлено зв'язки для бінарних (скопмільованих) форматів - cli (exe), jar, python 2.7 та 3.9.

Якщо раптом закортить додати запуск exe (MZ) не через wine то достатньо просто додати наступну конфігурацію:

$ sudo update-binfmts --package wine --install wine /usr/bin/wine --magic 'MZ'

Дивимося:

$ sudo update-binfmts --display
cli (enabled):
     package = mono-runtime
        type = magic
      offset = 0
       magic = MZ
        mask = 
 interpreter = /usr/bin/cli
    detector = /usr/lib/cli/binfmt-detector-cli
jar (enabled):
     package = oracle-java16
        type = magic
      offset = 0
       magic = PK\x03\x04
        mask = 
 interpreter = /usr/lib/jvm/java-16-oracle/lib/jexec
    detector = 
python2.7 (enabled):
     package = python2.7
        type = magic
      offset = 0
       magic = \x03\xf3\x0d\x0a
        mask = 
 interpreter = /usr/bin/python2.7
    detector = 
python3.9 (enabled):
     package = python3.9
        type = magic
      offset = 0
       magic = \x61\x0d\x0d\x0a
        mask = 
 interpreter = /usr/bin/python3.9
    detector = 
wine (enabled):
     package = wine
        type = magic
      offset = 0
       magic = MZ
        mask = 
 interpreter = /usr/bin/wine
    detector = 

Все, після цього можна "прозоро" запускати exe-файли через wine. Наприклад:

$ chmod +x ./winbox-3.40.exe
$ ./winbox-3.40.exe

Якщо ж хочеться встановити коректне відображення кодування CP1251 то можна виконати запуск наступним чином:

$ LANG=ru_RU.cp1251 luit winbox.exe

Видалити конфігурацію binfmts так само легко як і встановити:

$ sudo update-binfmts --package wine --remove wine /usr/bin/wine

Ось така магія ;)

Java 21 & Debian (Ubuntu)

Нарешті! Нарешті це сталося!

Oracle почала випускати deb-пакети з Java. Принаймні Java 21 вже можна завантажити як deb-пакет. А далі все стає просто і без зайвих танців з бубном. За потреби, видаляємо залишки openjdk:

sudo apt purge openjdk-17-jre-headless

Також, переда встановленням deb-пакету з Java 21, краще видалити binfmts для попередньої версії (в моєму випадку це openjdk-17):

sudo update-binfmts --display
sudo update-binfmts --package openjdk-17 --remove jar /usr/bin/jexec

Встановлюємо пакет:

sudo dpkg -i jdk-21_linux-x64_bin.deb

Все ;)

понеділок, 18 грудня 2023 р.

Viber 21.0.0.1 на Debian 11.8 (Bullseye)

 Зіткнувся з проблемою при оновленні версії Viber, а саме - припинив запускатися. При запуску в консолі виводить наступне:

$ /opt/viber/Viber
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: wayland, eglfs, minimalegl, minimal, offscreen, vnc, linuxfb, wayland-egl, xcb.
З'ясувалося, що лікується доволі просто, хоч і не очевидно. Встановлюємо пакет libxcb-cursor0:
$ sudo apt install libxcb-cursor0
Після встановлення Viber "ожив".
Неочевидність полягає саме в тому, що встановлення самого по собі пакету xcb не допомагає. Більше того, для роботи Viber, його можна й не встановлювати.

вівторок, 5 грудня 2023 р.

Debian 11: deb uses unknown compression for member

 Звісно, що вже є Debian 12, але подекуди доводиться використовувати старіші версії. Так от трапилося й у мене. Debian 11 "матюгнувся":

$ sudo dpkg -i apache-netbeans_20-1_all.deb
dpkg-deb: error: archive 'apache-netbeans_20-1_all.deb' uses unknown compression for member 'control.tar.zst', giving up
dpkg: error processing archive apache-netbeans_20-1_all.deb (--install):
 dpkg-deb --control subprocess returned error exit status 2
Errors were encountered while processing:
 apache-netbeans_20-1_all.deb
Ну, нічого страшного. Просто доведеться перепакувати deb-пакет з тим методом компресії, який відомий Debian 11.

$ ar x apache-netbeans_20-1_all.deb
$ zstd -d < control.tar.zst | xz > control.tar.xz
$ zstd -d < data.tar.zst | xz > data.tar.xz
$ ar -m -c -a sdsd /tmp/apache-netbeans_20-1_all.deb debian-binary control.tar.xz data.tar.xz
$ rm debian-binary control.tar.xz data.tar.xz control.tar.zst data.tar.zst
$ sudo dpkg -i /tmp/apache-netbeans_20-1_all.deb
(Reading database ... 398738 files and directories currently installed.)
Preparing to unpack .../apache-netbeans_20-1_all.deb ...
Unpacking apache-netbeans (20-1) over (19-1) ...
Setting up apache-netbeans (20-1) ...
Processing triggers for gnome-menus (3.36.0-1) ...
Processing triggers for desktop-file-utils (0.26-1) ...
Processing triggers for mailcap (3.69) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Незручність лише в тому, що така конвертація займає певний час та місце.

четвер, 26 жовтня 2023 р.

Встановлення Zabbix-агента на Windows

  1. Завантажуємо https://cdn.zabbix.com/zabbix/binaries/stable/6.4/6.4.7/zabbix_agent-6.4.7-windows-amd64.zip
  2. Розпаковуємо архів zabbix_agent-6.4.7-windows-amd64.zip, наприклад, в c:\zabbix
  3. Відкриваємо на редагування C:\Zabbix\conf\zabbix_agentd.conf і правимо:
    1. LogFile=c:\Zabbix\zabbix_agentd.log
    2. Server=127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 - тут через кому перераховуємо мережі з яких буде доступним Zabbix-агент, точніше мережі на запити з яких він буде відповідати, якщо ці запити надійдуть
    3. Hostname=Windows host - тут замість "Windows host" пишемо свою назву, головне щоб вона збігалася з тою з якою ми будемо реєструвати цей хост на Zabbix-сервері
  4. В cmd, в режимі адміністратора, виконуємо:
    1. C:\Zabbix\bin\zabbix_agentd.exe --config C:\Zabbix\conf\zabbix_agentd.conf --install
    2. C:\Zabbix\bin\zabbix_agentd.exe --config C:\Zabbix\conf\zabbix_agentd.conf --start
  5. В cmd, в режимі адміністратора, та виконуємо:
    1. netsh advfirewall firewall add rule name="Open Zabbix agentd port 10050 inbound" dir=in action=allow protocol=TCP localport=10050
    2. netsh advfirewall firewall add rule name="Open Zabbix agentd port 10050 outbound" dir=out action=allow protocol=TCP localport=10050
    3. (опціонально) netsh advfirewall firewall add rule name="Open Zabbix trapper port 10051 inbound" dir=in action=allow protocol=TCP localport=10051
    4. (опціонально) netsh advfirewall firewall add rule name="Open Zabbix trapper port 10051 outbound" dir=out action=allow protocol=TCP localport=10051

понеділок, 2 жовтня 2023 р.

Встановлення з'єднання wireguard між Mikrotik та Linux (Debian)

Linux

Встановлюємо пакети wireguard та wireguard-dkms:

# apt install wireguard wireguard-dkms

Створюємо пару ключів:

# cd /etc/wireguard
# wg genkey > private-key
# wg pubkey > public-key < private-key

Скоріш за все, після цього, не зможете отримати доступ з під поточного користувача до файлів /etc/wireguard/private-key та /etc/wireguard/public-key. Хтось грається з заміною користувача та/або групи для каталогу /etc/wireguard, але я пропоную/практикую інший шлях:

$ sudo setfacl -m u:username:r-x /etc/wireguard
$ sudo setfacl -m u:username:r-x /etc/wireguard/private-key
$ sudo setfacl -m u:username:r-x /etc/wireguard/public-key

Отримуємо/дивимося на пару ключів:

$ cat /etc/wireguard/public-key
$ cat /etc/wireguard/private-key

Mikrotik

Тут все простіше:

/interface wireguard
add listen-port=13231 mtu=1420 name=wireguard1
/interface wireguard peers
add allowed-address=0.0.0.0/0 endpoint-address=10.10.10.11 endpoint-port=13231 interface=wireguard1 persistent-keepalive=30s public-key="…public key from /etc/wireguard/public-key…"
/ip address
add address=10.3.2.1/30 interface=wireguard1

Linux NetworkManager

Файл /etc/NetworkManager/system-connections/wireguard1.nmconnection при цьому може виглядати якось так:

[connection]
id=wireguard1
uuid=6b31553d-8782-4952-98e2-739ef4a05a87
type=wireguard
autoconnect=false
interface-name=wireguard1
permissions=
timestamp=1696251106

[wireguard]
listen-port=13231
private-key=…private key from /etc/wireguard/private-key…

[wireguard-peer.…public key from Mikrotik…]
endpoint=10.10.10.10:13231
persistent-keepalive=30
allowed-ips=10.3.2.0/24;192.168.88.0/24;

[ipv4]
address1=10.3.2.2/30
dns-search=
method=manual

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=ignore

[proxy]

Після чого активуємо інтерфейс:

$ sudo nmcli con up wireguard1

Все просто й доступно.

понеділок, 25 вересня 2023 р.

Як ввімкнути rc.local в Debian?

Якщо ви запускаєте дистрибутив Linux з використанням Systemd, то можете помітити, що при завантаженні системи інструкції з файлу /etc/rc.local не виконуються. Далі в статті йдеться про те як це виправити.

Якщо раптом при виконанні команди sudo systemctl status rc.local  побачите подібне повідомлення:
$ sudo systemctl status rc-local
○ rc-local.service - /etc/rc.local Compatibility
     Loaded: loaded (/lib/systemd/system/rc-local.service; static)
    Drop-In: /usr/lib/systemd/system/rc-local.service.d
             └─debian.conf
     Active: inactive (dead)
       Docs: man:systemd-rc-local-generator(8)
Або інше, відмінне від "Active: active", а sudo systemctl enable rc-local  видасть
$ sudo systemctl enable rc-local
The unit files have no installation config (WantedBy=, RequiredBy=, Also=,
Alias= settings in the [Install] section, and DefaultInstance= for template
units). This means they are not meant to be enabled using systemctl.
 
Possible reasons for having this kind of units are:
• A unit may be statically enabled by being symlinked from another unit's
  .wants/ or .requires/ directory.
• A unit's purpose may be to act as a helper for some other unit which has
  a requirement dependency on it.
• A unit may be started when needed via activation (socket, path, timer,
  D-Bus, udev, scripted systemctl call, ...).
• In case of template units, the unit is meant to be enabled with some
  instance name specified.
То можна виконати наступні інструкції, які мають виправити ситуацію:

$ echo "[Unit]
Description=/etc/rc.local Compatibility
ConditionPathExists=/etc/rc.local

[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99

[Install]
WantedBy=multi-user.target" | sudo tee /etc/systemd/system/rc-local.service > /dev/null
$ printf '%s\n' '#!/bin/bash' 'exit 0' | sudo tee -a /etc/rc.local
#!/bin/bash
exit 0
$ sudo chmod +x /etc/rc.local
$ sudo systemctl enable rc-local
Created symlink /etc/systemd/system/multi-user.target.wants/rc-local.service → /etc/systemd/system/rc-local.service.
$ sudo systemctl start rc-local.service
І отримати результат:
$ sudo systemctl status rc-local.service
* rc-local.service - /etc/rc.local Compatibility
     Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; preset: enabled)
    Drop-In: /usr/lib/systemd/system/rc-local.service.d
             `-debian.conf
     Active: active (exited) since Mon 2023-09-25 13:38:53 EEST; 15min ago
    Process: 34112 ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS)
        CPU: 1ms

Sep 25 13:38:53 oghome systemd[1]: Starting rc-local.service - /etc/rc.local Compatibility...
Sep 25 13:38:53 oghome systemd[1]: Started rc-local.service - /etc/rc.local Compatibility.
За мотивами статті How to Enable /etc/rc.local with Systemd.