Bypass ILV blocking mei DNSTap en BGP

Bypass ILV blocking mei DNSTap en BGP

It ûnderwerp is frij goed droegen, ik wit it. Bygelyks, der is in poerbêste artikel, mar allinich it IP-diel fan 'e bloklist wurdt dêr beskôge. Wy sille ek domeinen tafoegje.

Troch it feit dat de rjochtbanken en de RKN alles links en rjochts blokkearje, en providers besykje hurd net te fallen ûnder de boetes útjûn troch Revizorro, binne de byhearrende ferliezen fan blokkearjen frij grut. En ûnder de "legitimally" blokkearre siden binne d'r in protte nuttige (hallo, rutracker)

Ik wenje bûten de jurisdiksje fan de RKN, mar myn âlden, sibben en freonen bliuwe yn myn heitelân. Sa waard besletten om in maklike manier te betinken foar minsken fier fan IT om it blokkearjen om te gean, leafst sûnder har dielname.

Yn dizze notysje, Ik sil net beskriuwe basis netwurk dingen stap foar stap, mar sil beskriuwe de algemiene prinsipes fan hoe't dit skema kin wurde útfierd. Sa kennis fan hoe't it netwurk wurket yn it algemien en yn Linux yn it bysûnder is in must.

Soarten slûzen

Litte wy earst ús ûnthâld ferfarskje oer wat wurdt blokkearre.

D'r binne ferskate soarten slûzen yn 'e ynladen XML fan RKN:

  • IP
  • Domein
  • URL

Foar ienfâld sille wy se ferminderje nei twa: IP en domein, en fan blokkearjen troch URL sille wy it domein gewoan útlûke (of leaver, dit is al foar ús dien).

Goede minsken út Roskomsvoboda útfierd in prachtich API, wêrmei wy kinne krije wat wy nedich binne:

Tagong ta blokkearre siden

Om dit te dwaan, hawwe wy wat lytse bûtenlânske VPS nedich, leafst mei ûnbeheind ferkear - d'r binne in protte fan har foar 3-5 dollar. Jo moatte it keapje yn 'e buert bûtenlân, sadat de ping net te heech is, mar hâld der nochris yn' e hichte dat it ynternet en geografy net altyd gearfalle. En om't d'r gjin SLA is foar 5 dollar, is it better om 2+ stikken te nimmen fan ferskate oanbieders foar skuldtolerânsje.

Dêrnei moatte wy in fersifere tunnel ynstelle fan 'e client-router nei de VPS. Ik brûk Wireguard as de rapste en maklikste te konfigurearjen, om't ... Myn client-routers binne ek basearre op Linux (APU2 of wat op OpenWRT). Yn it gefal fan guon Mikrotik / Cisco kinne jo de beskikbere protokollen brûke lykas OpenVPN en GRE-over-IPSEC.

Identifikaasje en omlieding fan ferkear fan belang

Jo kinne fansels alle ynternetferkear stopje om nei it bûtenlân te gean. Mar, nei alle gedachten, de snelheid fan wurkjen mei lokale ynhâld sil gâns lije ûnder dit. Plus, de easken foar bânbreedte op in VPS sille folle heger wêze.

Dêrom sille wy it ferkear op ien of oare manier moatte isolearje nei blokkearre siden en selektyf routerje yn 'e tunnel. Sels as guon fan 'e "ekstra" ferkear dêr komt, is it noch folle better as alles troch de tunnel ride.

Om ferkear te behearjen, sille wy it BGP-protokol brûke en rûtes advertearje nei de nedige netwurken fan ús VPS nei kliïnten. Litte wy BIRD nimme as in BGP-daemon, om't it ien fan 'e meast funksjonele en handige is.

IP

Alles is dúdlik mei IP-blokkering: wy kundigje gewoan alle blokkearre IP's fan VPS oan. It probleem is dat d'r sawat 600 tûzen subnets binne yn 'e list levere troch de API, en de grutte mearderheid fan har binne / 32 hosts. Dit oantal rûtes kinne swakke client routers betize.

Dêrom waard by it ferwurkjen fan de list besletten om it /24-netwurk op te rekkenjen as d'r 2 of mear hosts yn binne. Sa waard it oantal rûtes fermindere nei ~100 tûzen. It skript hjirfoar sil folgje.

Domeinen

It is yngewikkelder en d'r binne ferskate manieren. Jo kinne bygelyks transparante Squid op elke client-router ynstallearje en HTTP dêr ûnderskeppe en in TLS-handshake spionearje om de frege URL yn it earste gefal te krijen en it domein fan SNI yn it twadde.

