Заобиколете го блокирањето на ILV со DNSTAp и BGP

Заобиколете го блокирањето на ILV со DNSTAp и BGP

Темата е прилично претепана, знам. На пример, постои голема Член, но таму се разгледува само IP делот од блок листата. Ќе додадеме и домени.

Поради фактот што судовите и РКН блокираат сè десно и лево, а давателите на услуги напорно се трудат да не потпаднат под казните издадени од Revizorro, придружните загуби од блокирањето се прилично големи. И меѓу „законски“ блокираните страници има многу корисни (здраво, rutracker)

Живеам надвор од надлежноста на РКН, но моите родители, роднини и пријатели останаа дома. Така, беше одлучено да се најде лесен начин за луѓето далеку од ИТ да го заобиколат блокирањето, по можност без нивно учество воопшто.

Во оваа белешка, нема да ги опишам основните мрежни работи во чекори, туку ќе ги опишам општите принципи за тоа како оваа шема може да се имплементира. Значи мора да се има знаење за тоа како функционира мрежата воопшто и особено во Linux.

Видови брави

Прво, да ја освежиме меморијата за блокирањето.

Постојат неколку типови на брави во истоварениот XML од RKN:

  • IP
  • Име на домен
  • URL

За едноставност, ќе ги намалиме на два: IP и домен, и едноставно ќе го повлечеме доменот од блокирање по URL (поточно, тие веќе ни го направија ова).

добри луѓе од Роскомсвобода реализира прекрасно API, преку кој можеме да го добиеме она што ни треба:

Пристап до блокирани сајтови

За да го направите ова, потребни ни се некои мали странски VPS, по можност со неограничен сообраќај - има многу такви за 3-5 долари. Треба да го земете во блиска странство, така што пингот не е многу голем, но повторно, земете во предвид дека Интернетот и географијата не секогаш се совпаѓаат. И бидејќи нема SLA за 5 долари, подобро е да земете 2+ парчиња од различни провајдери за толеранција на грешки.

Следно, треба да поставиме шифриран тунел од клиентскиот рутер до VPS. Јас го користам Wireguard како најбрз и најлесен за поставување. Имам и клиентски рутери базирани на Linux (APU2 или нешто во OpenWRT). Во случај на некои Mikrotik / Cisco, можете да ги користите протоколите достапни на нив како OpenVPN и GRE-over-IPSEC.

Идентификација и пренасочување на сообраќајот од интерес

Се разбира, можете да го исклучите целиот интернет сообраќај преку странски земји. Но, најверојатно, брзината на работа со локална содржина ќе страда многу од ова. Плус, барањата за пропусниот опсег на VPS ќе бидат многу повисоки.

Затоа, ќе треба некако да го распределиме сообраќајот на блокираните локации и селективно да го насочиме кон тунелот. Дури и ако дел од „дополнителниот“ сообраќај стигне таму, сепак е многу подобро отколку да возите сè низ тунелот.

За да управуваме со сообраќајот, ќе го користиме протоколот BGP и ќе објавиме маршрути до потребните мрежи од нашите VPS до клиентите. Да го земеме BIRD како еден од најфункционалните и најзгодните BGP демони.

IP

Со блокирање преку IP, сè е јасно: едноставно ги објавуваме сите блокирани IP-адреси со VPS. Проблемот е што има околу 600 илјади подмрежи во списокот што API ги враќа, а огромното мнозинство од нив се /32 хостови. Овој број на рути може да ги збуни слабите рутери на клиентите.

Затоа, при обработката на списокот, беше одлучено да се сумира до мрежата / 24 ако има 2 или повеќе хостови. Така, бројот на рути се намали на ~ 100 илјади. Ќе следи сценариото за ова.

домени

Покомплицирано е и има неколку начини. На пример, можете да инсталирате транспарентен Squid на секој клиентски рутер и таму да извршите пресретнување на HTTP и да ѕирнете во ракувањето со TLS за да ја добиете бараната URL во првиот случај и доменот од SNI во вториот.

Но, поради сите видови новоформирани TLS1.3 + eSNI, HTTPS анализата станува се помалку реална секој ден. Да, и инфраструктурата на клиентската страна станува посложена - ќе мора да користите барем OpenWRT.

