Obíďte blokovanie ILV pomocou DNSTap a BGP

Obíďte blokovanie ILV pomocou DNSTap a BGP

Téma je dosť prebitá, ja viem. Napríklad je tu skvelý článok, ale berie sa do úvahy iba časť IP zo zoznamu blokovaných adries. Pridáme aj domény.

Vzhľadom na to, že súdy a RKN blokujú všetko napravo aj naľavo a poskytovatelia sa usilovne snažia nespadnúť pod pokuty, ktoré udeľuje Revizorro, sú s tým spojené straty z blokovania pomerne veľké. A medzi „zákonne“ zablokovanými stránkami je veľa užitočných (ahoj, rutracker)

Žijem mimo jurisdikcie RKN, ale moji rodičia, príbuzní a priatelia zostali doma. Preto bolo rozhodnuté vymyslieť jednoduchý spôsob, ako obísť blokovanie pre ľudí ďaleko od IT, najlepšie bez ich účasti.

V tejto poznámke nebudem popisovať základné sieťové veci v krokoch, ale popíšem všeobecné princípy, ako je možné túto schému implementovať. Znalosť fungovania siete vo všeobecnosti a konkrétne v Linuxe je teda nevyhnutnosťou.

Typy zámkov

Najprv si osviežme pamäť toho, čo je blokované.

V uvoľnenom XML z RKN existuje niekoľko typov zámkov:

  • IP
  • Домен
  • URL

Pre jednoduchosť ich zredukujeme na dve: IP a doménu a doménu jednoducho vytiahneme z blokovania podľa URL (presnejšie to už urobili za nás).

dobrí ľudia z Roskomsvoboda uvedomil si úžasné API, prostredníctvom ktorého môžeme získať to, čo potrebujeme:

Prístup k blokovaným stránkam

Na to potrebujeme nejaké malé zahraničné VPS, najlepšie s neobmedzenou návštevnosťou – tých je veľa za 3-5 dolárov. Treba si to zobrať v blízkom zahraničí, aby ping nebol veľmi veľký, ale opäť počítajte s tým, že internet a geografia sa nie vždy zhodujú. A keďže neexistuje žiadna zmluva SLA za 5 dolárov, je lepšie vziať si 2+ kusy od rôznych poskytovateľov na odolnosť voči chybám.

Ďalej musíme nastaviť šifrovaný tunel z klientskeho smerovača do VPS. Wireguard používam ako najrýchlejšie a najjednoduchšie na nastavenie. Mám tiež klientske smerovače založené na Linuxe (APU2 alebo niečo v OpenWRT). V prípade niektorých Mikrotik / Cisco môžete použiť protokoly, ktoré sú na nich dostupné, ako OpenVPN a GRE-over-IPSEC.

Identifikácia a presmerovanie návštevnosti záujmu

Môžete samozrejme vypnúť všetok internetový prenos cez cudzie krajiny. S najväčšou pravdepodobnosťou tým však značne utrpí rýchlosť práce s miestnym obsahom. Navyše, požiadavky na šírku pásma na VPS budú oveľa vyššie.

Preto budeme musieť nejakým spôsobom prideliť návštevnosť zablokovaným stránkam a selektívne ju nasmerovať do tunela. Aj keď sa tam dostane nejaká tá „extra“ premávka, stále je to oveľa lepšie, ako jazdiť všetko cez tunel.

Na riadenie prevádzky využijeme protokol BGP a klientom oznámime trasy do potrebných sietí z našich VPS. Zoberme si BIRD ako jeden z najfunkčnejších a najpohodlnejších BGP démonov.

IP

S blokovaním IP je všetko jasné: všetky blokované IP jednoducho oznamujeme pomocou VPS. Problém je, že v zozname, ktorý API vracia, je asi 600 tisíc podsietí a drvivá väčšina z nich je /32 hostiteľov. Tento počet trás môže zmiasť slabé klientske smerovače.

Preto sa pri spracovaní zoznamu rozhodlo zhrnúť až do siete / 24 ak má 2 alebo viac hostiteľov. Počet trás sa tak znížil na ~100 tisíc. Scenár na to bude nasledovať.

domény

Je to zložitejšie a existuje viacero spôsobov. Môžete napríklad nainštalovať transparentný Squid na každý klientsky smerovač a vykonať tam zachytávanie HTTP a nahliadnuť do TLS handshake, aby ste získali požadovanú URL v prvom prípade a doménu od SNI v druhom prípade.

