Ohita ILV-esto DNSTapilla ja BGP:llä

Ohita ILV-esto DNSTapilla ja BGP:llä

Aihe on aika päihtynyt, tiedän. Esimerkiksi siellä on hieno artikkeli, mutta vain estolistan IP-osa otetaan huomioon. Lisäämme myös verkkotunnuksia.

Koska tuomioistuimet ja RKN estävät kaiken oikealle ja vasemmalle, ja palveluntarjoajat yrittävät kovasti olla joutumatta Revizorron myöntämien sakkojen alle, estoon liittyvät tappiot ovat melko suuria. Ja "laillisesti" estettyjen sivustojen joukossa on monia hyödyllisiä (hei, rutracker)

Asun RKN:n toimialueen ulkopuolella, mutta vanhempani, sukulaiseni ja ystäväni jäivät kotiin. Niinpä päätettiin keksiä helppo tapa IT:stä kaukana oleville ihmisille ohittaa esto, mieluiten ilman heidän osallistumistaan.

Tässä muistiinpanossa en kuvaile verkon perusasioita vaiheittain, vaan kuvaan yleiset periaatteet, miten tämä malli voidaan toteuttaa. Joten tieto verkon toiminnasta yleensä ja erityisesti Linuxissa on pakollinen.

Lukkojen tyypit

Virkistetään ensin muistimme siitä, mikä on estetty.

RKN:stä lataamattomassa XML:ssä on useita eri tyyppejä:

  • IP
  • Verkkotunnuksen nimi
  • URL

Yksinkertaisuuden vuoksi vähennämme ne kahteen: IP ja verkkotunnus, ja poistamme verkkotunnuksen URL-osoitteen eston (tarkemmin sanottuna he ovat jo tehneet tämän puolestamme).

hyviä ihmisiä Roskomsvoboda tajusi upeaa API, jonka kautta saamme tarvitsemamme:

Pääsy estetyille sivustoille

Tätä varten tarvitsemme pienen ulkomaisen VPS:n, mieluiten rajoittamattomalla liikenteellä - näitä on monia 3-5 taalalla. Sinun on otettava se lähiulkomailta, jotta ping ei ole kovin suuri, mutta ota jälleen huomioon, että Internet ja maantiede eivät aina ole samat. Ja koska 5 taalalla ei ole SLA:ta, on parempi ottaa 2+ kappaletta eri toimittajilta vikasietoisuuden vuoksi.

Seuraavaksi meidän on määritettävä salattu tunneli asiakasreitittimestä VPS:ään. Käytän Wireguardia nopeimmin ja helpoimmin asennettavana. Minulla on myös Linux-pohjaisia ​​asiakasreitittimiä (APU2 tai jotain OpenWRT:ssä). Joidenkin Mikrotik / Ciscon tapauksessa voit käyttää niissä saatavilla olevia protokollia, kuten OpenVPN ja GRE-over-IPSEC.

Kiinnostavan liikenteen tunnistaminen ja uudelleenohjaus

Voit tietysti sammuttaa kaiken Internet-liikenteen ulkomailla. Mutta todennäköisesti paikallisen sisällön kanssa työskentelyn nopeus kärsii tästä suuresti. Lisäksi VPS:n kaistanleveysvaatimukset ovat paljon korkeammat.

Siksi meidän on jotenkin kohdennettava liikenne estettyihin sivustoihin ja ohjattava se valikoivasti tunneliin. Vaikka osa "ylimääräisestä" liikenteestä pääsisi sinne, se on silti paljon parempi kuin ajaa kaikki tunnelin läpi.

Liikenteen hallintaan käytämme BGP-protokollaa ja ilmoitamme reitit tarvittaviin verkkoihin VPS:stä asiakkaillemme. Otetaan BIRD yhdeksi toimivimmista ja kätevimmistä BGP-daemoneista.

IP