Затоа, решив да тргнам по патот на пресретнување одговори на барањата за DNS. Овде, исто така, секој DNS-over-TLS / HTTPS почнува да лебди над вашата глава, но ние можеме (засега) да го контролираме овој дел на клиентот - или да го оневозможиме или да користиме сопствен сервер за DoT / DoH.

Како да пресретнете DNS?

Тука, исто така, може да има неколку пристапи.

  • Пресретнување на DNS сообраќај преку PCAP или NFLOG
    И двата од овие методи на пресретнување се имплементирани во алатката сидмат. Но, тој не е поддржан долго време и функционалноста е многу примитивна, па сепак треба да напишете темперамент за него.
  • Анализа на дневници на серверот DNS
    За жал, рекурзорите што ми се познати не можат да ги евидентираат одговорите, туку само барањата. Во принцип, ова е логично, бидејќи, за разлика од барањата, одговорите имаат сложена структура и тешко е да се напишат во текстуална форма.
  • DNSTap
    За среќа, многу од нив веќе поддржуваат DNSTap за оваа намена.

Што е DNSTap?

Заобиколете го блокирањето на ILV со DNSTAp и BGP

Тоа е протокол клиент-сервер базиран на протокол бафери и стримови на рамки за пренос од DNS сервер до собирач на структурирани DNS прашања и одговори. Во суштина, DNS серверот пренесува метаподатоци за барање и одговор (тип на порака, IP на клиент/сервер, итн.) плус комплетни DNS пораки во (бинарна) форма во која работи со нив преку мрежата.

Важно е да се разбере дека во парадигмата DNSTap, серверот DNS делува како клиент, а колекторот како сервер. Тоа е, серверот DNS се поврзува со колекторот, а не обратно.

Денес DNSTap е поддржан во сите популарни DNS сервери. Но, на пример, BIND во многу дистрибуции (како Ubuntu LTS) често се гради поради некоја причина без негова поддршка. Затоа, да не се замараме со повторно склопување, туку да земеме полесен и побрз рекурсор - Неврзано.

Како да фатите DNSTap?

Постои некои број CLI комунални услуги за работа со проток на настани DNSTap, но тие не се погодни за решавање на нашиот проблем. Затоа, решив да измислам свој велосипед кој ќе направи се што е потребно: dnstap-bgp

Работен алгоритам:

  • Кога ќе се стартува, вчитува список со домени од текстуална датотека, ги превртува (habr.com -> com.habr), исклучува скршени линии, дупликати и поддомени (т.е. ако списокот содржи habr.com и www.habr.com, ќе се вчита само првиот) и гради префиксно дрво за брзо пребарување низ оваа листа
  • Дејствувајќи како сервер DNSTap, тој чека врска од DNS сервер. Во принцип, поддржува и UNIX и TCP приклучоци, но DNS серверите што ги знам можат да користат само UNIX приклучоци
  • Дојдовните DNSTap пакети најпрво се десеријализираат во структура Protobuf, а потоа самата бинарна DNS порака, сместена во едно од полињата Protobuf, се анализира на ниво на записи DNS RR
  • Се проверува дали бараниот хост (или неговиот родителски домен) е во вчитаната листа, ако не, одговорот се игнорира
  • Само A/AAAA/CNAME RR се избираат од одговорот и од нив се извлекуваат соодветните IPv4/IPv6 адреси
  • IP-адресите се кеширани со TTL што може да се конфигурира и се рекламираат на сите конфигурирани BGP врсници
  • Кога примате одговор кој укажува на веќе кеширана IP адреса, нејзиниот TTL се ажурира
  • Откако ќе истече TTL, записот се отстранува од кешот и од објавите BGP

Дополнителна функционалност:

  • Препрочитување на листата на домени од SIGHUP
  • Одржување на кешот во синхронизација со други примероци dnstap-bgp преку HTTP/JSON
  • Умножете го кешот на дискот (во базата на податоци BoltDB) за да ја вратите неговата содржина по рестартирање
  • Поддршка за префрлување на друг мрежен именски простор (зошто е тоа потребно ќе биде опишано подолу)
  • Поддршка за IPv6

Ограничувања:

  • IDN домените сè уште не се поддржани
  • Неколку поставки за BGP

