Zaobiđite ILV blokiranje uz DNSTap i BGP

Zaobiđite ILV blokiranje uz DNSTap i BGP

Tema je prilično pretučena, znam. Na primjer, postoji sjajan članak, ali tamo se uzima u obzir samo IP dio liste blokiranih. Dodat ćemo i domene.

Zbog činjenice da sudovi i RKN blokiraju sve desno i lijevo, a pružatelji se jako trude ne potpasti pod kazne koje izdaje Revizorro, povezani gubici od blokiranja su prilično veliki. A među "zakonito" blokiranim stranicama ima mnogo korisnih (zdravo, rutracker)

Živim izvan nadležnosti RKN, ali moji roditelji, rodbina i prijatelji ostali su kod kuće. Stoga je odlučeno da se smisli jednostavan način za ljude koji su daleko od IT-a da zaobiđu blokiranje, po mogućnosti bez njihovog sudjelovanja uopće.

U ovoj bilješci neću opisivati ​​osnovne mrežne stvari u koracima, već ću opisati opća načela kako se ova shema može implementirati. Dakle, morate imati znanje o tome kako mreža funkcionira općenito, a posebno u Linuxu.

Vrste brava

Prvo, osvježimo sjećanje na ono što je blokirano.

Postoji nekoliko vrsta zaključavanja u neučitanom XML-u iz RKN-a:

  • IP
  • Naziv domene
  • URL

Radi jednostavnosti svešćemo ih na dva: IP i domenu, a domenu ćemo jednostavno izvući iz blokade po URL-u (točnije to su nam već napravili).

dobri ljudi iz Roskomsvoboda shvatio divan API, putem kojeg možemo dobiti ono što nam je potrebno:

Pristup blokiranim stranicama

Da bismo to učinili, trebamo neki mali strani VPS, po mogućnosti s neograničenim prometom - ima ih mnogo za 3-5 dolara. Morate ga uzeti u blisko inozemstvo tako da ping nije jako velik, ali opet, uzmite u obzir da se internet i zemljopis ne podudaraju uvijek. A budući da ne postoji SLA za 5 dolara, bolje je uzeti 2+ komada od različitih pružatelja usluga za toleranciju grešaka.

Zatim moramo postaviti šifrirani tunel od klijentskog usmjerivača do VPS-a. Koristim Wireguard kao najbrži i najlakši za postavljanje. Također imam klijentske usmjerivače temeljene na Linuxu (APU2 ili nešto u OpenWRT-u). U slučaju nekih Mikrotik / Cisco, možete koristiti protokole dostupne na njima kao što su OpenVPN i GRE-over-IPSEC.

Identifikacija i preusmjeravanje prometa od interesa

Možete, naravno, isključiti sav internet promet kroz inozemstvo. Ali najvjerojatnije će brzina rada s lokalnim sadržajem uvelike patiti od toga. Osim toga, zahtjevi za propusnost na VPS-u bit će puno veći.

Stoga ćemo morati nekako dodijeliti promet blokiranim stranicama i selektivno ga usmjeriti u tunel. Čak i ako nešto od "ekstra" prometa stigne tamo, to je još uvijek puno bolje nego voziti sve kroz tunel.

Za upravljanje prometom koristit ćemo BGP protokol i objavljivati ​​rute do potrebnih mreža od našeg VPS-a do klijenata. Uzmimo BIRD kao jedan od najfunkcionalnijih i najprikladnijih BGP demona.

IP

S blokiranjem po IP-u sve je jasno: jednostavno objavljujemo sve blokirane IP-ove s VPS-om. Problem je što se na listi koju vraća API nalazi oko 600 tisuća podmreža, a velika većina njih su /32 hostovi. Ovaj broj ruta može zbuniti slabe klijentske usmjerivače.

Stoga je prilikom obrade popisa odlučeno da se sumira do mreže /24 ako ima 2 ili više hostova. Time je broj ruta smanjen na ~100 tisuća. Slijedi scenarij za to.

Domene

To je kompliciranije i postoji nekoliko načina. Na primjer, možete instalirati prozirni Squid na svaki klijentski usmjerivač i tamo izvršiti presretanje HTTP-a i zaviriti u TLS rukovanje kako biste dobili traženi URL u prvom slučaju i domenu od SNI-ja u drugom.

