Preskočite blokiranje ILV z DNSTap in BGP

Preskočite blokiranje ILV z DNSTap in BGP

Vem, da je tema precej nabita. Na primer, obstaja odličen članek, vendar se tam upošteva samo IP del seznama blokiranih. Dodali bomo tudi domene.

Ker sodišča in RKN blokirajo vse desno in levo, ponudniki pa se močno trudijo, da ne bi padli pod kazni, ki jih izda Revizorro, so povezane izgube zaradi blokade precej velike. In med "zakonito" blokiranimi spletnimi mesti je veliko uporabnih (zdravo, rutracker)

Živim izven pristojnosti RKN, doma pa so ostali starši, sorodniki in prijatelji. Zato je bilo odločeno, da se najde preprost način za ljudi, ki so daleč od IT, da zaobidejo blokado, po možnosti brez njihovega sodelovanja.

V tej opombi ne bom opisal osnovnih omrežnih stvari po korakih, ampak bom opisal splošna načela, kako je mogoče to shemo izvajati. Zato morate imeti znanje o delovanju omrežja na splošno in še posebej v Linuxu.

Vrste ključavnic

Najprej si osvežimo spomin, kaj je blokirano.

Obstaja več vrst ključavnic v nenaloženem XML-ju iz RKN:

  • IP
  • Ime domene
  • URL

Zaradi poenostavitve jih bomo zmanjšali na dva: IP in domeno, domeno pa bomo preprosto umaknili iz blokade po URL-ju (natančneje, to so nam že storili).

dobri ljudje iz Roskomsvoboda spoznal čudovito API, prek katerega lahko dobimo, kar potrebujemo:

Dostop do blokiranih spletnih mest

Za to potrebujemo kakšen manjši tuji VPS, po možnosti z neomejenim prometom - teh je veliko za 3-5 dolarjev. Vzeti ga morate v bližnjo tujino, da ping ni zelo velik, vendar spet upoštevajte, da internet in geografija ne sovpadata vedno. In ker ni SLA za 5 dolarjev, je za toleranco napak bolje vzeti 2+ kosa od različnih ponudnikov.

Nato moramo nastaviti šifriran tunel od odjemalskega usmerjevalnika do VPS. Uporabljam Wireguard kot najhitrejšo in najpreprostejšo nastavitev. Imam tudi odjemalske usmerjevalnike, ki temeljijo na Linuxu (APU2 ali nekaj v OpenWRT). V primeru nekaterih Mikrotik / Cisco lahko uporabite protokole, ki so na voljo pri njih, kot sta OpenVPN in GRE-over-IPSEC.

Identifikacija in preusmeritev prometa, ki vas zanima

Lahko pa seveda izklopite ves internetni promet preko tujine. Toda najverjetneje bo hitrost dela z lokalno vsebino zaradi tega močno prizadeta. Poleg tega bodo zahteve glede pasovne širine na VPS veliko višje.

Zato bomo morali nekako dodeliti promet blokiranim mestom in ga selektivno usmeriti v tunel. Tudi če nekaj "odvečnega" prometa pride tja, je še vedno veliko bolje, kot da bi vse vozili skozi tunel.

Za upravljanje prometa bomo uporabljali protokol BGP in strankam napovedovali poti do potrebnih omrežij iz našega VPS. Vzemimo BIRD kot enega najbolj funkcionalnih in priročnih demonov BGP.

IP

Z blokiranjem po IP je vse jasno: vse blokirane IP preprosto objavimo z VPS. Težava je v tem, da je na seznamu, ki ga vrne API, približno 600 tisoč podomrežij, velika večina med njimi pa so gostitelji /32. To število poti lahko zmede šibke odjemalske usmerjevalnike.

Zato je bilo pri obdelavi seznama odločeno, da se povzame do omrežja / 24, če ima 2 ali več gostiteljev. Tako se je število poti zmanjšalo na ~100 tisoč. Scenarij za to bo sledil.

domene

Je bolj zapleteno in obstaja več načinov. Na primer, lahko namestite pregleden Squid na vsak odjemalski usmerjevalnik in tam izvedete prestrezanje HTTP ter pokukate v rokovanje TLS, da pridobite zahtevani URL v prvem primeru in domeno od SNI v drugem.