Собрав RPM и DEB пакети за лесна инсталација. Треба да работи на сите релативно неодамнешни ОС со systemd. тие немаат никакви зависности.

Шемата

Значи, да почнеме да ги собираме сите компоненти заедно. Како резултат на тоа, треба да добиеме нешто како оваа мрежна топологија:
Заобиколете го блокирањето на ILV со DNSTAp и BGP

Логиката на работа, мислам, е јасна од дијаграмот:

  • Клиентот го има нашиот сервер конфигуриран како DNS, а барањата за DNS исто така мора да одат преку VPN. Ова е неопходно за да може провајдерот да користи DNS пресретнување за блокирање.
  • Кога ја отворате страницата, клиентот испраќа барање за DNS како „кои се IP-адресите на xxx.org“
  • Неврзани го решава xxx.org (или го зема од кешот) и испраќа одговор до клиентот „xxx.org има таква и таква IP адреса“, дуплирајќи ја паралелно преку DNSTap
  • dnstap-bgp ги објавува овие адреси во BIRD преку BGP ако доменот е на блокираната листа
  • BIRD рекламира рута до овие IP-адреси со next-hop self клиент рутер
  • Следните пакети од клиентот до овие IP-адреси одат низ тунелот

На серверот, за маршрути до блокирани сајтови, користам посебна табела во BIRD и таа не се вкрстува со ОС на кој било начин.

Оваа шема има недостаток: првиот SYN пакет од клиентот, најверојатно, ќе има време да замине преку домашниот провајдер. рутата не се објавува веднаш. И тука се можни опции во зависност од тоа како давателот го прави блокирањето. Ако само го испушти сообраќајот, тогаш нема проблем. А ако го пренасочи на некој DPI, тогаш (теоретски) се можни специјални ефекти.

Исто така, можно е клиентите да не ги почитуваат чудата на DNS TTL, што може да предизвика клиентот да користи некои застарени записи од својата скапана кеш меморија наместо да прашува Unbound.

Во пракса, ниту првото ниту второто не ми правеа проблеми, но вашата километража може да варира.

Подесување на серверот

За полесно тркалање, напишав улога за Ансибл. Може да ги конфигурира и серверите и клиентите базирани на Linux (дизајниран за дистрибуции базирани на deb). Сите поставки се сосема очигледни и се поставени инвентар.yml. Оваа улога е отсечена од мојата голема игротека, па може да содржи грешки - повлече барања добредојде 🙂

Ајде да поминеме низ главните компоненти.

БГП

Кога се извршуваат два BGP демони на истиот домаќин, се јавува фундаментален проблем: BIRD не сака да започне BGP peering со локалниот хост (или со кој било локален интерфејс). Од зборот воопшто. Гуглирањето и читањето мејлинг-листи не помогна, тие тврдат дека тоа е по дизајн. Можеби има некој начин, но не го најдов.

Можете да пробате друг BGP демон, но ми се допаѓа BIRD и се користи насекаде од мене, не сакам да произведувам ентитети.

Затоа, го скрив dnstap-bgp во мрежниот именски простор, кој е поврзан со коренот преку интерфејсот veth: тоа е како цевка, чии краеви се држат во различни именски простори. На секој од овие краеви, закачуваме приватни p2p IP адреси кои не одат подалеку од домаќинот, за да можат да бидат што било. Ова е истиот механизам што се користи за пристап до процесите внатре сакан од сите Докер и други контејнери.

За ова беше напишано скрипта и функционалноста веќе опишана погоре за влечење за коса во друг именски простор беше додадена во dnstap-bgp. Поради ова, мора да се изврши како root или да се издаде на бинарната CAP_SYS_ADMIN преку командата setcap.

Пример скрипта за создавање именски простор

#!/bin/bash

NS="dtap"

IP="/sbin/ip"
IPNS="$IP netns exec $NS $IP"

IF_R="veth-$NS-r"
IF_NS="veth-$NS-ns"

IP_R="192.168.149.1"
IP_NS="192.168.149.2"

/bin/systemctl stop dnstap-bgp || true

$IP netns del $NS > /dev/null 2>&1
$IP netns add $NS

$IP link add $IF_R type veth peer name $IF_NS
$IP link set $IF_NS netns $NS

