ILV blokeerimisest möödaminek DNSTap ja BGP abil

ILV blokeerimisest möödaminek DNSTap ja BGP abil

Teema on päris läbi löödud, ma tean. Näiteks on suurepärane artikkel, kuid seal võetakse arvesse ainult blokeerimisloendi IP-osa. Lisame ka domeenid.

Kuna kohtud ja RKN blokeerivad kõike paremale ja vasakule ning teenusepakkujad püüavad mitte jääda Revizorro määratud trahvide alla, on blokeerimisega seotud kahjud üsna suured. Ja "seaduslikult" blokeeritud saitide hulgas on palju kasulikke (tere, rutracker)

Ma elan väljaspool RKN-i jurisdiktsiooni, kuid mu vanemad, sugulased ja sõbrad jäid koju. Nii otsustati välja mõelda lihtne viis, kuidas IT-kaugetel inimestel blokeeringust mööda hiilida, eelistatavalt ilma nende osaluseta.

Selles märkuses ei kirjelda ma põhilisi võrguasju sammude kaupa, vaid kirjeldan üldisi põhimõtteid, kuidas seda skeemi saab rakendada. Nii et teadmised võrgu toimimisest üldiselt ja eriti Linuxis peavad olema.

Lukkude tüübid

Esmalt värskendame oma mälu blokeeritava kohta.

RKN-ist laadimata XML-is on mitut tüüpi lukke:

  • IP
  • Domeeninimi
  • URL

Lihtsuse huvides vähendame need kaheks: IP ja domeen ning eemaldame domeeni lihtsalt URL-i järgi blokeerimisest (täpsemalt on nad seda meie eest juba teinud).

head inimesed pärit Roskomsvoboda sai aru imelisest API, mille kaudu saame vajaliku:

Juurdepääs blokeeritud saitidele

Selleks vajame mõnda väikest välismaist VPS-i, soovitavalt piiramatu liiklusega – neid on 3-5 taala eest palju. Peate selle võtma lähivälismaal, et ping ei oleks väga suur, kuid jällegi arvestage, et Internet ja geograafia ei lange alati kokku. Ja kuna 5 dollari eest SLA-d pole, on veataluvuse tagamiseks parem võtta 2+ tükki erinevatelt pakkujatelt.

Järgmiseks peame seadistama krüptitud tunneli kliendiruuterist VPS-i. Ma kasutan Wireguardi kui kõige kiiremini ja lihtsamini seadistatavat. Mul on ka Linuxil põhinevad kliendiruuterid (APU2 või midagi OpenWRT-s). Mõne Mikrotik / Cisco puhul saate kasutada nendes saadaolevaid protokolle, nagu OpenVPN ja GRE-over-IPSEC.

Huvipakkuva liikluse tuvastamine ja ümbersuunamine

Loomulikult saate välja lülitada kogu Interneti-liikluse läbi välisriikide. Kuid tõenäoliselt kannatab see kohaliku sisuga töötamise kiirus suuresti. Lisaks on VPS-i ribalaiuse nõuded palju kõrgemad.

Seetõttu peame liikluse kuidagi jaotama blokeeritud saitidele ja suunama selle valikuliselt tunnelisse. Isegi kui osa "lisa" liiklusest sinna satub, on see ikkagi palju parem kui kõik tunnelist läbi sõita.

Liikluse haldamiseks kasutame BGP-protokolli ja teatame oma VPS-ist klientidele marsruudid vajalikesse võrkudesse. Võtame BIRDi kui ühe kõige funktsionaalsema ja mugavama BGP deemoni.

IP

IP blokeerimisega on kõik selge: me lihtsalt teatame kõik blokeeritud IP-d VPS-iga. Probleem on selles, et loendis, mille API tagastab, on umbes 600 tuhat alamvõrku ja valdav enamus neist on /32 hostid. Selline marsruutide arv võib nõrgad kliendiruuterid segadusse ajada.

Seetõttu otsustati loendi töötlemisel teha kokkuvõte kuni võrguni / 24, kui sellel on 2 või enam hosti. Seega vähenes liinide arv ~100 tuhandeni. Sellele järgneb stsenaarium.

Domeenid

See on keerulisem ja selleks on mitu võimalust. Näiteks saate installida igale kliendiruuterile läbipaistva Squidi ja teha seal HTTP pealtkuulamist ning piiluda TLS-i käepigistust, et esimesel juhul saada nõutud URL ja teisel juhul SNI-lt domeen.

