Kerülje meg az ILV blokkolást DNSTap és BGP segítségével

Kerülje meg az ILV blokkolást DNSTap és BGP segítségével

A téma eléggé el van verve, tudom. Például van egy nagyszerű cikk, de ott csak a blokklista IP-része veszi figyelembe. Domaineket is hozzáadunk.

Tekintettel arra, hogy a bíróságok és az RKN mindent jobbról és balról blokkolnak, a szolgáltatók pedig igyekeznek nem esnek a Revizorro által kiszabott bírságok alá, a blokkolással járó veszteségek meglehetősen nagyok. És a "törvényesen" blokkolt webhelyek között sok hasznos van (helló, rutracker)

Az RKN illetékességi területén kívül élek, de szüleim, rokonaim és barátaim otthon maradtak. Ezért úgy döntöttek, hogy egy egyszerű módszert találnak ki az informatikától távol élők számára a blokkolás megkerülésére, lehetőleg részvételük nélkül.

Ebben a jegyzetben nem az alapvető hálózati dolgokat írom le lépésenként, hanem leírom az általános elveket, hogyan lehet ezt a sémát megvalósítani. Tehát elengedhetetlen a hálózat működésének ismerete általában és különösen a Linuxban.

A zárak típusai

Először is frissítsük fel az emlékezetünket, hogy mi van blokkolva.

Az RKN-ből ki nem töltött XML-ben többféle zárolás létezik:

  • IP
  • Домен
  • URL

Az egyszerűség kedvéért kettőre redukáljuk őket: IP-re és domainre, és egyszerűen kivonjuk a domaint az URL-alapú blokkolás alól (pontosabban ezt már megtették helyettünk).

jó emberek Roskomsvoboda rájött egy csodálatos API, amelyen keresztül megkaphatjuk, amire szükségünk van:

Hozzáférés a blokkolt webhelyekhez

Ehhez szükségünk van valami kis külföldi VPS-re, lehetőleg korlátlan forgalommal - 3-5 dollárért sok ilyen van. A közeli külföldre kell vinnie, hogy a ping ne legyen túl nagy, de vegye figyelembe, hogy az internet és a földrajz nem mindig esik egybe. És mivel 5 dollárért nincs SLA, jobb, ha veszünk 2+ darabot különböző szolgáltatóktól a hibatűrés érdekében.

Ezután be kell állítanunk egy titkosított alagutat a kliens útválasztótól a VPS-ig. A Wireguardot használom, mint a leggyorsabb és legegyszerűbb beállítást. Linux alapú kliens routereim is vannak (APU2 vagy valami OpenWRT-ben). Egyes Mikrotik / Cisco esetében használhatja a rajtuk elérhető protokollokat, például az OpenVPN és a GRE-over-IPSEC.

Az érdeklődésre számot tartó forgalom azonosítása és átirányítása

Természetesen kikapcsolhatja az összes külföldi internetes forgalmat. De valószínűleg a helyi tartalommal való munka sebessége nagyban szenved ettől. Ráadásul a VPS sávszélesség-igénye sokkal magasabb lesz.

Ezért a forgalmat valahogyan a blokkolt oldalakhoz kell rendelnünk, és szelektíven az alagútba kell irányítanunk. Még ha a "extra" forgalom egy része oda is érkezik, még mindig sokkal jobb, mintha mindent az alagúton vezetnénk át.

A forgalom lebonyolítására a BGP protokollt fogjuk használni, és a VPS-től a kliensekhez útvonalakat hirdetünk a szükséges hálózatokhoz. Vegyük a BIRD-et az egyik legfunkcionálisabb és legkényelmesebb BGP démonnak.

IP

Az IP-alapú blokkolással minden világos: egyszerűen bejelentjük az összes blokkolt IP-címet VPS-sel. A probléma az, hogy az API által visszaadott listában körülbelül 600 ezer alhálózat található, és ezek túlnyomó többsége /32-es gazdagép. Ez a számú útvonal összezavarhatja a gyenge ügyfélútválasztókat.

Ezért a lista feldolgozása során úgy döntöttek, hogy a hálózatig összegzik / 24, ha 2 vagy több gazdagépe van. Így az útvonalak száma ~100 ezerre csökkent. Ennek forgatókönyve következik.

Domains

Ez bonyolultabb, és több módja is van. Például telepíthet egy átlátszó Squid-et minden kliens útválasztóra, és ott HTTP-elfogást hajthat végre, és bekukucskálhat a TLS-kézfogásba, hogy az első esetben megkapja a kért URL-t, a második esetben pedig a tartományt az SNI-től.