$IP addr add $IP_R remote $IP_NS dev $IF_R
$IP link set $IF_R up

$IPNS addr add $IP_NS remote $IP_R dev $IF_NS
$IPNS link set $IF_NS up

/bin/systemctl start dnstap-bgp

dnstap-bgp.conf

namespace = "dtap"
domains = "/var/cache/rkn_domains.txt"
ttl = "168h"

[dnstap]
listen = "/tmp/dnstap.sock"
perm = "0666"

[bgp]
as = 65000
routerid = "192.168.149.2"

peers = [
    "192.168.149.1",
]

птица.conf

router id 192.168.1.1;

table rkn;

# Clients
protocol bgp bgp_client1 {
    table rkn;
    local as 65000;
    neighbor 192.168.1.2 as 65000;
    direct;
    bfd on;
    next hop self;
    graceful restart;
    graceful restart time 60;
    export all;
    import none;
}

# DNSTap-BGP
protocol bgp bgp_dnstap {
    table rkn;
    local as 65000;
    neighbor 192.168.149.2 as 65000;
    direct;
    passive on;
    rr client;
    import all;
    export none;
}

# Static routes list
protocol static static_rkn {
    table rkn;
    include "rkn_routes.list";
    import all;
    export none;
}

rkn_routes.list

route 3.226.79.85/32 via "ens3";
route 18.236.189.0/24 via "ens3";
route 3.224.21.0/24 via "ens3";
...

DNS

Стандардно, во Ubuntu, бинарниот Unbound е прицврстен од профилот AppArmor, што му забранува да се поврзе со сите видови DNSTap приклучоци. Можете или да го избришете овој профил или да го оневозможите:

# cd /etc/apparmor.d/disable && ln -s ../usr.sbin.unbound .
# apparmor_parser -R /etc/apparmor.d/usr.sbin.unbound

Ова веројатно треба да се додаде во книгата за игри. Идеално е, се разбира, да се поправи профилот и да се издадат потребните права, но бев премногу мрзлив.

неврзан.conf

server:
    chroot: ""
    port: 53
    interface: 0.0.0.0
    root-hints: "/var/lib/unbound/named.root"
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
    access-control: 192.168.0.0/16 allow

remote-control:
    control-enable: yes
    control-use-cert: no

dnstap:
    dnstap-enable: yes
    dnstap-socket-path: "/tmp/dnstap.sock"
    dnstap-send-identity: no
    dnstap-send-version: no

    dnstap-log-client-response-messages: yes

Преземање и обработка на листи

Скрипта за преземање и обработка на список со IP адреси
Ја презема листата, сумира до префиксот pfx. Во не_додавај и не_сумирај можете да им кажете на IP-адресите и мрежите да прескокнуваат или да не резимираат. ми требаше. подмрежата на мојот VPS беше во блок листата 🙂

Смешното е што RosKomSvoboda API блокира барања со стандардниот кориснички агент на Python. Изгледа дека сценариото го сфатило. Затоа, го менуваме во Огнелис.

Засега работи само со IPv4. уделот на IPv6 е мал, но ќе биде лесно да се поправи. Освен ако не мора да користите и птица6.

rkn.py

#!/usr/bin/python3

import json, urllib.request, ipaddress as ipa

url = 'https://api.reserve-rbl.ru/api/v2/ips/json'
pfx = '24'

dont_summarize = {
    # ipa.IPv4Network('1.1.1.0/24'),
}

dont_add = {
    # ipa.IPv4Address('1.1.1.1'),
}

req = urllib.request.Request(
    url,
    data=None, 
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
    }
)

f = urllib.request.urlopen(req)
ips = json.loads(f.read().decode('utf-8'))

prefix32 = ipa.IPv4Address('255.255.255.255')

r = {}
for i in ips:
    ip = ipa.ip_network(i)
    if not isinstance(ip, ipa.IPv4Network):
        continue

    addr = ip.network_address

    if addr in dont_add:
        continue

    m = ip.netmask
    if m != prefix32:
        r[m] = [addr, 1]
        continue

    sn = ipa.IPv4Network(str(addr) + '/' + pfx, strict=False)

    if sn in dont_summarize:
        tgt = addr
    else:
        tgt = sn

    if not sn in r:
        r[tgt] = [addr, 1]
    else:
        r[tgt][1] += 1