Ali zbog svih vrsta novonastalih TLS1.3 + eSNI, HTTPS analiza svakim danom postaje sve manje stvarna. Da, i infrastruktura na strani klijenta postaje sve kompliciranija - morat ćete koristiti barem OpenWRT.

Stoga sam odlučio krenuti putem presretanja odgovora na DNS upite. I ovdje vam svaki DNS-over-TLS / HTTPS počinje lebdjeti iznad glave, ali možemo (za sada) kontrolirati ovaj dio na klijentu - ili ga onemogućite ili koristite vlastiti poslužitelj za DoT / DoH.

Kako presresti DNS?

I ovdje može postojati nekoliko pristupa.

  • Presretanje DNS prometa putem PCAP-a ili NFLOG-a
    Obje ove metode presretanja implementirane su u uslužnom programu sidmat. Ali dugo nije podržan i funkcionalnost je vrlo primitivna, tako da još uvijek trebate napisati pojas za njega.
  • Analiza zapisnika DNS poslužitelja
    Nažalost, meni poznati rekurzori ne mogu bilježiti odgovore, već samo zahtjeve. U principu, to je logično, jer za razliku od zahtjeva, odgovori imaju složenu strukturu i teško ih je napisati u tekstualnom obliku.
  • DNStap
    Srećom, mnogi od njih već podržavaju DNSTap za tu svrhu.

Što je DNSTap?

Zaobiđite ILV blokiranje uz DNSTap i BGP

To je protokol klijent-poslužitelj temeljen na međuspremnicima protokola i tokovima okvira za prijenos s DNS poslužitelja na kolektor strukturiranih DNS upita i odgovora. U osnovi, DNS poslužitelj prenosi metapodatke upita i odgovora (vrsta poruke, IP klijenta/poslužitelja itd.) plus kompletne DNS poruke u (binarnom) obliku u kojem radi s njima preko mreže.

Važno je razumjeti da u paradigmi DNSTap DNS poslužitelj djeluje kao klijent, a kolektor djeluje kao poslužitelj. Odnosno, DNS poslužitelj se povezuje s kolektorom, a ne obrnuto.

Danas je DNSTap podržan u svim popularnim DNS poslužiteljima. Ali, na primjer, BIND u mnogim distribucijama (kao što je Ubuntu LTS) često je izgrađen iz nekog razloga bez svoje podrške. Dakle, nemojmo se zamarati reasembliranjem, nego uzmimo lakši i brži rekurzor - Unbound.

Kako uhvatiti DNSTap?

Tu je neki broj CLI uslužni programi za rad s streamom DNSTap događaja, ali nisu prikladni za rješavanje našeg problema. Stoga sam odlučio izumiti vlastiti bicikl koji će raditi sve što je potrebno: dnstap-bgp

Algoritam rada:

  • Kada se pokrene, učitava popis domena iz tekstualne datoteke, preokreće ih (habr.com -> com.habr), isključuje isprekidane linije, duplikate i poddomene (tj. ako popis sadrži habr.com i www.habr.com, učitat će se samo prvi) i gradi stablo prefiksa za brzo pretraživanje kroz ovaj popis
  • Djelujući kao DNSTap poslužitelj, čeka vezu s DNS poslužitelja. U principu, podržava i UNIX i TCP utičnice, ali DNS poslužitelji koje ja poznajem mogu koristiti samo UNIX utičnice
  • Dolazni DNSTap paketi prvo se deserijaliziraju u Protobuf strukturu, a zatim se sama binarna DNS poruka, smještena u jednom od Protobuf polja, analizira na razinu DNS RR zapisa
  • Provjerava se je li traženi host (ili njegova roditeljska domena) na učitanoj listi, ako nije, odgovor se zanemaruje
  • Iz odgovora se biraju samo A/AAAA/CNAME RR-ovi i iz njih se izdvajaju odgovarajuće IPv4/IPv6 adrese
  • IP adrese se pohranjuju u predmemoriju s podesivim TTL-om i reklamiraju svim konfiguriranim BGP peerovima
  • Prilikom primanja odgovora koji upućuje na već predmemorirani IP, njegov TTL se ažurira
  • Nakon što TTL istekne, unos se uklanja iz predmemorije i iz BGP najava