Mar troch alle nijmoadrige TLS1.3 + eSNI, wurdt HTTPS-analyze elke dei minder en minder realistysk. En de ynfrastruktuer oan 'e kant fan' e kliïnt wurdt yngewikkelder - jo moatte op syn minst OpenWRT brûke.

Dêrom besleat ik it paad te nimmen om antwurden op DNS-fragen te ûnderskeppen. Ek hjir begjinne allerhande DNS-over-TLS/HTTPS oer ús hollen te sweeven, mar wy kinne (foar no) dit diel op 'e client kontrolearje - of it útskeakelje of ús eigen server brûke foar DoT/DoH.

Hoe DNS te kapjen?

D'r kinne hjir ek ferskate oanpak wêze.

  • DNS-ferkear ûnderskeppe fia PCAP of NFLOG
    Beide fan dizze ûnderskeppingsmetoaden wurde ymplementearre yn it nut sidmat. Mar it is in lange tiid net stipe en de funksjonaliteit is heul primityf, dus jo moatte der noch in bining foar skriuwe.
  • DNS-tsjinner log analyse
    Spitigernôch, de recursors Ik wit net witte hoe te loggen antwurden, mar allinnich fersiken. Yn prinsipe is dit logysk, om't, yn tsjinstelling ta oanfragen, antwurden in komplekse struktuer hawwe en it is lestich om se yn tekstfoarm te skriuwen.
  • DNSTap
    Gelokkich stypje in protte fan harren al DNSTap foar dizze doelen.

Wat is DNSTap?

Bypass ILV blocking mei DNSTap en BGP

Dit is in client-tsjinner protokol basearre op Protocol Buffers en Frame Streams om strukturearre DNS-fragen en antwurden oer te dragen fan in DNS-tsjinner nei in samler. Yn essinsje stjoert de DNS-tsjinner fersyk- en antwurdmetadata (berjochttype, client / tsjinner IP, ensfh.) plus folsleine DNS-berjochten yn 'e (binêre) foarm wêryn't it mei har wurket oer it netwurk.

It is wichtich om te begripen dat yn it DNSTap-paradigma de DNS-tsjinner fungearret as in kliïnt, en de samler fungearret as tsjinner. Dat is, de DNS-tsjinner ferbynt mei de samler, en net oarsom.

Tsjintwurdich wurdt DNSTap stipe yn alle populêre DNS-tsjinners. Mar bygelyks BIND yn in protte distribúsjes (lykas Ubuntu LTS) wurdt faak om ien of oare reden kompilearre sûnder syn stipe. Dat litte wy ús net bemuoie mei werbouwen, mar litte wy in lichtere en rappere rekursor nimme - Unbound.

Hoe kinne jo DNSTap fange?

der binne guon количество D'r binne CLI-hulpprogramma's foar it wurkjen mei de stream fan DNSTap-eveneminten, mar se binne net geskikt foar it oplossen fan ús probleem. Dat ik besleat om myn eigen fyts út te finen, dy't alles sil dwaan wat nedich is: dnstap-bgp

Wurk algoritme:

  • As it wurdt lansearre, laadt it in list mei domeinen út in teksttriem, feroaret se (habr.com -> com.habr), slút brutsen rigels, duplikaten en subdomeinen út (dat wol sizze as de list habr.com en www.habr.com befettet, it sil allinich de earste laden wurde) en bout in foarheakselbeam foar fluch sykjen fia dizze list
  • As DNSTap-tsjinner fungearret, wachtet it op in ferbining fan 'e DNS-tsjinner. Yn prinsipe stipet it sawol UNIX- as TCP-sockets, mar de DNS-tsjinners dy't ik ken stypje allinich UNIX-sockets
  • Ynkommende DNSTap-pakketten wurde earst deserialisearre yn in Protobuf-struktuer, en dan wurdt it binêre DNS-berjocht sels, leit yn ien fan 'e Protobuf-fjilden, parsed nei it nivo fan DNS RR-records
  • It wurdt kontrolearre oft de frege host (of syn âlder domein) is yn de laden list as net, it antwurd wurdt negearre
  • Allinich A/AAAA/CNAME RR's wurde selektearre út it antwurd en de korrespondearjende IPv4/IPv6-adressen wurde derút ekstrahearre
  • IP-adressen wurde yn 't cache bewarre mei in konfigurearbere TTL en advertearre oan alle konfigureare BGP-peers
  • By it ûntfangen fan in antwurd dat ferwiist nei in al yn 'e cache IP, wurdt syn TTL bywurke
  • Nei't de TTL ferrint, wurdt de yngong fuortsmiten fan 'e cache en fan BGP-oankundigingen