IP-estolla kaikki on selvää: ilmoitamme vain kaikista estetyistä IP-osoitteista VPS:llä. Ongelmana on, että luettelossa, jonka API palauttaa, on noin 600 tuhatta aliverkkoa, ja suurin osa niistä on /32-isäntiä. Tämä reittien määrä voi hämmentää heikkoja asiakasreitittimiä.

Siksi luetteloa käsiteltäessä päätettiin tehdä yhteenveto verkkoon / 24 asti, jos sillä on 2 tai useampia isäntiä. Näin reittien määrä väheni ~100 tuhanteen. Tämän käsikirjoitus seuraa.

Verkkotunnukset

Se on monimutkaisempi ja siihen on useita tapoja. Voit esimerkiksi asentaa läpinäkyvän Squidin jokaiseen asiakasreitittimeen ja tehdä siellä HTTP-sieppauksen ja kurkistaa TLS-kättelyyn saadaksesi pyydetyn URL-osoitteen ensimmäisessä tapauksessa ja verkkotunnuksen SNI:ltä toisessa.

Mutta kaikenlaisten uusien TLS1.3 + eSNI:n vuoksi HTTPS-analyysi on yhä vähemmän todellista joka päivä. Kyllä, ja asiakaspuolen infrastruktuurista on tulossa monimutkaisempi - sinun on käytettävä vähintään OpenWRT: tä.

Siksi päätin ottaa polun siepata vastaukset DNS-pyyntöihin. Myös täällä DNS-over-TLS / HTTPS alkaa leijua pään päällä, mutta voimme (toistaiseksi) hallita tätä osaa asiakkaalla - joko poistaa sen käytöstä tai käyttää omaa palvelinta DoT / DoH: lle.

Kuinka siepata DNS?

Tässäkin voi olla useita lähestymistapoja.

  • DNS-liikenteen sieppaus PCAP:n tai NFLOGin kautta
    Molemmat näistä sieppausmenetelmistä on otettu käyttöön apuohjelmassa sidmat. Mutta sitä ei ole tuettu pitkään aikaan ja toiminnallisuus on erittäin alkeellista, joten sinun on silti kirjoitettava siihen valjaat.
  • DNS-palvelimen lokien analyysi
    Valitettavasti tuntemani rekursorit eivät pysty kirjaamaan vastauksia, vaan vain pyyntöjä. Periaatteessa tämä on loogista, koska toisin kuin pyynnöillä, vastauksilla on monimutkainen rakenne ja niitä on vaikea kirjoittaa tekstimuotoon.
  • DNSTap
    Onneksi monet heistä tukevat jo DNSTapia tähän tarkoitukseen.

Mikä on DNSTap?

Ohita ILV-esto DNSTapilla ja BGP:llä

Se on protokollapuskureihin ja kehysvirtoihin perustuva asiakas-palvelin-protokolla, jolla siirretään DNS-palvelimelta jäsenneltyjen DNS-kyselyjen ja -vastausten kerääjää. Pohjimmiltaan DNS-palvelin lähettää kyselyn ja vastauksen metatiedot (viestin tyyppi, asiakkaan/palvelimen IP-osoite jne.) sekä täydelliset DNS-viestit (binäärimuodossa), jossa se toimii niiden kanssa verkon yli.

On tärkeää ymmärtää, että DNSTap-paradigmassa DNS-palvelin toimii asiakkaana ja kerääjä toimii palvelimena. Eli DNS-palvelin muodostaa yhteyden kerääjään, ei päinvastoin.

Nykyään DNSTap on tuettu kaikissa suosituissa DNS-palvelimissa. Mutta esimerkiksi BIND monissa jakeluissa (kuten Ubuntu LTS) on usein rakennettu jostain syystä ilman sen tukea. Joten älkäämme vaivautuko kokoamiseen, vaan otamme kevyemmän ja nopeamman rekursorin - Sitoutumaton.

Kuinka saada DNSTap kiinni?