Dodatne funkcije:

  • Ponovno čitanje popisa domena putem SIGHUP-a
  • Održavanje predmemorije u sinkronizaciji s drugim instancama dnstap-bgp putem HTTP/JSON
  • Duplicirajte predmemoriju na disku (u bazi podataka BoltDB) da vratite njezin sadržaj nakon ponovnog pokretanja
  • Podrška za prebacivanje na drugi mrežni imenski prostor (zašto je to potrebno bit će opisano u nastavku)
  • IPv6 podrška

ograničenja:

  • IDN domene još nisu podržane
  • Malo BGP postavki

skupljao sam RPM i DEB paketi za laku instalaciju. Trebalo bi raditi na svim relativno novijim operativnim sustavima sa systemd. nemaju nikakve ovisnosti.

Shema

Dakle, počnimo sastavljati sve komponente zajedno. Kao rezultat, trebali bismo dobiti nešto poput ove topologije mreže:
Zaobiđite ILV blokiranje uz DNSTap i BGP

Logika rada, mislim, jasna je iz dijagrama:

  • Klijent ima naš poslužitelj konfiguriran kao DNS, a DNS upiti također moraju ići preko VPN-a. Ovo je neophodno kako davatelj ne bi mogao koristiti presretanje DNS-a za blokiranje.
  • Prilikom otvaranja stranice, klijent šalje DNS upit poput "koji su IP-ovi xxx.org"
  • nevezan rješava xxx.org (ili ga uzima iz predmemorije) i šalje odgovor klijentu "xxx.org ima taj i takav IP", duplicirajući ga paralelno putem DNSTapa
  • dnstap-bgp objavljuje ove adrese u PTICA putem BGP-a ako je domena na popisu blokiranih
  • PTICA oglašava rutu do ovih IP-ova s next-hop self klijent usmjerivač
  • Sljedeći paketi od klijenta do tih IP-ova prolaze kroz tunel

Na poslužitelju, za rute do blokiranih stranica, koristim zasebnu tablicu unutar BIRD-a i ona se ni na koji način ne presijeca s OS-om.

U ovoj shemi postoji nedostatak: prvi SYN paket od klijenta najvjerojatnije će imati vremena otići preko domaćeg davatelja usluga. ruta se ne objavljuje odmah. I ovdje su moguće opcije ovisno o tome kako pružatelj blokira. Ako samo smanji promet, onda nema problema. A ako ga preusmjeri na neki DPI, onda su (teoretski) mogući specijalni efekti.

Također je moguće da klijenti ne poštuju DNS TTL čuda, što može uzrokovati da klijent koristi neke ustajale unose iz svoje pokvarene predmemorije umjesto da traži Unbound.

U praksi, niti prvo niti drugo mi nije stvaralo probleme, ali vaša kilometraža može varirati.

Podešavanje poslužitelja

Radi lakšeg motanja, napisao sam ulogu za Ansible. Može konfigurirati i poslužitelje i klijente temeljene na Linuxu (dizajniran za distribucije temeljene na deb). Sve postavke su sasvim očite i postavljene inventar.yml. Ova je uloga izrezana iz mog velikog priručnika pa može sadržavati pogreške - povuci zahtjeve dobrodošli 🙂

Prođimo kroz glavne komponente.

BGA

Kada se izvode dva BGP demona na istom hostu, pojavljuje se temeljni problem: BIRD ne želi pokrenuti BGP peering s lokalnim hostom (ili s bilo kojim lokalnim sučeljem). Od riječi uopće. Guglanje i čitanje mailing lista nije pomoglo, tvrde da je to smišljeno. Možda postoji neki način, ali ja ga nisam našao.

Možete pokušati s drugim BGP demonom, ali ja volim BIRD i svugdje ga koristim, ne želim proizvoditi entitete.

Stoga sam sakrio dnstap-bgp unutar mrežnog imenskog prostora, koji je povezan s korijenom preko veth sučelja: to je poput cijevi čiji krajevi strše u različitim imenskim prostorima. Na svaki od ovih krajeva objesimo privatne p2p IP adrese koje ne idu dalje od hosta, tako da mogu biti bilo što. Ovo je isti mehanizam koji se koristi za pristup procesima unutar voljen od svih Docker i drugi kontejneri.

