FörbigÄ ILV-blockering med DNSTap och BGP

FörbigÄ ILV-blockering med DNSTap och BGP

Ämnet Ă€r ganska upprört, jag vet. Till exempel finns det en stor artikel, men endast IP-delen av blockeringslistan beaktas dĂ€r. Vi kommer ocksĂ„ att lĂ€gga till domĂ€ner.

PÄ grund av det faktum att domstolarna och RKN blockerar allt till höger och vÀnster, och leverantörerna försöker hÄrt för att inte falla under de böter som utfÀrdats av Revizorro, Àr de tillhörande förlusterna frÄn blockering ganska stora. Och bland de "lagligt" blockerade webbplatserna finns det mÄnga anvÀndbara (hej, rutracker)

Jag bor utanför RKN:s jurisdiktion, men mina förÀldrar, slÀktingar och vÀnner förblev hemma. SÄ man bestÀmde sig för att komma pÄ ett enkelt sÀtt för mÀnniskor lÄngt ifrÄn IT att kringgÄ blockering, helst utan deras deltagande alls.

I denna not kommer jag inte att beskriva de grundlÀggande nÀtverkssakerna i steg, utan kommer att beskriva de allmÀnna principerna för hur detta schema kan implementeras. SÄ kunskap om hur nÀtverket fungerar i allmÀnhet och i Linux i synnerhet Àr ett mÄste.

Typer av lÄs

LÄt oss först frÀscha upp vÄrt minne av det som blockeras.

Det finns flera typer av lÄs i den avlÀsta XML-filen frÄn RKN:

  • IP
  • Đ”ĐŸĐŒĐ”Đœ
  • URL

För enkelhetens skull kommer vi att reducera dem till tvÄ: IP och domÀn, och vi kommer helt enkelt att ta bort domÀnen frÄn blockering via URL (mer exakt, de har redan gjort detta Ät oss).

bra mÀnniskor frÄn Roskomsvoboda insÄg en underbar API, genom vilken vi kan fÄ det vi behöver:

TillgÄng till blockerade webbplatser

För att göra detta behöver vi nĂ„gra smĂ„ utlĂ€ndska VPS, gĂ€rna med obegrĂ€nsad trafik – det finns mĂ„nga sĂ„dana för 3-5 spĂ€nn. Du mĂ„ste ta det i nĂ€rheten av utlandet sĂ„ att pingen inte Ă€r sĂ€rskilt stor, men Ă„terigen, ta hĂ€nsyn till att internet och geografi inte alltid sammanfaller. Och eftersom det inte finns nĂ„gon SLA för 5 spĂ€nn Ă€r det bĂ€ttre att ta 2+ stycken frĂ„n olika leverantörer för feltolerans.

DÀrefter mÄste vi stÀlla in en krypterad tunnel frÄn klientroutern till VPS. Jag anvÀnder Wireguard som den snabbaste och enklaste att stÀlla in. Jag har Àven klientroutrar baserade pÄ Linux (APU2 eller nÄgot i OpenWRT). NÀr det gÀller vissa Mikrotik / Cisco kan du anvÀnda protokollen som finns tillgÀngliga pÄ dem som OpenVPN och GRE-over-IPSEC.

Identifiering och omdirigering av intressetrafik

Du kan naturligtvis stÀnga av all internettrafik genom frÀmmande lÀnder. Men sannolikt kommer hastigheten att arbeta med lokalt innehÄll att lida mycket av detta. Dessutom kommer bandbreddskraven pÄ VPS att vara mycket högre.

DĂ€rför mĂ„ste vi pĂ„ nĂ„got sĂ€tt allokera trafik till blockerade webbplatser och selektivt dirigera den till tunneln. Även om en del av den "extra" trafiken kommer dit Ă€r det Ă€ndĂ„ mycket bĂ€ttre Ă€n att köra allt genom tunneln.

För att hantera trafik kommer vi att anvÀnda BGP-protokollet och meddela rutter till nödvÀndiga nÀtverk frÄn vÄr VPS till kunder. LÄt oss ta BIRD som en av de mest funktionella och bekvÀma BGP-demonerna.

IP

Med blockering av IP Àr allt klart: vi meddelar helt enkelt alla blockerade IP:er med VPS. Problemet Àr att det finns cirka 600 tusen subnÀt i listan som API:et returnerar, och de allra flesta av dem Àr /32-vÀrdar. Detta antal rutter kan förvirra svaga klientroutrar.

DÀrför, nÀr listan bearbetades, beslutades det att sammanfatta upp till nÀtverket / 24 om det har 2 eller fler vÀrdar. SÄledes reducerades antalet rutter till ~100 tusen. Manuset för detta kommer att följa.

domÀner