On jonkin verran numero CLI-apuohjelmat DNSTap-tapahtumavirran kanssa työskentelemiseen, mutta ne eivät sovellu ongelmamme ratkaisemiseen. Siksi päätin keksiä oman polkupyöräni, joka tekee kaiken tarvittavan: dnstap-bgp

Työn algoritmi:

  • Kun se käynnistetään, se lataa luettelon verkkotunnuksista tekstitiedostosta, kääntää ne (habr.com -> com.habr), sulkee pois katkoviivat, kaksoiskappaleet ja aliverkkotunnukset (eli jos luettelo sisältää habr.com ja www.habr.com, se ladataan vain ensimmäisen) ja rakentaa etuliitepuun nopeaa hakua varten tässä luettelossa
  • Se toimii DNSTap-palvelimena ja odottaa yhteyttä DNS-palvelimelta. Periaatteessa se tukee sekä UNIX- että TCP-pistokkeita, mutta tuntemani DNS-palvelimet voivat käyttää vain UNIX-pistokkeita
  • Saapuvat DNSTap-paketit sarjoitetaan ensin Protobuf-rakenteeseen ja sitten itse binääri DNS-viesti, joka sijaitsee yhdessä Protobuf-kentistä, jäsennetään DNS RR -tietueiden tasolle.
  • Tarkistetaan, onko pyydetty isäntä (tai sen pääverkkotunnus) latausluettelossa, jos ei, vastaus jätetään huomioimatta
  • Vain A/AAAA/CNAME RR:t valitaan vastauksesta ja vastaavat IPv4/IPv6-osoitteet poimitaan niistä.
  • IP-osoitteet tallennetaan välimuistiin konfiguroitavalla TTL:llä ja mainostetaan kaikille määritetyille BGP-vertaisyrityksille
  • Kun vastaanotetaan vastaus, joka osoittaa jo välimuistissa olevaan IP-osoitteeseen, sen TTL päivitetään
  • Kun TTL vanhenee, merkintä poistetaan välimuistista ja BGP-ilmoituksista

Lisätoiminnot:

  • SIGHUP lukee verkkotunnusluettelon uudelleen
  • Välimuistin pitäminen synkronoituna muiden esiintymien kanssa dnstap-bgp HTTP/JSONin kautta
  • Kopioi välimuisti levyllä (BoltDB-tietokannassa) palauttaaksesi sen sisällön uudelleenkäynnistyksen jälkeen
  • Tuki vaihtamiselle toiseen verkon nimiavaruuteen (miksi sitä tarvitaan, kuvataan alla)
  • IPv6 tuki

rajoituksia:

  • IDN-verkkotunnuksia ei vielä tueta
  • Vähän BGP-asetuksia

keräsin RPM ja DEB paketit helppoa asennusta varten. Pitäisi toimia kaikissa suhteellisen uusissa käyttöjärjestelmissä, joissa on systemd. heillä ei ole riippuvuuksia.

ohjelma

Joten aloitetaan kaikkien komponenttien kokoaminen yhteen. Tämän seurauksena meidän pitäisi saada jotain tämänkaltaista verkkotopologiaa:
Ohita ILV-esto DNSTapilla ja BGP:llä

Työn logiikka on mielestäni selkeä kaaviosta:

  • Asiakkaalla on palvelimemme määritetty DNS:ksi, ja myös DNS-kyselyiden on mentävä VPN:n yli. Tämä on välttämätöntä, jotta palveluntarjoaja ei voi käyttää DNS-sieppausta estämään.
  • Kun avaat sivuston, asiakas lähettää DNS-kyselyn, kuten "mitä ovat xxx.orgin IP-osoitteet"
  • sitomaton ratkaisee xxx.org:n (tai ottaa sen välimuistista) ja lähettää vastauksen asiakkaalle "xxx.orgilla on sellainen ja sellainen IP-osoite", monistamalla sen rinnakkain DNSTapin kautta
  • dnstap-bgp ilmoittaa nämä osoitteet LINTU BGP:n kautta, jos verkkotunnus on estettyjen luettelossa
  • LINTU mainostaa reittiä näihin IP-osoitteisiin next-hop self asiakasreititin
  • Myöhemmät paketit asiakkaalta näille IP-osoitteille kulkevat tunnelin läpi