Za ovo je napisano skripta i gore opisana funkcionalnost za povlačenje za kosu u drugi prostor imena je dodana u dnstap-bgp. Zbog toga se mora pokrenuti kao root ili izdati binarnom CAP_SYS_ADMIN putem naredbe setcap.

Primjer skripte za stvaranje imenskog prostora

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

ptica.konf

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

Prema zadanim postavkama, u Ubuntuu, Unbound binary je stegnut AppArmor profilom, koji mu zabranjuje povezivanje sa svim vrstama DNSTap utičnica. Možete izbrisati ovaj profil ili ga onemogućiti:

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

Ovo bi vjerojatno trebalo dodati u priručnik. Idealno je, naravno, ispraviti profil i izdati potrebna prava, ali bio sam previše lijen.

nevezano.konf

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

Preuzimanje i obrada popisa

Skripta za preuzimanje i obradu popisa IP adresa
Preuzima popis, zbraja do prefiksa pfx. U ne_dodaj и ne_sažimaj možete reći IP-ovima i mrežama da preskoče ili ne sumiraju. Trebalo mi je. podmreža mog VPS-a bila je na listi blokiranih 🙂

Smiješno je to što RosKomSvoboda API blokira zahtjeve sa zadanim Python korisničkim agentom. Čini se da je scenarij-kiddy shvatio. Stoga ga mijenjamo u Ognelis.

Za sada radi samo s IPv4. udio IPv6 je mali, ali će se to lako popraviti. Osim ako ne morate koristiti i 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)

Skripta za ažuriranje
Vodim ga na krunu jednom dnevno, možda je vrijedno povlačenja svaka 4 sata. ovo je, po mom mišljenju, razdoblje obnove koje RKN zahtijeva od pružatelja usluga. Plus, imaju neke druge super-hitne blokade, koje mogu stići brže.

Radi sljedeće:

  • Pokreće prvu skriptu i ažurira popis ruta (rkn_routes.list) za PTICU
  • Ponovno učitaj BIRD
  • Ažurira i čisti popis domena za dnstap-bgp
  • Ponovno učitaj 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

Napisane su bez puno razmišljanja, pa ako vidite nešto što se može poboljšati, krenite.

Postavljanje klijenta

Ovdje ću dati primjere za Linux rutere, ali u slučaju Mikrotik / Cisco to bi trebalo biti još lakše.

Prvo smo postavili BIRD:

ptica.konf

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;
}

Stoga ćemo sinkronizirati rute primljene od BGP-a s tablicom usmjeravanja jezgre broj 222.

Nakon toga, dovoljno je zatražiti od kernela da pogleda ovu ploču prije nego što pogleda zadanu:

# 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

Sve, ostaje konfigurirati DHCP na usmjerivaču da distribuira IP adresu tunela poslužitelja kao DNS i shema je spremna.

Ograničenja

Uz trenutni algoritam za generiranje i obradu popisa domena, on između ostalog uključuje youtube.com i njegove CDN-ove.

A to dovodi do činjenice da će svi videozapisi ići kroz VPN, što može začepiti cijeli kanal. Možda je vrijedno sastaviti popis popularnih domena-isključenja koja blokiraju RKN za sada, crijeva su tanka. I preskočite ih prilikom raščlanjivanja.

Zaključak

Opisana metoda omogućuje vam zaobilaženje gotovo svih blokada koje davatelji trenutno provode.

U načelu, dnstap-bgp može se koristiti za bilo koju drugu svrhu gdje je potrebna određena razina kontrole prometa na temelju naziva domene. Samo imajte na umu da u naše vrijeme tisuću stranica može visjeti na istoj IP adresi (na primjer, iza nekog Cloudflarea), tako da ova metoda ima prilično nisku točnost.

Ali za potrebe zaobilaženja brava i ovo je sasvim dovoljno.

Dodaci, izmjene, zahtjevi za povlačenjem - dobrodošli!

Izvor: www.habr.com

Dodajte komentar