Ale kvôli všetkým druhom nového TLS1.3 + eSNI je analýza HTTPS každým dňom menej a menej realistická. Áno, a infraštruktúra na strane klienta sa komplikuje - budete musieť použiť aspoň OpenWRT.

Preto som sa rozhodol ísť cestou zachytávania odpovedí na DNS požiadavky. Aj tu sa vám nad hlavou začne vznášať akýkoľvek DNS-over-TLS / HTTPS, ale túto časť môžeme (zatiaľ) ovládať na klientovi – buď ju deaktivovať, alebo použiť vlastný server na DoT/DoH.

Ako zachytiť DNS?

Aj tu môže existovať niekoľko prístupov.

  • Zachytávanie prevádzky DNS cez PCAP alebo NFLOG
    Oba tieto spôsoby odpočúvania sú implementované v obslužnom programe sidmat. Ale to už dávno nie je podporované a funkčnosť je veľmi primitívna, takže si na to musíte ešte napísať postroj.
  • Analýza protokolov servera DNS
    Bohužiaľ, mne známi rekurzori nie sú schopní zaznamenávať odpovede, ale iba požiadavky. V zásade je to logické, keďže na rozdiel od požiadaviek majú odpovede zložitú štruktúru a je ťažké ich napísať v textovej forme.
  • DNSTap
    Našťastie mnohé z nich už na tento účel podporujú DNSTap.

Čo je DNSTap?

Obíďte blokovanie ILV pomocou DNSTap a BGP

Ide o protokol klient-server založený na vyrovnávacích pamätiach protokolov a tokoch rámcov na prenos zo servera DNS do zberača štruktúrovaných DNS dotazov a odpovedí. DNS server v podstate prenáša metadáta dotazu a odpovede (typ správy, IP klient/server atď.) plus kompletné DNS správy v (binárnej) forme, v akej s nimi pracuje cez sieť.

Je dôležité pochopiť, že v paradigme DNSTap server DNS vystupuje ako klient a kolektor funguje ako server. To znamená, že server DNS sa pripája ku kolektoru a nie naopak.

Dnes je DNSTap podporovaný na všetkých populárnych serveroch DNS. Ale napríklad BIND v mnohých distribúciách (ako Ubuntu LTS) je často vytvorený z nejakého dôvodu bez jeho podpory. Netrápme sa teda opätovným zložením, ale zoberme si ľahší a rýchlejší rekurzor – Unbound.

Ako chytiť DNSTap?

K dispozícii je niektoré číslo Pomôcky CLI na prácu s prúdom udalostí DNSTap, ale nie sú vhodné na riešenie nášho problému. Preto som sa rozhodol vymyslieť svoj vlastný bicykel, ktorý bude robiť všetko, čo je potrebné: dnstap-bgp

Pracovný algoritmus:

  • Po spustení načíta zoznam domén z textového súboru, invertuje ich (habr.com -> com.habr), vylúči prerušované riadky, duplikáty a subdomény (t. j. ak zoznam obsahuje habr.com a www.habr.com, načíta sa iba prvý) a vytvorí strom prefixov na rýchle vyhľadávanie v tomto zozname
  • Funguje ako server DNSTap a čaká na pripojenie zo servera DNS. V zásade podporuje sokety UNIX aj TCP, ale servery DNS, ktoré poznám, môžu používať iba sokety UNIX
  • Prichádzajúce pakety DNSTap sa najskôr deserializujú do štruktúry Protobuf a potom sa samotná binárna správa DNS, ktorá sa nachádza v jednom z polí Protobuf, analyzuje na úroveň záznamov DNS RR.
  • Skontroluje sa, či je požadovaný hostiteľ (alebo jeho nadradená doména) v načítanom zozname, ak nie, odpoveď sa ignoruje
  • Z odpovede sa vyberú iba RR A/AAAA/CNAME a z nich sa extrahujú zodpovedajúce adresy IPv4/IPv6
  • IP adresy sa ukladajú do vyrovnávacej pamäte s konfigurovateľným TTL a propagujú sa všetkým nakonfigurovaným partnerom BGP
  • Pri prijatí odpovede, ktorá ukazuje na už uloženú IP adresu, sa aktualizuje jej TTL
  • Po uplynutí platnosti TTL sa záznam odstráni z vyrovnávacej pamäte a z oznámení BGP