Palvelimella käytän reiteille estetyille sivustoille erillistä taulukkoa BIRD:n sisällä, eikä se leikkaa käyttöjärjestelmän kanssa millään tavalla.

Tällä järjestelmällä on haittapuoli: asiakkaan ensimmäisellä SYN-paketilla on todennäköisesti aikaa lähteä kotimaisen palveluntarjoajan kautta. reittiä ei ilmoiteta heti. Ja tässä vaihtoehdot ovat mahdollisia riippuen siitä, kuinka palveluntarjoaja tekee eston. Jos hän vain pudottaa liikennettä, ei ole ongelmaa. Ja jos hän ohjaa sen johonkin DPI:hen, niin (teoreettisesti) erikoistehosteet ovat mahdollisia.

On myös mahdollista, että asiakkaat eivät kunnioita DNS TTL-ihmeitä, mikä voi saada asiakkaan käyttämään joitain vanhentuneita merkintöjä mätäneestä välimuististaan ​​sen sijaan, että hän kysyisi Sitoutumatonta.

Käytännössä ensimmäinen tai toinen ei aiheuttanut minulle ongelmia, mutta kilometrimääräsi voi vaihdella.

Palvelimen viritys

Rullaamisen helpottamiseksi kirjoitin rooli Ansiblelle. Se voi määrittää sekä palvelimia että asiakkaita, jotka perustuvat Linuxiin (suunniteltu deb-pohjaisiin jakeluihin). Kaikki asetukset ovat melko ilmeisiä ja asetettu inventory.yml. Tämä rooli on leikattu suuresta pelikirjastani, joten se voi sisältää virheitä - vetopyynnöt tervetuloa 🙂

Käydään läpi pääkomponentit.

BGP

Kun ajetaan kahta BGP-daemonia samalla isännällä, syntyy perustavanlaatuinen ongelma: BIRD ei halua aloittaa BGP-liikennettä paikallispalvelimen (tai minkä tahansa paikallisen käyttöliittymän) kanssa. Sanasta ollenkaan. Googlaaminen ja postituslistojen lukeminen ei auttanut, he väittävät, että tämä on suunniteltu. Ehkä on olemassa keino, mutta en löytänyt sitä.

Voit kokeilla toista BGP-demonia, mutta pidän BIRDistä ja käytän sitä kaikkialla, en halua tuottaa kokonaisuuksia.

Siksi piilotin dnsap-bgp:n verkon nimiavaruuden sisään, joka on yhdistetty juuriin veth-rajapinnan kautta: se on kuin putki, jonka päät työntyvät esiin eri nimiavaruuksissa. Kumpaankin näistä päistä ripustamme yksityisiä p2p-IP-osoitteita, jotka eivät ylitä isäntää, joten ne voivat olla mitä tahansa. Tämä on sama mekanismi, jota käytetään pääsyyn sisäisiin prosesseihin kaikkien rakastama Docker ja muut kontit.

Tätä varten se kirjoitettiin käsikirjoitus ja dnstap-bgp:hen lisättiin jo yllä kuvattu toiminto hiuksistasi raahaamiseksi toiseen nimiavaruuteen. Tästä syystä se on suoritettava pääkäyttäjänä tai annettava CAP_SYS_ADMIN-binäärille setcap-komennolla.

Esimerkkikomentosarja nimitilan luomiseen

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

bird.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

Oletusarvoisesti Ubuntussa Unbound binääri on kiinnitetty AppArmor-profiililla, joka estää sitä muodostamasta yhteyttä kaikenlaisiin DNSTap-pistokkeisiin. Voit joko poistaa tämän profiilin tai poistaa sen käytöstä:

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

