A single point of exit to the web, I2P, TOR and blocking bypass

Єдина точка виходу в web, I2P, TOR та обхід блокувань

Грабовий
хв

Преамбула ... Ця стаття була написана ще влітку але, з незалежних від автора причин, трохи підзатрималася...


Одного разу, спекотного літнього вечора, після чергової введеної в консолі браузера команди виду:set content.proxy socks://localhost:9050, Автор цього опусу зрозумів, що далі так жити не можна і час приводити вихід у всякі приховані мережі, а заодно і обхід блокувань імені відомої організації до якогось єдиного, для будь-якого софту взагалі і браузера зокрема, «спільному знаменнику». А як наводити? Вочевидь так, щоб проксі сервер сам «розумів», через який вищестоящий проксі відправляти та приймати трафік залежно від введеної адреси. Друга мета, що випливає з першої, вищестоящі проксі можуть працювати або як http, або як socks і обидва протоколи повинні підтримуватися вхідним проксі. Ну і сам софт повинен бути більш-менш актуальним, щоб у разі помилок або «хотіння фіч», не доводилося сумно дивитися на самотню ріпу на гітхабі, а то й взагалі на якомусь сорсфоржі.
Отже, цілі поставлені!


Муки вибору


Насправді особливих мук не було. Бо, за великим рахунком, з відомих проксі серверів поставленим вимогам задовольняли два. Це privoxyі tinyproxyАле tinyproxyвиявився живішим, легковажнішим і простішим, тому і був обраний і негайно встановлений (як приклад використовується поточна версія Manjaro Linux).


sudo pacman -Syu tinyproxy

Само собою, раніше, вже були встановлені налаштовані пакети torта i2pdsudo pacman -Syu tor i2pd).


Базове налаштування tinyproxy


Отже, налаштуємо базові перенаправлення, щоб у звичайний web ходило безпосередньо, а *.i2pчерез *.onionвідповідні вищестоящі (parent) proxy.


/etc/tinyproxy/tinyproxy.conf:


User tinyproxy
Group tinyproxy
PidFile "/var/run/tinyproxy/tinyproxy.pid"

Port 8888
Listen 127.0.0.1
Timeout 600

DefaultErrorFile "/usr/share/tinyproxy/default.html"
StatFile "/usr/share/tinyproxy/stats.html"

Syslog On
# Set the logging level. Allowed settings are:
#   Critical, Error, Warning, Notice, Connect, Info
LogLevel Info

MaxClients 100
MinSpareServers 5
MaxSpareServers 20
StartServers 10
MaxRequestsPerChild 0

Allow 127.0.0.1

ViaProxyName "tinyproxy"

## Parent proxy for TOR hosts
upstream socks5 127.0.0.1:9050 ".onion"
## Parent proxy for I2P hosts
upstream socks5 127.0.0.1:4447 ".i2p"

##### End of static configuration #####