Ďalšie funkcie:

  • Opätovné čítanie zoznamu domén od SIGHUP
  • Udržiavanie vyrovnávacej pamäte v synchronizácii s ostatnými inštanciami dnstap-bgp cez HTTP/JSON
  • Duplikujte vyrovnávaciu pamäť na disku (v databáze BoltDB), aby ste po reštarte obnovili jej obsah
  • Podpora prepínania na iný sieťový menný priestor (prečo je to potrebné bude popísané nižšie)
  • podpora IPv6

obmedzenia:

  • Domény IDN zatiaľ nie sú podporované
  • Málo nastavení BGP

zbieral som RPM a DEB balíčky pre jednoduchú inštaláciu. Mal by fungovať na všetkých relatívne najnovších operačných systémoch so systemd. nemajú žiadne závislosti.

Schéma

Začnime teda montovať všetky komponenty dohromady. V dôsledku toho by sme mali dostať niečo ako táto topológia siete:
Obíďte blokovanie ILV pomocou DNSTap a BGP

Myslím si, že logika práce je jasná z diagramu:

  • Klient má náš server nakonfigurovaný ako DNS a DNS dotazy musia ísť aj cez VPN. Je to potrebné, aby poskytovateľ nemohol použiť odpočúvanie DNS na blokovanie.
  • Pri otvorení stránky klient odošle DNS dotaz ako „aké sú IP adresy xxx.org“
  • neviazaný rozpozná xxx.org (alebo ho vezme z vyrovnávacej pamäte) a odošle klientovi odpoveď „xxx.org má takú a takú IP“, pričom ju paralelne duplikuje cez DNSTap
  • dnstap-bgp oznamuje tieto adresy v BIRD cez BGP, ak je doména na zozname blokovaných
  • BIRD inzeruje cestu k týmto IP adresám s next-hop self klientsky smerovač
  • Nasledujúce pakety od klienta k týmto IP adresám prechádzajú tunelom

Na serveri pre trasy na blokované stránky používam samostatnú tabuľku vnútri BIRD a nijako sa neprelína s OS.

Táto schéma má nevýhodu: prvý paket SYN od klienta bude mať s najväčšou pravdepodobnosťou čas odísť cez domáceho poskytovateľa. trasa nie je oznámená okamžite. A tu sú možné možnosti v závislosti od toho, ako poskytovateľ blokuje. Ak len zníži premávku, potom nie je problém. A ak to presmeruje na nejaké DPI, tak sú možné (teoreticky) špeciálne efekty.

Je tiež možné, že klienti nerešpektujú DNS TTL zázraky, čo môže spôsobiť, že klient použije niektoré zastaralé položky zo svojej prehnitej vyrovnávacej pamäte namiesto toho, aby požiadal o Unbound.

V praxi mi prvé ani druhé nespôsobili problémy, no váš počet najazdených kilometrov sa môže líšiť.

Ladenie servera

Pre uľahčenie rolovania som napísal úlohu pre Ansible. Dokáže konfigurovať servery aj klientov na báze Linuxu (určené pre distribúcie založené na deb). Všetky nastavenia sú celkom zrejmé a sú zadané inventár.yml. Táto rola je vystrihnutá z mojej veľkej príručky, takže môže obsahovať chyby - požiadavky vitajte 🙂

Poďme si prejsť hlavné komponenty.

bgp

Spustenie dvoch BGP démonov na tom istom hostiteľovi má zásadný problém: BIRD nechce nastaviť BGP peering s localhostom (alebo akýmkoľvek lokálnym rozhraním). Zo slova vôbec. Google a čítanie mailinglistov nepomohlo, tvrdia, že je to zámerné. Možno existuje nejaký spôsob, ale nenašiel som ho.

Môžete vyskúšať iného démona BGP, ale páči sa mi BIRD a používam ho všade, nechcem vytvárať entity.

Preto som skryl dnstap-bgp do sieťového menného priestoru, ktorý je pripojený ku koreňu cez rozhranie veth: je to ako rúrka, ktorej konce trčia v rôznych menných priestoroch. Na každom z týchto koncov zavesíme súkromné ​​p2p IP adresy, ktoré nepresahujú hostiteľa, takže to môže byť čokoľvek. Ide o rovnaký mechanizmus, ktorý sa používa na prístup k procesom vo vnútri všetkými milovaný Docker a iné kontajnery.