o = []
for n, v in r.items():
    if v[1] == 1:
        o.append(str(v[0]) + '/32')
    else:
        o.append(n)

for k in o:
    print(k)

Скрипта за ажурирање
Го пуштам на круната еднаш дневно, можеби вреди да се влече на секои 4 часа. ова, според мое мислење, е периодот на обновување што RKN го бара од давателите на услуги. Плус, тие имаат некое друго суперитно блокирање, кое може да стигне побрзо.

Го прави следново:

  • Ја извршува првата скрипта и ја ажурира листата на правци (rkn_routes.list) за ПТИЦА
  • Вчитај повторно BIRD
  • Ја ажурира и чисти листата на домени за dnstap-bgp
  • Вчитај повторно dnstap-bgp

rkn_update.sh

#!/bin/bash

ROUTES="/etc/bird/rkn_routes.list"
DOMAINS="/var/cache/rkn_domains.txt"

# Get & summarize routes
/opt/rkn.py | sed 's/(.*)/route 1 via "ens3";/' > $ROUTES.new

if [ $? -ne 0 ]; then
    rm -f $ROUTES.new
    echo "Unable to download RKN routes"
    exit 1
fi

if [ -e $ROUTES ]; then
    mv $ROUTES $ROUTES.old
fi

mv $ROUTES.new $ROUTES

/bin/systemctl try-reload-or-restart bird

# Get domains
curl -s https://api.reserve-rbl.ru/api/v2/domains/json -o - | jq -r '.[]' | sed 's/^*.//' | sort | uniq > $DOMAINS.new

if [ $? -ne 0 ]; then
    rm -f $DOMAINS.new
    echo "Unable to download RKN domains"
    exit 1
fi

if [ -e $DOMAINS ]; then
    mv $DOMAINS $DOMAINS.old
fi

mv $DOMAINS.new $DOMAINS

/bin/systemctl try-reload-or-restart dnstap-bgp

Тие се напишани без многу размислување, па ако видите нешто што може да се подобри - повелете.

Поставување на клиентот

Еве ќе дадам примери за Linux рутери, но во случајот со Mikrotik / Cisco би требало да биде уште полесно.

Прво, поставивме BIRD:

птица.conf

router id 192.168.1.2;
table rkn;

protocol device {
    scan time 10;
};

# Servers
protocol bgp bgp_server1 {
    table rkn;
    local as 65000;
    neighbor 192.168.1.1 as 65000;
    direct;
    bfd on;
    next hop self;
    graceful restart;
    graceful restart time 60;
    rr client;
    export none;
    import all;
}

protocol kernel {
    table rkn;
    kernel table 222;
    scan time 10;
    export all;
    import none;
}

Така, ќе ги синхронизираме маршрутите добиени од BGP со рутирачката табела на кернелот број 222.

После тоа, доволно е да побарате од јадрото да ја погледне оваа плоча пред да ја погледне стандардната:

# ip rule add from all pref 256 lookup 222
# ip rule
0:  from all lookup local
256:    from all lookup 222
32766:  from all lookup main
32767:  from all lookup default

Сè, останува да се конфигурира DHCP на рутерот за да се дистрибуира IP адресата на тунелот на серверот како DNS, а шемата е подготвена.

Ограничувања

Со сегашниот алгоритам за генерирање и обработка на листата на домени, меѓу другото вклучува и youtube.com и неговите ЦДН.

И ова води до фактот дека сите видеа ќе поминат преку VPN, што може да го заглави целиот канал. Можеби вреди да се состави список на популарни домени-исклучувања кои засега го блокираат RKN, храброста е тенка. И прескокнете ги при парсирање.

Заклучок

Опишаниот метод ви овозможува да го заобиколите речиси секое блокирање што моментално го спроведуваат провајдерите.

Во принцип, dnstap-bgp може да се користи за која било друга цел каде што е потребно одредено ниво на контрола на сообраќајот врз основа на името на доменот. Само имајте на ум дека во наше време, илјада страници можат да висат на иста IP адреса (зад некои Cloudflare, на пример), така што овој метод има прилично мала точност.

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

Дополнувања, уредувања, барања за повлекување - добредојде!

Извор: www.habr.com

Додадете коментар