De a mindenféle újszerű TLS1.3 + eSNI miatt a HTTPS-elemzés napról napra kevésbé valós. Igen, és az ügyféloldali infrastruktúra egyre bonyolultabbá válik - legalább OpenWRT-t kell használnia.

Ezért úgy döntöttem, hogy elkapom a DNS-lekérdezésekre adott válaszokat. Itt is minden DNS-over-TLS / HTTPS elkezd lebegni a feje fölött, de (egyelőre) tudjuk irányítani ezt a részt a kliensen – vagy letilthatjuk, vagy használhatjuk a saját szerverünket a DoT/DoH-hoz.

Hogyan lehet elkapni a DNS-t?

Itt is többféle megközelítés létezhet.

  • DNS-forgalom elfogása PCAP-on vagy NFLOG-on keresztül
    Mindkét lehallgatási módszert megvalósítja a segédprogram sidmat. De már régóta nem támogatott, és a funkcionalitása nagyon primitív, ezért még mindig kell hozzá kábelt írni.
  • DNS-kiszolgáló naplóinak elemzése
    Sajnos az általam ismert rekurzorok nem képesek válaszokat naplózni, csak kéréseket. Ez elvileg logikus, hiszen a kérésekkel ellentétben a válaszok összetett szerkezetűek, és nehéz szöveges formában megírni őket.
  • DNSTap
    Szerencsére közülük sokan már támogatják a DNSTap-et erre a célra.

Mi az a DNSTap?

Kerülje meg az ILV blokkolást DNSTap és BGP segítségével

Ez egy kliens-szerver protokoll, amely protokollpuffereken és keretfolyamokon alapul, és a DNS-kiszolgálóról a strukturált DNS-lekérdezések és -válaszok gyűjtőjébe továbbítható. Lényegében a DNS-kiszolgáló a lekérdezések és válaszok metaadatait (üzenet típusa, kliens/szerver IP-címe stb.), valamint teljes DNS-üzeneteket továbbít abban a (bináris) formában, amelyben együttműködik velük a hálózaton keresztül.

Fontos megérteni, hogy a DNSTap paradigmában a DNS-kiszolgáló ügyfélként, a gyűjtő pedig szerverként működik. Vagyis a DNS-kiszolgáló csatlakozik a gyűjtőhöz, és nem fordítva.

Ma a DNSTap minden népszerű DNS-kiszolgálón támogatott. De például a BIND számos disztribúcióban (például az Ubuntu LTS-ben) gyakran valamilyen okból a támogatása nélkül épül fel. Tehát ne foglalkozzunk az összeszereléssel, hanem vegyünk egy könnyebb és gyorsabb rekurzort – Kötetlen.

Hogyan lehet elkapni a DNSTap-ot?

Van néhány szám CLI segédprogramok DNSTap eseményfolyammal való munkához, de nem alkalmasak a problémánk megoldására. Ezért úgy döntöttem, hogy feltalálok egy saját kerékpárt, amely mindent megtesz, ami szükséges: dnsap-bgp

Munka algoritmus:

  • Indításkor betölti a tartományok listáját egy szöveges fájlból, megfordítja azokat (habr.com -> com.habr), kizárja a szaggatott vonalakat, a duplikációkat és az aldomaineket (azaz ha a lista tartalmazza a habr.com és a www.habr.com, csak az első töltődik be), és létrehoz egy előtagfát a listában való gyors kereséshez
  • DNSTap-szerverként működik, és egy DNS-kiszolgálótól érkező kapcsolatot vár. Elvileg támogatja a UNIX és a TCP socketeket is, de az általam ismert DNS szerverek csak UNIX socketeket tudnak használni
  • A bejövő DNSTap csomagokat először egy Protobuf struktúrába deszerializálják, majd magát a bináris DNS üzenetet, amely az egyik Protobuf mezőben található, elemzi a DNS RR rekordok szintjére.
  • Ellenőrzi, hogy a kért gazdagép (vagy szülőtartománya) szerepel-e a betöltött listában, ha nem, a választ figyelmen kívül hagyja
  • A válaszból csak az A/AAAA/CNAME RR-ek kerülnek kiválasztásra, és a megfelelő IPv4/IPv6-címek kerülnek kinyerésre.
  • Az IP-címek konfigurálható TTL-lel vannak tárolva, és minden konfigurált BGP-társnak hirdetve
  • Ha olyan válasz érkezik, amely egy már gyorsítótárazott IP-címre mutat, annak TTL-je frissül
  • A TTL lejárta után a bejegyzés törlődik a gyorsítótárból és a BGP közleményekből