Oanfoljende funksjonaliteit:

  • De list mei domeinen opnij lêze troch SIGHUP
  • Syngronisearje cache mei oare eksimplaren dnstap-bgp fia HTTP/JSON
  • De cache op skiif duplisearje (yn 'e BoltDB-database) om de ynhâld te herstellen nei in trochstart
  • Stipe foar it wikseljen nei in oare netwurknammeromte (wêrom dit nedich is sil hjirûnder beskreaun wurde)
  • IPv6-stipe

Beheinings:

  • IDN-domeinen wurde noch net stipe
  • In pear BGP ynstellings

Ik sammele RPM en DEB pakketten foar maklike ynstallaasje. Moat wurkje oan alle relatyf resinte OS's mei systemd, om't ... se hawwe gjin ôfhinklikens.

De regeling

Dus, litte wy begjinne mei it gearstallen fan alle komponinten tegearre. As resultaat moatte wy sa'n ding krije as dizze netwurktopology:
Bypass ILV blocking mei DNSTap en BGP

De logika fan it wurk, tink ik, is dúdlik út it diagram:

  • De kliïnt hat ús tsjinner konfigureare as in DNS, en DNS-oanfragen moatte ek fia de VPN gean. Dit is nedich sadat de provider DNS-ûnderskepping net brûke kin om te blokkearjen.
  • As in kliïnt in webside iepenet, stjoert it in DNS-fersyk lykas "wat IP hat xxx.org?"
  • Fallen lost xxx.org op (of nimt it út 'e cache) en stjoert in antwurd nei de kliïnt "xxx.org hat sa'n en sa'n IP", tagelyk duplikearje it fia DNSTap
  • dnstap-bgp advertearret dizze adressen yn FÛGEL fia BGP as it domein op 'e blokkearre list stiet
  • FÛGEL advertearret in rûte nei dizze IPs mei next-hop self client router
  • Opfolgjende pakketten fan 'e kliïnt nei dizze IP's geane troch de tunnel

Op de tsjinner brûk ik in aparte tabel binnen BIRD foar rûtes nei blokkearre siden en it krúst op gjin inkelde manier mei it OS.

D'r is in neidiel yn dit skema: it earste SYN-pakket fan 'e klant sil nei alle gedachten tiid hawwe om troch de ynlânske provider te gean, om't De rûte wurdt net daliks oankundige. En hjir binne d'r mooglike opsjes ôfhinklik fan hoe't de provider it blokkearjen docht. As er gewoan ferkear delset, dan is der gjin probleem. En as it trochferwiist nei wat DPI, dan binne (teoretysk) spesjale effekten mooglik.

Wûnders binne ek mooglik mei kliïnten dy't de DNS TTL net respektearje, wat kin liede ta de kliïnt mei help fan wat ferâldere records út syn rotte cache ynstee fan te freegjen Unbound.

Yn 'e praktyk feroarsake noch de earste noch de twadde problemen foar my, mar jo kilometers kinne ferskille.

Tsjinner Tuning

Foar it gemak fan útrol, skreau ik rol foar Ansible. It kin sawol servers as kliïnten konfigurearje basearre op Linux (ûntworpen foar deb-basearre distribúsjes). Alle ynstellingen binne frij dúdlik en binne ynsteld inventory.yml. Dizze rol is ôfsnien út myn grutte playbook, dus it kin flaters befetsje - pull fersiken Wolkom :)

Lit ús gean troch de wichtichste komponinten.

BGP

By it útfieren fan twa BGP-daemons op deselde host, ûntstiet in fûnemintele probleem: BIRD wol gjin BGP-peering ferheegje mei de localhost (of mei elke lokale ynterface). Fan it wurd absolút. It googlejen en it lêzen fan mailinglisten hat net holpen, se beweare dat it troch ûntwerp is. Der kin in manier wêze, mar ik haw it net fûn.

Jo kinne besykje in oare BGP daemon, mar ik hâld fan BIRD en ik brûk it oeral, Ik wol net meitsje mear entiteiten.

Dêrom haw ik dnstap-bgp ferburgen yn 'e netwurknammeromte, dy't ferbûn is mei de root fia de veth-ynterface: it is as in piip, wêrfan de úteinen yn ferskate nammeromten stekke. Oan elk fan dizze einen heakje wy privee p2p IP-adressen ta dy't net boppe de host geane, sadat se alles kinne wêze. Dit is itselde meganisme dat wurdt brûkt om tagong te krijen ta prosessen yntern elkenien syn favorite Docker en oare konteners.

Dit wie wêrom it waard skreaun skrift en de al beskreaune boppesteande funksjonaliteit fan slepen dysels by it hier nei in oare nammeromte waard tafoege oan dnstap-bgp. Hjirtroch moat it wurde útfierd as root of jûn wurde oan de CAP_SYS_ADMIN-binêre fia it setcap-kommando.

Foarbyld skript foar it meitsjen fan nammeromte

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

Standert, yn Ubuntu, wurdt de Unbound-binêr beklamme mei in AppArmor-profyl, wat it ferbiedt om te ferbinen mei alle DNSTap-sockets. Jo kinne dit profyl wiskje of it útskeakelje:

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

Dit moat wierskynlik tafoege wurde oan it playbook. It soe ideaal wêze, fansels, om it profyl te korrigearjen en de nedige rjochten út te jaan, mar ik wie te lui.

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

Ynladen en ferwurkjen fan listen

Skript foar it downloaden en ferwurkjen fan in list mei IP-adressen
It downloadt de list, gearfettet nei it foarheaksel pfx. de dont_add и dont_summarize jo kinne de IP's en netwurken fertelle dy't moatte wurde oerslein of net gearfette. Ik hie dit nedich om't ... myn VPS-subnet stie op 'e bloklist :)