Спочатку всі параметри в конфізі залишаються за замовчуванням.


  • Зберігаємо
  • Запускаємо:sudo systemctl enable --now tinyproxy
  • Перевіряємо: journalctl -f -u tinyproxy, паралельно намагаємося зайти на i2p і onion ресурси (налаштувавши браузер на використання http proxy http://localhost:8888) і бачимо в лог файлі повідомлення про перенаправлення на parent proxy's:
    июл 20 01:36:16 dell-lnx tinyproxy[198356]: Request (file descriptor 6): GET http://flibusta.i2p/ HTTP/1.1
    июл 20 01:36:17 dell-lnx tinyproxy[198356]: Found upstream proxy socks5 127.0.0.1:4447 for flibusta.i2p
    июл 20 01:36:17 dell-lnx tinyproxy[198356]: opensock: opening connection to 127.0.0.1:4447
    июл 20 01:36:17 dell-lnx tinyproxy[198356]: opensock: getaddrinfo returned for 127.0.0.1:4447
    июл 20 01:36:17 dell-lnx tinyproxy[198356]: Established connection to socks5 proxy "127.0.0.1" using file descriptor 7.
    июл 20 01:36:40 dell-lnx tinyproxy[198356]: Closed connection between local client (fd:6) and remote client (fd:7)
    ...
    июл 20 01:39:36 dell-lnx tinyproxy[214495]: Found upstream proxy socks5 127.0.0.1:9050 for ilitafrzzgxymv6umx2ux7kbz3imyeko6cnqkvy4nisjjj4qpqkrptid.onion
    июл 20 01:39:36 dell-lnx tinyproxy[214495]: opensock: opening connection to 127.0.0.1:9050
    июл 20 01:39:36 dell-lnx tinyproxy[214495]: opensock: getaddrinfo returned for 127.0.0.1:9050
    июл 20 01:39:36 dell-lnx tinyproxy[214495]: Established connection to socks5 proxy "127.0.0.1" using file descriptor 7.

Список «zapret.info»


Що ж, зв'язка проксі базово працює, тепер починається найцікавіше — обхід блокувань розкомнагляду. На жаль, tinyproxyне підтримує зовнішні файли зі списком parent proxy, але це не повинно бути перешкодою. Адже ми можемо згенерувати монолітний конфіг on the fly.


  1. Копіюємо наявний конфіг tinyproxy під новим ім'ям:


    cp /etc/tinyproxy/tinyproxy.conf /etc/tinyproxy/tinyproxy.conf.static

  2. Злегка правимо новий /etc/tinyproxy/tinyproxy.conf.staticLogLevel InfoLogLevel Error


  3. Створюємо юніт, який клонуватиме репозиторій проекту zapret.info — sudo systemctl edit --full --force z-i-prepare.service:


    # /etc/systemd/system/z-i-prepare.service
    [Unit]
    Description=Zapret Info repository cloner
    ConditionPathExists=|!/usr/local/lib/z-i/
    ConditionFileNotEmpty=|!/usr/local/lib/z-i/dump.csv
    Wants=local-fs.target
    After=local-fs.target
    Wants=network.target
    After=network.target
    #
    [Service]
    Type=oneshot
    User=tinyproxy
    Group=tinyproxy
    ExecStartPre=+/usr/bin/mkdir -p /usr/local/lib/z-i
    ExecStartPre=+/usr/bin/chown tinyproxy:tinyproxy /usr/local/lib/z-i
    ExecStartPre=+/usr/bin/chmod 0750 /usr/local/lib/z-i
    ExecStart=git clone --depth 1 https://github.com/zapret-info/z-i.git /usr/local/lib/z-i

  4. Створюємо юніт який буде генерувати конфіг tinyproxy, в рантаймі - sudo systemctl edit --full --force tinyproxy-cfg-generator.service:


    # /etc/systemd/system/tinyproxy-cfg-generator.service
    [Unit]
    After=z-i-prepare.service
    Wants=z-i-prepare.service
    #
    [Service]
    Type=oneshot
    User=tinyproxy
    Group=tinyproxy
    Environment="PATH=/usr/local/bin:/usr/sbin:/usr/bin"
    ExecStart=tinyproxy-cfg-gen.sh
    StandardOutput=file:/run/tinyproxy/tinyproxy.conf

    … і власне скрипт /usr/local/bin/tinyproxy-cfg-gen.shдо нього:


    #!/usr/bin/env sh
    # tinyproxy-cfg-gen.sh -- tinyproxy dynamic config generator to stdout.
    awk -F';' '{print "upstream socks5 127.0.0.1:9050 \"" $2"\""}' /usr/local/lib/z-i/dump.csv|tr -d '*'|sort|uniq|grep -v '\s\"\"'>/tmp/tinyproxy.conf.dynamic
    cat /etc/tinyproxy/tinyproxy.conf.static /tmp/tinyproxy.conf.dynamic

  5. Таймер та сервіс, який раз на добу викачуватиме оновлення списку та рестартуватиме основний сервіс: sudo systemctl edit --full --force z-i-update-daily.timer:


    # /etc/systemd/system/z-i-update-daily.timer
    [Unit]
    Description=Zapret Info daily update
    After=network.target
    Wants=network.target
    #
    [Timer]
    OnCalendar=daily
    AccuracySec=1h
    Persistent=true
    #
    [Install]
    WantedBy=timers.target

    І сервіс до нього sudo systemctl edit --full --force z-i-update-daily.service:


    # /etc/systemd/system/z-i-update-daily.service
    [Unit]
    Description=Zapret Info daily update service
    After=network.target
    Wants=network.target
    #
    [Service]
    Type=oneshot
    User=tinyproxy
    Group=tinyproxy
    ExecStartPre=/usr/bin/git -C /usr/local/lib/z-i pull
    ExecStart=+/usr/bin/systemctl try-restart tinyproxy.service

  6. Нарешті вишенька на торті, редагуємо tinyproxy.service під наші потреби sudo systemctl edit tinyproxy.service.


    # /etc/systemd/system/tinyproxy.service.d/override.conf
    [Unit]
    Wants=network.target
    Wants=z-i-prepare.service
    After=z-i-prepare.service
    Wants=tinyproxy-cfg-generator.service
    After=tinyproxy-cfg-generator.service
    #
    [Service]
    User=tinyproxy
    Group=tinyproxy
    ExecStart=
    ExecStart=/usr/bin/tinyproxy -c /run/tinyproxy/tinyproxy.conf
    ExecStopPost=+/usr/bin/rm -rf /run/tinyproxy/tinyproxy.conf

  7. А тепер, з усім цим неподобством ми спробуємо злетіти ©


    sudo systemctl enable --now tinyproxy
    sudo systemctl enable --now z-i-update-daily.timer

    Як це працює?



Для чого такі танці з бубном? Що ж, у висновку не заважає прояснити деякі моменти. Підемо прямо по пунктах попереднього розділу.


  1. Тут все просто. Ми зберігаємо в окремому файлі ту частину конфігурації, яка не повинна змінюватись автоматично.
  2. Дуже важливий параметр, що скорочує час завантаження основного сервісу з години (SIC!) до приблизно півтори хвилини (нетбучний AMD відсотків року 2009-го і HDD на 5400 об./хв.). Зрозуміло, це не єдиний спосіб підвищення продуктивності.
  3. "bootstrap" юніт, який запускається завжди, але відпрацьовує тільки в тому випадку якщо відсутня директорія /usr/local/lib/z-i/або порожній файл /usr/local/lib/z-i/dump.csv(Директиви Condition*). Ключик --depth 1дозволяє схилювати лише останній комміт, а не всі 8 Гб.
  4. Основна генерація конфіга та ще один лайвхак для підвищення продуктивності. З csv
    awk-ом вирізується поле з доменом, що очищається від зайвих символів. Видаляються рядки з порожнім доменом, далі catнадсилає результат на stdoutа вже юніт, завдяки директиві StandardOutput=записує весь висновок у конфіг файл /runна tmpfsЗа залежностями запускається після того, як відпрацює bootstrap юніт з попереднього пункту.
  5. Раз на добу, починаючи з нуля годинника, з джиттером на годину, оновлюємо репозиторій і перегенеруємо конфіг, з рестартом сервісу. Точніше рестартуємо сервіс із перегенерацією конфігу.
  6. (І 7.) Ну тут все зрозуміло, запуск допоміжних юнітів та основного.

Ця зв'язка працює вжетиждень2,5 місяці. Глюкобагів, поки що, начебто не помічено. готові конфіги та скрипти живуть на гітхабі , PR вітаються!

Comments