Toda zaradi vseh vrst novodobnih TLS1.3 + eSNI postaja analiza HTTPS vsak dan manj resnična. Da, in infrastruktura na strani odjemalca postaja vse bolj zapletena - uporabiti boste morali vsaj OpenWRT.

Zato sem se odločil ubrati pot prestrezanja odgovorov na poizvedbe DNS. Tudi tukaj vam začne vsakršen DNS-over-TLS / HTTPS lebdeti nad glavo, vendar lahko ta del (zaenkrat) nadzorujemo na odjemalcu - ali ga onemogočimo ali uporabimo svoj strežnik za DoT / DoH.

Kako prestreči DNS?

Tudi tu je lahko več pristopov.

  • Prestrezanje prometa DNS prek PCAP ali NFLOG
    Oba načina prestrezanja sta implementirana v pripomoček sidmat. Vendar že dolgo ni bil podprt in funkcionalnost je zelo primitivna, zato morate še vedno napisati pas zanj.
  • Analiza dnevnikov strežnika DNS
    Na žalost meni znani rekurzorji ne morejo beležiti odgovorov, ampak samo zahteve. Načeloma je to logično, saj imajo odgovori za razliko od prošenj kompleksno strukturo in jih je težko napisati v besedilni obliki.
  • DNStap
    Na srečo mnogi od njih že podpirajo DNSTap za ta namen.

Kaj je DNSTap?

Preskočite blokiranje ILV z DNSTap in BGP

To je protokol odjemalec-strežnik, ki temelji na medpomnilnikih protokolov in tokovih okvirjev za prenos iz strežnika DNS v zbiralnik strukturiranih poizvedb in odgovorov DNS. Strežnik DNS v bistvu prenaša metapodatke o poizvedbi in odgovoru (vrsto sporočila, IP odjemalca/strežnika itd.) ter celotna sporočila DNS v (binarni) obliki, v kateri z njimi deluje prek omrežja.

Pomembno je razumeti, da v paradigmi DNSTap strežnik DNS deluje kot odjemalec, zbiralnik pa kot strežnik. To pomeni, da se strežnik DNS poveže z zbiralnikom in ne obratno.

Danes je DNSTap podprt v vseh priljubljenih strežnikih DNS. Toda na primer BIND v številnih distribucijah (kot je Ubuntu LTS) je pogosto zgrajen iz nekega razloga brez njegove podpore. Zato se ne ubadajmo s ponovnim sestavljanjem, ampak vzemimo lažji in hitrejši rekurzor - Unbound.

Kako ujeti DNSTap?

Obstaja nekaj število Pripomočki CLI za delo s tokom dogodkov DNSTap, vendar niso primerni za rešitev našega problema. Zato sem se odločil izumiti svoje kolo, ki bo naredilo vse, kar je potrebno: dnstap-bgp

Algoritem dela:

  • Ko se zažene, naloži seznam domen iz besedilne datoteke, jih obrne (habr.com -> com.habr), izključi prekinjene črte, dvojnike in poddomene (tj. če seznam vsebuje habr.com in www.habr.com, naložen bo le prvi) in zgradi drevo predpon za hitro iskanje po tem seznamu
  • Deluje kot strežnik DNSTap in čaka na povezavo s strežnikom DNS. Načeloma podpira vtičnice UNIX in TCP, vendar DNS strežniki, ki jih poznam, lahko uporabljajo samo vtičnice UNIX
  • Dohodni paketi DNSTap se najprej deserializirajo v strukturo Protobuf, nato pa se samo binarno sporočilo DNS, ki se nahaja v enem od polj Protobuf, razčleni na raven zapisov DNS RR
  • Preveri se, ali je zahtevani gostitelj (ali njegova nadrejena domena) na naloženem seznamu, če ni, se odgovor prezre
  • Iz odgovora so izbrani samo RR-ji A/AAAA/CNAME in iz njih so ekstrahirani ustrezni naslovi IPv4/IPv6
  • Naslovi IP so predpomnjeni z nastavljivim TTL in oglaševani vsem konfiguriranim vrstnikom BGP
  • Ko prejmete odgovor, ki kaže na že predpomnjen IP, se njegov TTL posodobi
  • Ko TTL poteče, se vnos odstrani iz predpomnilnika in iz obvestil BGP