It grappige is dat de RosKomSvoboda API oanfragen blokkearret mei de standert Python-brûkersagent. It liket derop dat se it skript kiddy krigen. Dêrom feroarje wy it nei Ognelis.

Foar no wurket it allinich mei IPv4, om't ... IPv6-diel is lyts, mar it sil maklik te reparearjen wêze. Behalve as jo ek fûgel6 moatte brûke.

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 foar fernijing
Ik rin it ien kear deis troch de kroan, miskien is it de muoite wurdich om it ien kear yn 'e 4 oeren te rinnen, om't ... Dit is neffens my de fernijingsperioade dy't RKN fereasket fan oanbieders. Plus, se hawwe wat oare super-urgent blokkearingen dy't rapper kinne oankomme.

Docht it folgjende:

  • Rint it earste skript út en fernijt de list mei rûtes (rkn_routes.list) foar BIRD
  • Reload BIRD
  • Updates en skjinmeitsje de list mei domeinen foar dnstap-bgp
  • Ferfarskje 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

Se binne skreaun sûnder folle gedachte, dus as jo wat sjogge dat ferbettere wurde kin, gean dan derfoar.

Client opset

Hjir sil ik foarbylden jaan foar Linux-routers, mar yn it gefal fan Mikrotik/Cisco moat it noch ienfâldiger wêze.

Stel earst BIRD yn:

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

Op dizze manier sille wy de rûtes dy't ûntfongen binne fan BGP syngronisearje mei de kernel-routingtabel nûmer 222.

Hjirnei is it genôch om de kernel te freegjen om nei dizze tabel te sjen foardat jo nei de standert sjogge:

# 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

Dat is it, alles wat oerbliuwt is om DHCP op 'e router te konfigurearjen om it tunnel-IP-adres fan' e tsjinner as DNS te fersprieden en it skema is klear.

Nijsberjochten

Mei it hjoeddeiske algoritme foar it generearjen en ferwurkjen fan de list mei domeinen, befettet it û.o. youtube.com en syn CDN's.

En dit liedt ta it feit dat alle fideo's wurde stjoerd fia de VPN, dy't it heule kanaal kinne ferstoppe. It kin de muoite wurdich wêze om in list te kompilearjen mei populêre útsûnderingsdomeinen dy't RKN noch te swak is om te blokkearjen. En oerslaan se by it parsearjen.

konklúzje

De beskreaune metoade lit jo hast elke blokkearje omgean dy't providers op it stuit implementearje.

Yn prinsipe dnstap-bgp kin brûkt wurde foar alle oare doelen wêr't in bepaald nivo fan ferkearsbehear basearre op in domeinnamme nedich is. Jo moatte gewoan rekken hâlde dat tsjintwurdich tûzen siden op itselde IP-adres hingje kinne (efter guon Cloudflare, bygelyks), dus dizze metoade hat nochal lege krektens.

Mar foar de behoeften fan it omgean fan blokkearjen is dit genôch.

Tafoegings, bewurkings, pull-oanfragen binne wolkom!

Boarne: www.habr.com

Add a comment