Kuid kõikvõimalike uudsete TLS1.3 + eSNI tõttu muutub HTTPS-i analüüs iga päevaga üha vähem reaalseks. Jah, ja kliendipoolne infrastruktuur muutub keerulisemaks - peate kasutama vähemalt OpenWRT-d.

Seetõttu otsustasin võtta DNS-i päringutele vastuste pealtkuulamise tee. Ka siin hakkab teie pea kohal hõljuma mis tahes DNS-over-TLS / HTTPS, kuid me saame (praegu) seda osa kliendil juhtida - kas selle keelata või kasutada DoT / DoH jaoks oma serverit.

Kuidas DNS-i pealt kuulata?

Ka siin võib olla mitu lähenemist.

  • DNS-liikluse pealtkuulamine PCAP-i või NFLOG-i kaudu
    Mõlemad pealtkuulamismeetodid on utiliidis rakendatud sidmat. Kuid seda pole pikka aega toetatud ja funktsionaalsus on väga primitiivne, nii et peate selle jaoks ikkagi rakmed kirjutama.
  • DNS-serveri logide analüüs
    Kahjuks ei suuda minu teada rekursorid vastuseid logida, vaid ainult päringuid. Põhimõtteliselt on see loogiline, kuna erinevalt päringutest on vastustel keeruline struktuur ja neid on raske teksti kujul kirjutada.
  • DNSTap
    Õnneks toetavad paljud neist juba DNSTapi sel eesmärgil.

Mis on DNSTap?

ILV blokeerimisest möödaminek DNSTap ja BGP abil

See on klient-server protokoll, mis põhineb protokollipuhvritel ja kaadrivoogudel DNS-serverist struktureeritud DNS-päringute ja vastuste kogujale edastamiseks. Põhimõtteliselt edastab DNS-server päringu ja vastuse metaandmeid (sõnumi tüüp, kliendi/serveri IP jne) ning täielikke DNS-sõnumeid (binaarsel) kujul, milles ta nendega töötab.

Oluline on mõista, et DNSTap paradigmas toimib DNS-server kliendina ja koguja serverina. See tähendab, et DNS-server loob ühenduse kollektoriga, mitte vastupidi.

Tänapäeval toetavad DNSTapi kõik populaarsed DNS-serverid. Kuid näiteks BIND paljudes distributsioonides (nagu Ubuntu LTS) on sageli mingil põhjusel ehitatud ilma selle toetuseta. Nii et ärgem vaevutagem uuesti kokkupanemisega, vaid võtkem kergem ja kiirem rekursor – Piiramata.

Kuidas DNSTapi püüda?

On mõned number CLI utiliidid DNSTapi sündmuste vooga töötamiseks, kuid need ei sobi meie probleemi lahendamiseks. Seetõttu otsustasin leiutada oma jalgratta, mis teeb kõik vajaliku: dnsap-bgp

Töö algoritm:

  • Käivitamisel laadib see tekstifailist domeenide loendi, pöörab need ümber (habr.com -> com.habr), välistab katkendlikud read, duplikaadid ja alamdomeenid (st kui loend sisaldab habr.com ja www.habr.com, see laaditakse ainult esimene) ja loob selle loendi kiireks otsimiseks prefiksipuu
  • DNSTap-serverina tegutsedes ootab see DNS-serverilt ühendust. Põhimõtteliselt toetab see nii UNIX-i kui ka TCP-pesasid, kuid minu teada DNS-serverid saavad kasutada ainult UNIX-i sokke
  • Sissetulevad DNSTap-paketid deserialiseeritakse esmalt Protobuf-struktuuriks ja seejärel sõelutakse binaarne DNS-sõnum ise, mis asub ühel Protobufi väljadest, DNS-i RR-kirjete tasemele.
  • Kontrollitakse, kas taotletud host (või selle ülemdomeen) on laaditud nimekirjas, kui mitte, siis vastust ignoreeritakse
  • Vastusest valitakse ainult A/AAAA/CNAME RR-id ja neist ekstraheeritakse vastavad IPv4/IPv6 aadressid
  • IP-aadressid salvestatakse vahemällu konfigureeritava TTL-iga ja reklaamitakse kõigile konfigureeritud BGP-kaaslastele
  • Kui saate vastuse, mis osutab juba vahemällu salvestatud IP-le, värskendatakse selle TTL-i
  • Pärast TTL-i aegumist eemaldatakse kirje vahemälust ja BGP-teadetest