Dodatne funkcije:

  • Ponovno branje seznama domen s SIGHUP
  • Ohranjanje sinhronizacije predpomnilnika z drugimi primerki dnstap-bgp prek HTTP/JSON
  • Podvojite predpomnilnik na disku (v bazi podatkov BoltDB), da obnovite njegovo vsebino po ponovnem zagonu
  • Podpora za preklop na drug omrežni imenski prostor (zakaj je to potrebno, bo opisano spodaj)
  • Podpora za IPv6

Omejitve:

  • IDN domene še niso podprte
  • Nekaj ​​nastavitev BGP

Zbral sem RPM in DEB paketi za enostavno namestitev. Delovati bi moralo na vseh relativno novejših operacijskih sistemih s systemd. nimajo nobenih odvisnosti.

Shema

Torej, začnimo sestavljati vse komponente skupaj. Kot rezultat bi morali dobiti nekaj podobnega tej topologiji omrežja:
Preskočite blokiranje ILV z DNSTap in BGP

Mislim, da je logika dela jasna iz diagrama:

  • Odjemalec ima naš strežnik konfiguriran kot DNS, poizvedbe DNS pa morajo iti tudi preko VPN-ja. To je potrebno, da ponudnik ne more uporabiti prestrezanja DNS za blokiranje.
  • Ko odpre spletno mesto, odjemalec pošlje poizvedbo DNS, kot je "kakšni so IP-ji xxx.org"
  • Brez obvez razreši xxx.org (ali ga vzame iz predpomnilnika) in odjemalcu pošlje odgovor "xxx.org ima tak in tak IP", ki ga vzporedno podvoji prek DNSTap
  • dnstap-bgp objavlja te naslove v BIRD prek BGP, če je domena na seznamu blokiranih
  • BIRD oglašuje pot do teh IP-jev z next-hop self odjemalski usmerjevalnik
  • Naslednji paketi od odjemalca do teh IP-jev gredo skozi tunel

Na strežniku za poti do blokiranih spletnih mest uporabljam ločeno tabelo znotraj BIRD-a in se na noben način ne križa z OS.

Ta shema ima pomanjkljivost: prvi paket SYN od odjemalca bo najverjetneje imel čas, da zapusti domačega ponudnika. trase ne objavijo takoj. In tukaj so možne možnosti, odvisno od tega, kako ponudnik izvaja blokado. Če le zmanjša promet, potem ni problema. In če ga preusmeri na nek DPI, potem so (teoretično) možni posebni učinki.

Možno je tudi, da odjemalci ne upoštevajo čudežev DNS TTL, kar lahko povzroči, da odjemalec uporabi nekaj zastarelih vnosov iz svojega pokvarjenega predpomnilnika, namesto da bi vprašal Unbound.

V praksi mi ne prvo ne drugo ni povzročalo težav, lahko pa se vaša kilometrina razlikuje.

Nastavitev strežnika

Za lažje valjanje sem napisal vlogo za Ansible. Lahko konfigurira tako strežnike kot odjemalce, ki temeljijo na Linuxu (zasnovan za distribucije, ki temeljijo na deb). Vse nastavitve so povsem očitne in nastavljene popis.yml. Ta vloga je izrezana iz mojega velikega priročnika, zato lahko vsebuje napake - povleci zahteve dobrodošli 🙂

Pojdimo skozi glavne komponente.

bgp

Izvajanje dveh demonov BGP na istem gostitelju ima temeljno težavo: BIRD ne želi vzpostaviti enakovrednega BGP z lokalnim gostiteljem (ali katerim koli lokalnim vmesnikom). Sploh od besede. Googlanje in branje poštnih seznamov ni pomagalo, trdijo, da je to načrtno. Mogoče obstaja kakšen način, vendar ga nisem našel.

Lahko poskusite z drugim demonom BGP, vendar mi je všeč BIRD in ga uporabljam povsod, ne želim ustvarjati entitet.