További funkciók:

  • A domainek listájának újraolvasása a SIGHUP által
  • A gyorsítótár szinkronban tartása más példányokkal dnsap-bgp HTTP/JSON-on keresztül
  • Másolja meg a gyorsítótárat a lemezen (a BoltDB adatbázisban), hogy újraindítás után visszaállítsa annak tartalmát
  • Támogatás egy másik hálózati névtérre való váltáshoz (az alábbiakban leírjuk, hogy miért van erre szükség)
  • IPv6 támogatás

korlátozások:

  • Az IDN domainek még nem támogatottak
  • Néhány BGP beállítás

gyűjtöttem RPM és DEB csomagok az egyszerű telepítés érdekében. Minden viszonylag friss operációs rendszeren működnie kell a systemd-vel. nincs függőségük.

A rendszer

Tehát kezdjük el az összes alkatrész összeszerelését. Ennek eredményeként valami ehhez hasonló hálózati topológiát kell kapnunk:
Kerülje meg az ILV blokkolást DNSTap és BGP segítségével

A munka logikája szerintem egyértelmű a diagramból:

  • A kliens szerverünk DNS-ként van konfigurálva, és a DNS-lekérdezéseknek is át kell menniük a VPN-en. Erre azért van szükség, hogy a szolgáltató ne tudjon DNS-elfogást használni a blokkoláshoz.
  • A webhely megnyitásakor az ügyfél DNS-lekérdezést küld, például „mik az xxx.org IP-címei”
  • Nincs korlátozás feloldja az xxx.org webhelyet (vagy kiveszi a gyorsítótárból), és választ küld a kliensnek, hogy „xxx.org-nak ilyen és ilyen IP-je van”, párhuzamosan lemásolva DNSTap-on keresztül.
  • dnsap-bgp bejelenti ezeket a címeket BIRD BGP-n keresztül, ha a domain a blokkolt listán van
  • BIRD útvonalat hirdet ezekhez az IP-címekhez next-hop self kliens útválasztó
  • A klienstől ezekre az IP-címekre továbbított csomagok átmennek az alagúton

A szerveren a blokkolt oldalakhoz vezető útvonalakhoz külön táblát használok a BIRD-en belül, és az semmilyen módon nem metszi egymást az operációs rendszerrel.

Ennek a sémának van egy hátránya: az ügyféltől származó első SYN-csomagnak valószínűleg ideje lesz elhagyni a hazai szolgáltatón keresztül. az útvonalat nem jelentik be azonnal. És itt a lehetőségek attól függően lehetségesek, hogy a szolgáltató hogyan végzi el a blokkolást. Ha csak csökkenti a forgalmat, akkor nincs gond. És ha átirányítja valamilyen DPI-re, akkor (elméletileg) speciális effektusok lehetségesek.

Az is előfordulhat, hogy a kliensek nem tartják tiszteletben a DNS TTL csodáit, ami miatt a kliens néhány elavult bejegyzést használ a rohadt gyorsítótárából, ahelyett, hogy az Unbound választ kérné.

A gyakorlatban nekem sem az első, sem a második nem okozott gondot, de a futásteljesítményed változhat.

Szerver hangolás

A gurulás megkönnyítésére írtam szerepe Ansible számára. Linux alapú szervereket és klienseket egyaránt konfigurálhat (deb alapú disztribúciókhoz tervezve). Minden beállítás teljesen nyilvánvaló és be van állítva leltár.yml. Ez a szerep a nagy játékkönyvemből van kivágva, így hibákat tartalmazhat - húzási kérések üdvözöllek 🙂

Nézzük át a fő összetevőket.

bgp

Két BGP-démon futtatása ugyanazon a gazdagépen egy alapvető problémával jár: a BIRD nem akarja beállítani a BGP társviszony-létesítést a localhosttal (vagy bármilyen helyi interfésszel). Egyáltalán a szóból. A guglizás és a levelezőlisták olvasása nem segített, állításuk szerint ez tervezési. Talán van rá mód, de nem találtam.

Kipróbálhatsz egy másik BGP démont, de én szeretem a BIRD-et, és mindenhol ezt használom, nem akarok entitásokat gyártani.