Tämä pitäisi varmaan lisätä pelikirjaan. On tietysti ihanteellista korjata profiilia ja myöntää tarvittavat oikeudet, mutta olin liian laiska.

sitomaton.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

Listojen lataaminen ja käsittely

Komentosarja IP-osoiteluettelon lataamiseen ja käsittelyyn
Se lataa luettelon, summaa etuliitteeksi pfx. Sisään älä_lisää и dont_summarize voit käskeä IP-osoitteet ja verkot ohittamaan tai jättämään yhteenvedon. Tarvitsin sitä. VPS:ni aliverkko oli estoluettelossa 🙂

Hauska asia on, että RosKomSvoboda API estää pyynnöt oletusarvoisella Python-käyttäjäagentilla. Näyttää siltä, ​​​​että käsikirjoituslapsi ymmärsi sen. Siksi vaihdamme sen Ognelikseksi.

Toistaiseksi se toimii vain IPv4: n kanssa. IPv6:n osuus on pieni, mutta se on helppo korjata. Ellei sinun tarvitse käyttää myös bird6:ta.

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)

Päivitettävä komentosarja
Ajan sen kruunulle kerran päivässä, ehkä kannattaa vetää 4 tunnin välein. Tämä on mielestäni uusimisaika, jonka RKN vaatii palveluntarjoajilta. Lisäksi niillä on muita erittäin kiireellisiä estoja, jotka voivat saapua nopeammin.

Toimii seuraavasti:

  • Suorittaa ensimmäisen skriptin ja päivittää reittiluettelon (rkn_routes.list) BIRDille
  • Lataa BIRD uudelleen
  • Päivittää ja puhdistaa dnsap-bgp:n verkkotunnusluettelon
  • Lataa dnsap-bgp uudelleen

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

Ne on kirjoitettu ajattelematta, joten jos näet jotain, mitä voidaan parantaa - mene siihen.

Asiakkaan asetukset

Tässä annan esimerkkejä Linux-reitittimistä, mutta Mikrotikin / Ciscon tapauksessa sen pitäisi olla vielä helpompaa.

Ensin määritimme BIRDin:

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

Näin ollen synkronoimme BGP:ltä vastaanotetut reitit ytimen reititystaulukon numero 222 kanssa.

Sen jälkeen riittää, kun pyydät ydintä katsomaan tätä levyä ennen kuin katsot oletuslevyä:

# 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

Kaikki, on vielä määritettävä reitittimen DHCP jakamaan palvelimen tunnelin IP-osoite DNS:nä, ja järjestelmä on valmis.

Rajoitukset

Nykyisellä toimialueluettelon luomis- ja käsittelyalgoritmilla se sisältää mm. youtube.com ja sen CDN:t.

Ja tämä johtaa siihen, että kaikki videot kulkevat VPN:n kautta, mikä voi tukkia koko kanavan. Ehkä kannattaa koota lista suosituista verkkotunnuksista-poissulkemisista, jotka estävät RKN:n toistaiseksi, sisu on ohut. Ja ohita ne jäsennettäessä.

Johtopäätös

Kuvatun menetelmän avulla voit ohittaa lähes kaikki palveluntarjoajien tällä hetkellä toteuttamat estot.

Periaatteessa dnstap-bgp voidaan käyttää mihin tahansa muuhun tarkoitukseen, jossa tarvitaan jonkin verran liikenteenohjausta verkkotunnuksen perusteella. Muista vain, että meidän aikanamme tuhat sivustoa voi roikkua samassa IP-osoitteessa (esimerkiksi jonkin Cloudflaren takana), joten tällä menetelmällä on melko alhainen tarkkuus.

Mutta lukkojen ohituksen tarpeisiin tämä riittää.

Lisäykset, muokkaukset, vetopyynnöt - tervetuloa!

Lähde: will.com

Lisää kommentti