Det Àr mer komplicerat och det finns flera sÀtt. Du kan till exempel installera en genomskinlig Squid pÄ varje klientrouter och göra HTTP-avlyssning dÀr och kika in i TLS-handskakningen för att fÄ den begÀrda URL:en i det första fallet och domÀnen frÄn SNI i det andra.

Men pÄ grund av alla möjliga nymodiga TLS1.3 + eSNI, blir HTTPS-analys mindre och mindre verklig för varje dag. Ja, och infrastrukturen pÄ klientsidan blir mer komplicerad - du mÄste anvÀnda Ätminstone OpenWRT.

DĂ€rför bestĂ€mde jag mig för att ta vĂ€gen att avlyssna svar pĂ„ DNS-förfrĂ„gningar. Även hĂ€r börjar all DNS-over-TLS/HTTPS att svĂ€va över ditt huvud, men vi kan (för nu) styra denna del pĂ„ klienten – antingen inaktivera den eller anvĂ€nd din egen server för DoT/DoH.

Hur avlyssnar man DNS?

Även hĂ€r kan det finnas flera tillvĂ€gagĂ„ngssĂ€tt.

  • Avlyssning av DNS-trafik via PCAP eller NFLOG
    BÄda dessa metoder för avlyssning Àr implementerade i verktyget sidmat. Men det har inte stötts pÄ lÀnge och funktionaliteten Àr vÀldigt primitiv, sÄ du behöver fortfarande skriva en sele för den.
  • Analys av DNS-serverloggar
    TyvÀrr kan inte de för mig kÀnda rekursorerna logga svar, utan bara förfrÄgningar. I princip Àr detta logiskt, eftersom svar, till skillnad frÄn förfrÄgningar, har en komplex struktur och det Àr svÄrt att skriva dem i textform.
  • DNSTap
    Lyckligtvis har mÄnga av dem redan stöd för DNSTap för detta ÀndamÄl.

Vad Àr DNSTap?

FörbigÄ ILV-blockering med DNSTap och BGP

Det Àr ett klient-serverprotokoll baserat pÄ Protocol Buffers and Frame Streams för överföring frÄn en DNS-server till en samlare av strukturerade DNS-frÄgor och -svar. I huvudsak överför DNS-servern frÄge- och svarsmetadata (typ av meddelande, klient/server-IP, etc.) plus kompletta DNS-meddelanden i den (binÀra) form som den arbetar med dem över nÀtverket.

Det Àr viktigt att förstÄ att i DNSTap-paradigmet fungerar DNS-servern som en klient och samlaren som en server. Det vill sÀga att DNS-servern ansluter till insamlaren och inte vice versa.

Idag stöds DNSTap i alla populĂ€ra DNS-servrar. Men till exempel, BIND i mĂ„nga distributioner (som Ubuntu LTS) byggs ofta av nĂ„gon anledning utan dess stöd. SĂ„ lĂ„t oss inte besvĂ€ra oss med Ă„termontering, utan ta en lĂ€ttare och snabbare rekursor – Obundet.

Hur fÄngar man DNSTap?

Det finns vissa nummer CLI-verktyg för att arbeta med en ström av DNSTap-hÀndelser, men de Àr inte lÀmpliga för att lösa vÄrt problem. DÀrför bestÀmde jag mig för att uppfinna min egen cykel som gör allt som behövs: dnstap-bgp

Arbetsalgoritm:

  • NĂ€r den startas laddar den en lista över domĂ€ner frĂ„n en textfil, inverterar dem (habr.com -> com.habr), utesluter brutna linjer, dubbletter och underdomĂ€ner (dvs om listan innehĂ„ller habr.com och www.habr.com, den kommer att laddas endast den första) och bygger ett prefixtrĂ€d för snabb sökning genom denna lista
  • Den fungerar som en DNSTap-server och vĂ€ntar pĂ„ en anslutning frĂ„n en DNS-server. I princip stöder den bĂ„de UNIX- och TCP-sockets, men de DNS-servrar jag kĂ€nner kan bara anvĂ€nda UNIX-sockets
  • Inkommande DNSTap-paket deserialiseras först till en Protobuf-struktur, och sedan analyseras sjĂ€lva det binĂ€ra DNS-meddelandet, som finns i ett av Protobuf-fĂ€lten, till nivĂ„n för DNS RR-poster
  • Det kontrolleras om den begĂ€rda vĂ€rden (eller dess överordnade domĂ€n) finns i den laddade listan, om inte, ignoreras svaret
  • Endast A/AAAA/CNAME RR:er vĂ€ljs frĂ„n svaret och motsvarande IPv4/IPv6-adresser extraheras frĂ„n dem
  • IP-adresser cachelagras med konfigurerbar TTL och annonseras till alla konfigurerade BGP-kamrater
  • NĂ€r du fĂ„r ett svar som pekar pĂ„ en redan cachad IP uppdateras dess TTL
  • Efter att TTL löper ut tas posten bort frĂ„n cachen och frĂ„n BGP-meddelanden