Pre toto to bolo napísané skript a do dnstap-bgp bola pridaná už vyššie popísaná funkcionalita na pretiahnutie sa za vlasy do iného menného priestoru. Z tohto dôvodu musí byť spustený ako root alebo vydaný do binárneho súboru CAP_SYS_ADMIN pomocou príkazu setcap.

Príklad skriptu na vytvorenie priestoru názvov

#!/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",
]

vták.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

V predvolenom nastavení je v Ubuntu binárny súbor Unbound upnutý profilom AppArmor, ktorý mu zakazuje pripojenie ku všetkým druhom zásuviek DNSTap. Tento profil môžete buď odstrániť, alebo ho zakázať:

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

Toto by sa asi malo pridať do playbooku. Ideálne je samozrejme opraviť profil a vydať potrebné práva, ale bol som príliš lenivý.

neviazaný.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

Sťahovanie a spracovanie zoznamov

Skript na stiahnutie a spracovanie zoznamu IP adries
Stiahne zoznam, sčíta sa až po predponu pfx. V dont_add и nezosumarizuj IP a siete môžete preskočiť alebo nezosumarizovať. Potreboval som to. subnet mojho VPS bol v blockliste 🙂

Vtipné je, že API RosKomSvoboda blokuje požiadavky pomocou predvoleného používateľského agenta Pythonu. Zdá sa, že scenárista to pochopil. Preto ho meníme na Ognelis.

Zatiaľ to funguje len s IPv4. podiel IPv6 je malý, ale bude ľahké ho opraviť. Pokiaľ nemusíte používať aj bird6.

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)

Skript na aktualizáciu
Spustím ho na korunu raz denne, možno stojí za to ho ťahať každé 4 hodiny. toto je podľa mňa doba obnovy, ktorú RKN vyžaduje od poskytovateľov. Navyše majú nejaké ďalšie supernaliehavé blokovanie, ktoré môže prísť rýchlejšie.

Robí nasledovné:

  • Spustí prvý skript a aktualizuje zoznam trás (rkn_routes.list) pre BIRD
  • Znovu načítať BIRD
  • Aktualizuje a vyčistí zoznam domén pre dnstap-bgp
  • Znova načítať 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

Boli napísané bez veľkého premýšľania, takže ak vidíte niečo, čo by sa dalo zlepšiť, choďte do toho.

Nastavenie klienta

Tu uvediem príklady pre linuxové smerovače, ale v prípade Mikrotik / Cisco by to malo byť ešte jednoduchšie.

Najprv nastavíme BIRD:

vták.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;
}

Budeme teda synchronizovať cesty prijaté z BGP so smerovacou tabuľkou jadra číslo 222.

Potom už stačí požiadať jadro, aby sa pozrelo na túto platňu predtým, než sa pozrie na predvolenú platňu:

# 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

Všetko, zostáva nakonfigurovať DHCP na smerovači na distribúciu adresy IP tunela servera ako DNS a schéma je pripravená.

Obmedzenie

So súčasným algoritmom na generovanie a spracovanie zoznamu domén zahŕňa okrem iného napr. youtube.com a jeho CDN.

A to vedie k tomu, že všetky videá prejdú cez VPN, čo môže upchať celý kanál. Možno stojí za to zostaviť zoznam populárnych domén-vylúčení, ktoré zatiaľ blokujú RKN, črevá sú tenké. A pri analýze ich preskočte.

Záver

Opísaná metóda vám umožňuje obísť takmer akékoľvek blokovanie, ktoré poskytovatelia v súčasnosti implementujú.

V zásade dnstap-bgp možno použiť na akýkoľvek iný účel, kde je potrebná určitá úroveň riadenia prevádzky na základe názvu domény. Majte na pamäti, že v našej dobe môže na rovnakej IP adrese visieť tisíc stránok (napríklad za niektorými Cloudflare), takže táto metóda má dosť nízku presnosť.

Ale pre potreby obchádzania zámkov to úplne stačí.

Doplnenia, úpravy, požiadavky na stiahnutie - vitajte!

Zdroj: hab.com

Pridať komentár