Lisafunktsioonid:

  • SIGHUPi domeenide loendi uuesti lugemine
  • Vahemälu teiste eksemplaridega sünkroonis hoidmine dnsap-bgp HTTP/JSON-i kaudu
  • Kopeerige vahemälu kettal (BoltDB andmebaasis), et taastada selle sisu pärast taaskäivitamist
  • Toetus teisele võrgu nimeruumile üleminekuks (miks seda vaja on, kirjeldatakse allpool)
  • IPv6 tugi

Piirangud:

  • IDN-domeene ei toetata veel
  • Vähesed BGP-seaded

Ma kogusin RPM ja DEB paketid lihtsaks paigaldamiseks. Peaks töötama kõigi suhteliselt hiljutiste OS-idega, millel on systemd. neil ei ole mingeid sõltuvusi.

Kava

Niisiis, alustame kõigi komponentide kokkupanemist. Selle tulemusena peaksime saama midagi sellist, nagu see võrgutopoloogia:
ILV blokeerimisest möödaminek DNSTap ja BGP abil

Töö loogika on minu arvates diagrammil selge:

  • Kliendil on meie server konfigureeritud DNS-iks ja DNS-päringud peavad samuti minema üle VPN-i. See on vajalik selleks, et pakkuja ei saaks blokeerimiseks kasutada DNS-i pealtkuulamist.
  • Saidi avamisel saadab klient DNS-päringu, näiteks "What are the IPs of xxx.org"
  • sidumata lahendab xxx.org (või võtab selle vahemälust) ja saadab kliendile vastuse “xxx.org-il on selline ja selline IP”, dubleerides selle paralleelselt DNSTapi kaudu
  • dnsap-bgp teatab need aadressid sisse BIRD BGP kaudu, kui domeen on blokeeritud loendis
  • BIRD reklaamib marsruuti nende IP-de juurde next-hop self kliendi ruuter
  • Järgmised paketid kliendilt nendele IP-dele lähevad läbi tunneli

Serveris kasutan blokeeritud saitidele suunduvate marsruutide jaoks BIRD-i sees eraldi tabelit ja see ei ristu OS-iga kuidagi.

Sellel skeemil on puudus: kliendi esimesel SYN-paketil on tõenäoliselt aega kodumaise teenusepakkuja kaudu lahkuda. marsruuti kohe ei teatata. Ja siin on valikud võimalikud sõltuvalt sellest, kuidas pakkuja blokeerib. Kui ta lihtsalt vähendab liiklust, siis pole probleemi. Ja kui ta selle mõnele DPI-le ümber suunab, siis on (teoreetiliselt) eriefektid võimalikud.

Samuti on võimalik, et kliendid ei austa DNS-i TTL-i imesid, mis võib põhjustada selle, et klient kasutab oma mäda vahemälust mõnda aegunud kirjet, selle asemel et küsida sidumata.

Praktikas ei tekitanud minu jaoks probleeme ei esimene ega teine, kuid teie läbisõit võib erineda.

Serveri häälestamine

Veeremise hõlbustamiseks kirjutasin rolli Ansible. See võib konfigureerida nii servereid kui ka kliente, mis põhinevad Linuxil (mõeldud deb-põhiste distributsioonide jaoks). Kõik seaded on üsna ilmsed ja sisse seatud inventar.yml. See roll on minu suurest mänguraamatust välja lõigatud, nii et see võib sisaldada vigu - tõmbetaotlused tere tulemast 🙂

Vaatame läbi põhikomponendid.

Bgp

Kahe BGP-deemoni käitamisel samas hostis on põhiprobleem: BIRD ei taha seadistada BGP-ühendust kohaliku hosti (või mõne kohaliku liidesega). Sõnast üldse. Googeldamine ja meililistide lugemine ei aidanud, nad väidavad, et see on kavandatud. Võib-olla on mingi võimalus, aga ma ei leidnud seda.

Võite proovida teist BGP-deemonit, kuid mulle meeldib BIRD ja ma kasutan seda kõikjal, ma ei taha oleme toota.