Zato sem dnstap-bgp skril znotraj omrežnega imenskega prostora, ki je s korenom povezan prek vmesnika veth: je kot cev, katere konci štrlijo v različnih imenskih prostorih. Na vsakem od teh koncev obesimo zasebne naslove IP p2p, ki ne presegajo gostitelja, zato so lahko karkoli. To je isti mehanizem, ki se uporablja za dostop do notranjih procesov ljubljeni od vseh Docker in drugi kontejnerji.

Za to je bilo napisano skripta in zgoraj opisana funkcionalnost za vlečenje za lase v drug imenski prostor je bila dodana v dnstap-bgp. Zaradi tega ga je treba zagnati kot root ali izdati dvojiški datoteki CAP_SYS_ADMIN prek ukaza setcap.

Primer skripta za ustvarjanje imenskega 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

Privzeto je v Ubuntuju Unbound binary vpet s profilom AppArmor, ki ji prepoveduje povezovanje z vsemi vrstami vtičnic DNSTap. Ta profil lahko izbrišete ali onemogočite:

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

To bi verjetno morali dodati v priročnik. Idealno je seveda popraviti profil in izdati potrebne pravice, vendar sem bil preveč len.

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

Prenos in obdelava seznamov

Skripta za prenos in obdelavo seznama IP naslovov
Prenese seznam, sešteje do predpone pfx. V dont_add и dont_summarize IP-jem in omrežjem lahko naročite, naj preskočijo ali ne povzemajo. Potreboval sem ga. podomrežje mojega VPS je bilo na seznamu blokiranih 🙂

Smešno je, da API RosKomSvoboda blokira zahteve s privzetim uporabniškim agentom Python. Videti je, da ga je script-kiddy dobil. Zato ga spremenimo v Ognelis.

Zaenkrat deluje le z IPv4. delež IPv6 je majhen, a ga bo enostavno popraviti. Razen če morate uporabiti tudi 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 za posodobitev
Enkrat na dan ga vodim na krono, morda je vredno potegniti vsake 4 ure. to je po mojem podaljšanje, ki ga RKN zahteva od ponudnikov. Poleg tega imajo še nekaj super nujnih blokad, ki lahko pridejo hitreje.

Naredi naslednje:

  • Zažene prvi skript in posodobi seznam poti (rkn_routes.list) za BIRD
  • Ponovno naloži BIRD
  • Posodobi in počisti seznam domen za dnstap-bgp
  • Ponovno naloži 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 so bile brez premisleka, tako da, če vidite nekaj, kar je mogoče izboljšati - izvolite.

Nastavitev odjemalca

Tukaj bom navedel primere za usmerjevalnike Linux, v primeru Mikrotik / Cisco pa bi moralo biti še lažje.

Najprej smo nastavili 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;
}

Tako bomo sinhronizirali poti, prejete od BGP, z usmerjevalno tabelo jedra številka 222.

Po tem je dovolj, da prosite jedro, da pogleda to ploščo, preden pogleda privzeto:

# 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

Vse, ostalo je konfigurirati DHCP na usmerjevalniku za distribucijo naslova IP tunela strežnika kot DNS in shema je pripravljena.

Omejitve

Pri trenutnem algoritmu generiranja in obdelave seznama domen med drugim vključuje youtube.com in njegovih CDN-jev.

In to vodi v dejstvo, da bodo vsi videoposnetki šli skozi VPN, kar lahko zamaši celoten kanal. Morda je vredno sestaviti seznam priljubljenih domen-izključitev, ki zaenkrat blokirajo RKN, drobovje je tanko. In jih preskočite pri razčlenjevanju.

Zaključek

Opisana metoda vam omogoča, da obidete skoraj vse blokade, ki jih trenutno izvajajo ponudniki.

V bistvu, dnstap-bgp se lahko uporablja za kateri koli drug namen, kjer je potrebna določena raven nadzora prometa glede na ime domene. Upoštevajte le, da lahko v našem času na istem naslovu IP visi tisoč spletnih mest (na primer za nekaterim Cloudflarejem), zato ima ta metoda precej nizko natančnost.

Toda za potrebe obhoda ključavnic je to povsem dovolj.

Dodatki, urejanja, zahteve po vleki - dobrodošli!

Vir: www.habr.com

Dodaj komentar