Ezért a hálózati névtérben elrejtettem a dnsap-bgp-t, amely a veth interfészen keresztül kapcsolódik a roothoz: olyan, mint egy cső, amelynek végei különböző névterekben állnak ki. Mindegyik végére felakasztunk privát p2p IP-címeket, amelyek nem lépnek túl a gazdagépen, így bármi lehet. Ez ugyanaz a mechanizmus, amelyet a belső folyamatokhoz való hozzáféréshez használnak mindenki által szeretett Docker és egyéb konténerek.

Erre írták forgatókönyv és a fentebb már ismertetett funkcionalitás, amellyel hajánál fogva áthúzhatod magad egy másik névtérbe, hozzáadásra került a dnsap-bgp-hez. Emiatt rootként kell futtatni, vagy ki kell adni a CAP_SYS_ADMIN binárisnak a setcap paranccsal.

Példa szkript névtér létrehozásához

#!/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

dnsap-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",
]

madár.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

Alapértelmezés szerint az Ubuntuban az Unbound binárist az AppArmor profil rögzíti, ami megtiltja, hogy mindenféle DNSTap sockethez csatlakozzon. Ezt a profilt törölheti vagy letilthatja:

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

Ezt valószínűleg hozzá kellene adni a játékkönyvhöz. Természetesen ideális a profil javítása és a szükséges jogok kiadása, de túl lusta voltam.

kötetlen.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

Listák letöltése és feldolgozása

Szkript az IP-címek listájának letöltéséhez és feldolgozásához
Letölti a listát, összegzi az előtagot pfx. -Ban dont_add и dont_summarise megadhatja az IP-címeket és a hálózatokat, hogy hagyja ki vagy ne foglalja össze. Szükségem volt rá. a VPS-em alhálózata benne volt a blokklistában 🙂

A vicces az, hogy a RosKomSvoboda API blokkolja a kéréseket az alapértelmezett Python felhasználói ügynökkel. Úgy tűnik, a forgatókönyv-kölyök megkapta. Ezért megváltoztatjuk Ognelis-re.

Eddig csak IPv4-el működik. az IPv6 részesedése kicsi, de könnyen javítható lesz. Hacsak nem kell a bird6-ot is használnod.

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)

Frissítendő szkript
Naponta egyszer megfuttatom a koronán, talán 4 óránként érdemes meghúzni. véleményem szerint ez az a megújítási időszak, amelyet az RKN megkövetel a szolgáltatóktól. Ráadásul van még néhány rendkívül sürgős blokkolásuk, ami gyorsabban megérkezhet.

A következőket teszi:

  • Futtatja az első szkriptet és frissíti az útvonalak listáját (rkn_routes.list) a BIRD számára
  • Töltse be újra a MADÁRT
  • Frissíti és kitisztítja a dnsap-bgp domainek listáját
  • Töltsd újra a dnsap-bgp-t

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

Gondolkodás nélkül íródtak, így ha láttok valamit, amin lehet javítani - hajrá.

Kliens beállítása

Itt példákat adok Linux útválasztókra, de a Mikrotik / Cisco esetében ez még egyszerűbb.

Először beállítjuk a BIRD-et:

madár.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;
}

Így a BGP-től kapott útvonalakat a 222-es számú kernel útválasztó táblával szinkronizáljuk.

Ezt követően elég megkérni a kernelt, hogy nézze meg ezt a lemezt, mielőtt megnézné az alapértelmezettet:

# 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

Minden, csak be kell állítani a DHCP-t az útválasztón, hogy a szerver alagút-IP-címét DNS-ként ossza el, és a séma készen áll.

Korlátozások

A tartománylista létrehozásának és feldolgozásának jelenlegi algoritmusával többek között youtube.com és CDN-jei.

És ez ahhoz a tényhez vezet, hogy az összes videó átmegy a VPN-en, ami eltömítheti az egész csatornát. Talán érdemes összeállítani egy listát az RKN-t blokkoló népszerű domainekről-kizárásokról egyelőre, vékony a belek. És kihagyja őket elemzéskor.

Következtetés

A leírt módszer lehetővé teszi szinte minden blokkolás megkerülését, amelyet a szolgáltatók jelenleg alkalmaznak.

Elvileg, dnsap-bgp bármilyen más célra használható, ahol a tartománynév alapján valamilyen szintű forgalomszabályozásra van szükség. Ne feledje, hogy korunkban ezer webhely lóghat ugyanazon az IP-címen (például néhány Cloudflare mögött), így ennek a módszernek a pontossága meglehetősen alacsony.

De a zárak megkerülésének igényeihez ez elég.

Kiegészítések, szerkesztések, lehívási kérések – üdvözlöm!

Forrás: will.com

Hozzászólás