Seetõttu peitsin võrgu nimeruumi sisse dnsap-bgp, mis on vethi liidese kaudu juurega ühendatud: see on nagu toru, mille otsad paistavad erinevates nimeruumides välja. Kõigile nendele otstele riputame privaatsed p2p IP-aadressid, mis ei ulatu hostist kaugemale, nii et need võivad olla ükskõik millised. See on sama mehhanism, mida kasutatakse sisemistele protsessidele juurdepääsuks kõigi poolt armastatud Docker ja muud konteinerid.

Selle jaoks kirjutati stsenaarium ja dnsap-bgp-sse lisati juba ülalkirjeldatud funktsioon enda karvast teise nimeruumi tirimiseks. Seetõttu tuleb see käivitada administraatorina või väljastada kahendfailile CAP_SYS_ADMIN käsuga setcap.

Näidisskript nimeruumi loomiseks

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

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

Vaikimisi piirab Ubuntu sidumata binaarfaili AppArmor profiil, mis keelab sellel ühenduse luua igasuguste DNSTapi pesadega. Saate selle profiili kustutada või keelata.

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

See tuleks ilmselt mänguraamatusse lisada. Ideaalne on muidugi profiili parandada ja vajalikud õigused väljastada, aga ma olin liiga laisk.

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

Loendite allalaadimine ja töötlemine

Skript IP-aadresside loendi allalaadimiseks ja töötlemiseks
See laadib loendi alla, võtab kokku prefiksi pfx. Sisse dont_add и dont_summarise saate IP-aadressidele ja võrkudele öelda, kas jätate kokkuvõtte vahele või mitte. Mul oli seda vaja. minu VPS-i alamvõrk oli blokeerimisloendis 🙂

Naljakas on see, et RosKomSvoboda API blokeerib päringud Pythoni vaikekasutajaagendiga. Näib, et stsenarist sai sellest aru. Seetõttu muudame selle Ogneliseks.

Siiani töötab see ainult IPv4-ga. IPv6 osakaal on väike, kuid seda on lihtne parandada. Kui just ei pea kasutama ka 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)

Värskendatav skript
Ma jooksen seda kroonile korra päevas, võib-olla tasub seda tõmmata iga 4 tunni tagant. see on minu arvates uuendamisperiood, mida RKN pakkujatelt nõuab. Lisaks on neil mõni muu ülikiire blokeerimine, mis võib kiiremini kohale jõuda.

Teeb järgmist:

  • Käivitab esimese skripti ja värskendab marsruutide loendit (rkn_routes.list) LINNU jaoks
  • Laadi LIND uuesti
  • Värskendab ja puhastab dnsap-bgp domeenide loendit
  • Laadige uuesti dnsap-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

Need on kirjutatud ilma pikema mõtlemiseta, nii et kui näete midagi, mida saab parandada - laske sellel.

Kliendi seadistamine

Siin toon näiteid Linuxi ruuterite kohta, kuid Mikrotik / Cisco puhul peaks see olema veelgi lihtsam.

Esiteks seadistasime BIRD:

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

Seega sünkroniseerime BGP-lt saadud marsruudid kerneli marsruutimistabeli numbriga 222.

Pärast seda piisab, kui palute kernelil seda plaati vaadata, enne kui vaatate vaikimisi:

# 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

Kõik, jääb üle konfigureerida ruuteris DHCP serveri tunneli IP-aadressi DNS-ina levitamiseks ja skeem on valmis.

Piirangud

Praeguse domeenide loendi koostamise ja töötlemise algoritmiga sisaldab see muu hulgas youtube.com ja selle CDN-id.

Ja see toob kaasa asjaolu, et kõik videod läbivad VPN-i, mis võib kogu kanali ummistada. Võib-olla tasub esialgu koostada nimekiri populaarsetest domeenidest-välistustest, mis RKN-i blokeerivad, sisikond on õhuke. Ja jätke need sõelumisel vahele.

Järeldus

Kirjeldatud meetod võimaldab teil mööda minna peaaegu kõigist blokeeringutest, mida pakkujad praegu rakendavad.

Põhimõtteliselt dnsap-bgp saab kasutada mis tahes muul otstarbel, kus domeeninime alusel on vaja teatud tasemel liikluse juhtimist. Pidage vaid meeles, et meie ajal võib sama IP-aadressi küljes riputada tuhat saiti (näiteks mõne Cloudflare'i taga), seega on selle meetodi täpsus üsna madal.

Kuid lukkudest möödahiilimise vajadusteks on see täiesti piisav.

Täiendused, muudatused, tõmbamistaotlused – tere tulemast!

Allikas: www.habr.com

Lisa kommentaar