Ytterligare funktionalitet:

  • LĂ€ser om listan över domĂ€ner av SIGHUP
  • HĂ„ller cachen synkroniserad med andra instanser dnstap-bgp via HTTP/JSON
  • Duplicera cachen pĂ„ disken (i BoltDB-databasen) för att Ă„terstĂ€lla dess innehĂ„ll efter en omstart
  • Stöd för att byta till ett annat nĂ€tverksnamnomrĂ„de (varför detta behövs kommer att beskrivas nedan)
  • IPv6-stöd

restriktioner:

  • IDN-domĂ€ner stöds inte Ă€nnu
  • FĂ„ BGP-instĂ€llningar

jag samlade RPM och DEB paket för enkel installation. Bör fungera pÄ alla relativt nya operativsystem med systemd. de har inga beroenden.

Schemat

SÄ lÄt oss börja montera alla komponenterna tillsammans. Som ett resultat bör vi fÄ nÄgot som denna nÀtverkstopologi:
FörbigÄ ILV-blockering med DNSTap och BGP

Arbetets logik, tror jag, framgÄr tydligt av diagrammet:

  • Klienten har vĂ„r server konfigurerad som DNS, och DNS-frĂ„gor mĂ„ste ocksĂ„ gĂ„ över VPN. Detta Ă€r nödvĂ€ndigt sĂ„ att leverantören inte kan anvĂ€nda DNS-avlyssning för att blockera.
  • NĂ€r du öppnar webbplatsen skickar klienten en DNS-frĂ„ga som "vad Ă€r IP-adresserna för xxx.org"
  • Obundet löser xxx.org (eller tar det frĂ„n cachen) och skickar ett svar till klienten "xxx.org har en sĂ„dan och en sĂ„dan IP", duplicerar den parallellt via DNSTap
  • dnstap-bgp tillkĂ€nnager dessa adresser i FÅGEL via BGP om domĂ€nen finns pĂ„ blockeringslistan
  • FÅGEL annonserar en vĂ€g till dessa IP-adresser med next-hop self klientrouter
  • Efterföljande paket frĂ„n klienten till dessa IP:er gĂ„r genom tunneln

PÄ servern, för rutter till blockerade webbplatser, anvÀnder jag en separat tabell inuti BIRD och den korsar inte OS pÄ nÄgot sÀtt.

Detta schema har en nackdel: det första SYN-paketet frÄn klienten kommer troligen att ha tid att lÀmna via den inhemska leverantören. rutten meddelas inte omedelbart. Och hÀr Àr alternativ möjliga beroende pÄ hur leverantören gör blockeringen. Om han bara slÀpper trafiken Àr det inga problem. Och om han omdirigerar den till nÄgon DPI sÄ Àr (teoretiskt) specialeffekter möjliga.

Det Àr ocksÄ möjligt att klienter inte respekterar DNS TTL-mirakel, vilket kan fÄ klienten att anvÀnda nÄgra inaktuella poster frÄn sin ruttna cache istÀllet för att frÄga Unbound.

I praktiken orsakade varken den första eller den andra problem för mig, men din körstrÀcka kan variera.

Serverjustering

För att underlĂ€tta rullningen skrev jag roll för Ansible. Den kan konfigurera bĂ„de servrar och klienter baserade pĂ„ Linux (designad för deb-baserade distributioner). Alla instĂ€llningar Ă€r ganska uppenbara och Ă€r instĂ€llda inventory.yml. Den hĂ€r rollen Ă€r klippt frĂ„n min stora spelbok, sĂ„ den kan innehĂ„lla fel - dra önskemĂ„l vĂ€lkommen 🙂

LÄt oss gÄ igenom huvudkomponenterna.

bgp

Att köra tvÄ BGP-demoner pÄ samma vÀrd har ett grundlÀggande problem: BIRD vill inte stÀlla in BGP-peering med den lokala vÀrden (eller nÄgot lokalt grÀnssnitt). FrÄn ordet överhuvudtaget. Att googla och lÀsa e-postlistor hjÀlpte inte, de hÀvdar att detta Àr av design. Kanske finns det nÄgot sÀtt, men jag hittade det inte.

Du kan prova en annan BGP-demon, men jag gillar BIRD och den anvÀnds överallt av mig, jag vill inte producera entiteter.

DÀrför gömde jag dnstap-bgp inuti nÀtverkets namnutrymme, som Àr anslutet till roten via veth-grÀnssnittet: det Àr som ett rör, vars Àndar sticker ut i olika namnutrymmen. I var och en av dessa Àndar hÀnger vi privata p2p IP-adresser som inte gÄr utöver vÀrden, sÄ de kan vara vad som helst. Detta Àr samma mekanism som anvÀnds för att komma Ät processer inuti Àlskad av alla Hamnarbetare och andra containrar.

För detta skrevs det manus och den funktionalitet som redan beskrivits ovan för att dra dig sjÀlv i hÄret till ett annat namnomrÄde lades till i dnstap-bgp. PÄ grund av detta mÄste den köras som root eller utfÀrdas till CAP_SYS_ADMIN binÀr via kommandot setcap.

Exempelskript för att skapa namnutrymme

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

fÄgel.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

Som standard, i Ubuntu, Àr den obundna binÀren klÀmd av AppArmor-profilen, som förbjuder den frÄn att ansluta till alla typer av DNSTap-sockets. Du kan antingen ta bort den hÀr profilen eller inaktivera den:

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

Detta bör förmodligen lÀggas till i spelboken. Det Àr naturligtvis idealiskt att korrigera profilen och utfÀrda de nödvÀndiga rÀttigheterna, men jag var för lat.

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

Ladda ner och bearbeta listor

Skript för nedladdning och bearbetning av en lista med IP-adresser
Den laddar ner listan, summerar till prefixet pfx. I dont_add Đž dont_summarize du kan sĂ€ga Ă„t IP-adresserna och nĂ€tverken att hoppa över eller inte sammanfatta. Jag behövde det. undernĂ€tet för min VPS fanns i blockeringslistan 🙂

Det roliga Àr att RosKomSvoboda API blockerar förfrÄgningar med standard Python anvÀndaragent. Det verkar som att manuskillen fattade det. DÀrför Àndrar vi det till Ognelis.

Än sĂ„ lĂ€nge fungerar det bara med IPv4. andelen IPv6 Ă€r liten, men det kommer att vara lĂ€tt att fixa. Om du inte mĂ„ste anvĂ€nda bird6 ocksĂ„.

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 att uppdatera
Jag kör den pÄ kronan en gÄng om dagen, det kanske Àr vÀrt att dra den var fjÀrde timme. detta Àr enligt min mening den förnyelseperiod som RKN krÀver av tillhandahÄllare. Dessutom har de nÄgon annan superbrÄdskande blockering, som kan komma snabbare.

Gör följande:

  • Kör det första skriptet och uppdaterar listan med rutter (rkn_routes.list) för BIRD
  • Ladda om BIRD
  • Uppdaterar och rensar listan över domĂ€ner för dnstap-bgp
  • Ladda om 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

De skrevs utan mycket eftertanke, sÄ om du ser nÄgot som kan förbÀttras - kör pÄ det.

KlientinstÀllningar

HÀr kommer jag att ge exempel pÄ Linux-routrar, men i fallet Mikrotik/Cisco borde det vara Ànnu enklare.

Först stĂ€ller vi in ​​BIRD:

fÄgel.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;
}

SÄledes kommer vi att synkronisera de rutter som tas emot frÄn BGP med kÀrnans routingtabell nummer 222.

Efter det rÀcker det att be kÀrnan att titta pÄ den hÀr plattan innan du tittar pÄ standardplattan:

# 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

Allt, det ÄterstÄr att konfigurera DHCP pÄ routern för att distribuera serverns tunnel-IP-adress som DNS, och schemat Àr klart.

BegrÀnsningar

Med nuvarande algoritm för att generera och bearbeta listan över domÀner innehÄller den bl.a. youtube.com och dess CDN.

Och detta leder till det faktum att alla videor kommer att gÄ via VPN, vilket kan tÀppa till hela kanalen. Kanske Àr det vÀrt att sammanstÀlla en lista över populÀra domÀnuteslutningar som blockerar RKN för tillfÀllet, magen Àr tunn. Och hoppa över dem nÀr du analyserar.

Slutsats

Den beskrivna metoden lÄter dig kringgÄ nÀstan alla blockeringar som leverantörer för nÀrvarande implementerar.

I princip, dnstap-bgp kan anvÀndas för alla andra ÀndamÄl dÀr nÄgon nivÄ av trafikkontroll behövs baserat pÄ domÀnnamnet. TÀnk bara pÄ att i vÄr tid kan tusen sajter hÀnga pÄ samma IP-adress (bakom vissa Cloudflare till exempel), sÄ denna metod har en ganska lÄg noggrannhet.

Men för behoven av att kringgÄ lÄs rÀcker detta.

TillÀgg, redigeringar, pull-förfrÄgningar - vÀlkommen!

KĂ€lla: will.com

LĂ€gg en kommentar