Contourner les verrous ILV avec DNSTap et BGP


Le sujet est assez flou, je sais. Par exemple, il existe un excellent article , mais seule la partie IP de la liste de blocage y est prise en compte. Nous ajouterons également des domaines.


Étant donnĂ© que les tribunaux et l'ILV bloquent tout Ă  droite et Ă  gauche, et les fournisseurs s'efforcent de ne pas tomber sous le coup des amendes infligĂ©es par «Revizorro» - les pertes associĂ©es aux Ă©cluses sont assez importantes. Oui, et parmi les sites bloquĂ©s "lĂ©galement" il y en a de nombreux utiles (bonjour, rutracker)


Je vis en dehors de la juridiction de l'ILV, mais mes parents, parents et amis sont restés à la maison. Il a donc été décidé de trouver un moyen de contourner les verrous qui soit facile pour ceux qui sont loin de l'informatique, de préférence sans leur participation.


Dans cet article, je ne dĂ©crirai pas les choses de base du rĂ©seau par Ă©tapes, mais dĂ©crirai les principes gĂ©nĂ©raux de la façon dont ce schĂ©ma peut ĂȘtre mis en Ɠuvre. La connaissance du fonctionnement du rĂ©seau en gĂ©nĂ©ral et de Linux en particulier est donc indispensable.


Types de serrures


Commençons par actualiser ce qui est bloqué.


Il existe plusieurs types de verrous dans le XML paginé d'ILV:


  • IP
  • Domaine
  • URL

Pour simplifier, nous les réduirons à deux: IP et domaine, et nous retirerons simplement le domaine du blocage d'URL (plus précisément, nous l'avons déjà fait pour nous).


De bonnes personnes de Roskomsvoboda ont mis en Ɠuvre une merveilleuse API grñce à laquelle nous pouvons obtenir ce dont nous avons besoin:



Accéder aux sites bloqués


Pour ce faire, nous avons besoin de petits VPS étrangers, de préférence avec un trafic illimité - il y en a beaucoup de 3 à 5 dollars. Vous devez le prendre dans un proche étranger pour que le ping ne soit pas trÚs grand, mais encore une fois, tenez compte du fait qu'Internet et la géographie ne coïncident pas toujours. Et comme il n'y a pas de SLA pour 5 dollars, il est préférable de prendre 2 piÚces ou plus auprÚs de différents fournisseurs pour la tolérance aux pannes.


Ensuite, nous devons configurer le tunnel chiffré du routeur client au VPS. J'utilise Wireguard comme le plus rapide et le plus facile à configurer depuis J'ai également des routeurs clients basés sur Linux ( APU2 ou quelque chose sur OpenWRT). Dans le cas de certains Mikrotik / Cisco, vous pouvez utiliser des protocoles disponibles sur eux comme OpenVPN et GRE-over-IPSEC.


Identification et rĂ©orientation du trafic d'intĂ©rĂȘt


Vous pouvez, bien entendu, terminer complÚtement tout le trafic Internet via l'étranger. Mais, trÚs probablement, la vitesse de travail avec le contenu local en souffrira grandement. De plus, les exigences de bande passante sur le VPS seront beaucoup plus élevées.


Par consĂ©quent, nous devrons en quelque sorte allouer le trafic aux sites bloquĂ©s et l'envoyer de maniĂšre sĂ©lective au tunnel. MĂȘme si une partie du trafic «supplĂ©mentaire» y arrive, c'est encore mieux que de tout conduire dans un tunnel.


Pour gérer le trafic, nous utiliserons le protocole BGP et annoncerons les itinéraires vers les réseaux nécessaires de notre VPS aux clients. En tant que démon BGP, prenons BIRD, comme l'un des plus fonctionnels et pratiques.


IP


Avec le blocage IP, tout est clair: nous annonçons juste toutes les IP bloquĂ©es avec VPS. Le problĂšme est qu'il y a environ 600 000 sous-rĂ©seaux dans la liste fournie par l'API, et la grande majoritĂ© d'entre eux sont des hĂŽtes / 32. Un tel nombre de routes peut ĂȘtre dĂ©routant pour les routeurs clients faibles.


Par conséquent, il a été décidé de résumer au réseau / 24 lors du traitement de la liste s'il y a 2 hÎtes ou plus. Ainsi, le nombre de routes a été réduit à environ 100 000. Le script pour cela sera le prochain.


Domaines


C'est plus compliqué et il y a plusieurs façons. Par exemple, vous pouvez mettre Squid transparent sur chaque routeur client et effectuer l'interception HTTP et le peeping dans la négociation TLS afin d'obtenir l'URL demandée dans le premier cas et le domaine de SNI dans le second.


Mais en raison de tous les nouveaux TLS1.3 + eSNI, l'analyse HTTPS devient de moins en moins réelle chaque jour. Et l'infrastructure cÎté client devient plus compliquée - vous devrez utiliser au moins OpenWRT.


Par consĂ©quent, j'ai dĂ©cidĂ© de prendre le chemin de l'interception des rĂ©ponses aux requĂȘtes DNS. Ici aussi, tout DNS sur TLS / HTTPS commence Ă  planer au-dessus de nos tĂȘtes, mais nous pouvons (pour l'instant) contrĂŽler cette partie sur le client - le dĂ©sactiver ou utiliser notre propre serveur pour DoT / DoH.


Comment intercepter DNS?


Il peut également y avoir plusieurs approches.


  • Interception du trafic DNS via PCAP ou NFLOG
    Ces deux méthodes d'interception sont implémentées dans l'utilitaire sidmat . Mais il n'a pas été pris en charge depuis longtemps et la fonctionnalité est trÚs primitive, vous devez donc y écrire une liaison de toute façon.
  • Analyse du journal du serveur DNS
    Malheureusement, les récurseurs que je connais ne savent pas comment enregistrer les réponses, mais seulement les demandes. En principe, cela est logique, car contrairement aux demandes, les réponses ont une structure complexe et il est difficile de les écrire sous forme de texte.
  • DNSTap
    Heureusement, beaucoup d'entre eux prennent déjà en charge DNSTap à ces fins.

Qu'est-ce que DNSTap?



Il s'agit d'un protocole client-serveur basĂ© sur des tampons de protocole et des flux de trames pour le transfert d'un serveur DNS vers un collecteur de requĂȘtes et de rĂ©ponses DNS structurĂ©es. En substance, le serveur DNS transmet des mĂ©tadonnĂ©es de demandes et de rĂ©ponses (type de message, IP client / serveur, etc.) ainsi que des messages DNS complets sous la forme (binaire) dans laquelle il travaille avec eux sur le rĂ©seau.


Il est important de comprendre que dans le paradigme DNSTap, le serveur DNS agit en tant que client et le collecteur en tant que serveur. Autrement dit, le serveur DNS se connecte au collecteur, et non l'inverse.


Aujourd'hui, DNSTap est pris en charge par tous les serveurs DNS populaires. Mais, par exemple, BIND dans de nombreuses distributions (comme Ubuntu LTS) est souvent construit pour une raison quelconque sans son support. Donc, nous ne prendrons pas la peine de reconstruire, mais prenons un récursif plus léger et plus rapide - Non consolidé.


Comment attraper DNSTap?


Il existe un certain nombre d' utilitaires CLI pour travailler avec un flux d'événements DNSTap, mais ils ne fonctionnent pas bien pour notre tùche. J'ai donc décidé d'inventer mon propre vélo qui fera tout ce qu'il faut: dnstap-bgp


Algorithme de fonctionnement:


  • Une fois lancĂ©, il charge une liste de domaines Ă  partir d'un fichier texte, les inverse (habr.com -> com.habr), exclut les lignes brisĂ©es, les doublons et les sous-domaines (c'est-Ă -dire si habr.com et www.habr.com sont dans la liste - il sera chargĂ© seulement le premier) et construit un arbre de prĂ©fixes pour une recherche rapide sur cette liste
  • Agissant comme un serveur DNSTap, il attend une connexion du serveur DNS. En principe, il prend en charge les sockets UNIX et TCP, mais les serveurs DNS que je connais ne peuvent utiliser que les sockets UNIX
  • Les paquets DNSTap entrants sont d'abord dĂ©sĂ©rialisĂ©s dans la structure Protobuf, puis le message DNS binaire lui-mĂȘme, situĂ© dans l'un des champs Protobuf, est analysĂ© au niveau des enregistrements DNS RR
  • VĂ©rifie si l'hĂŽte demandĂ© (ou son domaine parent) est dans la liste chargĂ©e; sinon, la rĂ©ponse est ignorĂ©e
  • Seuls A / AAAA / CNAME RR sont sĂ©lectionnĂ©s dans la rĂ©ponse et les adresses IPv4 / IPv6 correspondantes en sont extraites
  • Les adresses IP sont mises en cache avec des TTL personnalisĂ©s et publiĂ©es auprĂšs de tous les homologues BGP configurĂ©s
  • DĂšs rĂ©ception d'une rĂ©ponse indiquant une IP dĂ©jĂ  mise en cache - son TTL est mis Ă  jour
  • AprĂšs l'expiration de TTL, l'enregistrement est supprimĂ© du cache et des annonces BGP

Fonctionnalité supplémentaire:


  • Relire la liste des domaines par SIGHUP
  • Synchronisation du cache avec d'autres instances dnstap-bgp via HTTP / JSON
  • Duplication du cache sur le disque (dans la base de donnĂ©es BoltDB) pour restaurer son contenu aprĂšs un redĂ©marrage
  • Prise en charge du basculement vers un autre espace de noms de rĂ©seau (pourquoi cela sera dĂ©crit ci-dessous)
  • Prise en charge IPv6

Limitations:


  • Domaines IDN non encore pris en charge
  • Peu de paramĂštres BGP

J'ai compilé des packages RPM et DEB pour une installation facile. Devrait fonctionner sur tous les OS relativement récents avec systemd, comme ils n'ont pas de dépendances.


Schéma


Commençons donc à assembler tous les composants ensemble. En conséquence, nous devrions obtenir quelque chose comme cette topologie de réseau:


La logique du travail, je pense, ressort clairement du diagramme:


  • Le client a notre serveur configurĂ© comme DNS, et les requĂȘtes DNS doivent Ă©galement passer par le VPN. Cela est nĂ©cessaire pour que le fournisseur ne puisse pas utiliser l'interception DNS pour bloquer.
  • Lorsque le site est ouvert, le client envoie une requĂȘte DNS de la forme "Quelles sont les adresses IP de xxx.org?"
  • Unbound rĂ©sout xxx.org (ou le prend du cache) et envoie une rĂ©ponse au client «xxx.org a telle ou telle IP», la dupliquant en parallĂšle via DNSTap
  • dnstap-bgp annonce ces adresses dans BIRD par BGP si le domaine est dans la liste des bloquĂ©s
  • BIRD annonce la route vers ces adresses IP avec le routeur next-hop self client du tronçon suivant
  • Les paquets suivants du client vers ces IP passent par le tunnel

Sur le serveur, pour les routes vers les sites bloqués, j'ai une table séparée à l'intérieur de BIRD et elle ne croise pas avec le systÚme d'exploitation.


Il y a un inconvénient à ce schéma: le premier paquet SYN du client aura trÚs probablement le temps de passer par le fournisseur national depuis l'itinéraire n'est pas annoncé instantanément. Et ici, les options sont possibles en fonction de la façon dont le fournisseur effectue le verrouillage. S'il laisse simplement tomber le trafic, il n'y a pas de problÚme. Et s'il le redirige vers un DPI, alors (théoriquement) des effets spéciaux sont possibles.


Des miracles sont également possibles avec des clients qui n'observent pas DNS TTL, ce qui peut conduire le client à utiliser des entrées obsolÚtes de leur cache pourri au lieu de demander Non lié.


En pratique, ni le premier ni le second ne m'ont posé de problÚme, mais votre kilométrage peut varier.


Configuration du serveur


Pour faciliter le roulement, j'ai écrit un rÎle pour Ansible . Il peut configurer à la fois des serveurs et des clients Linux (conçus pour les distributions basées sur deb). Tous les paramÚtres sont assez évidents et sont définis dans l' inventaire.yml . Ce rÎle est supprimé de mon grand livre de jeu, il peut donc contenir des erreurs - les demandes de tirage sont les bienvenues :)


Passons en revue les principaux composants.


BGP


Lors du lancement de deux dĂ©mons BGP sur le mĂȘme hĂŽte, un problĂšme fondamental se pose: BIRD ne souhaite pas augmenter l'homologation BGP avec un hĂŽte local (ou avec une interface locale). Du mot du tout. Googler et lire des listes de diffusion n'a pas aidĂ©, ils prĂ©tendent que c'est par conception. Il y a peut-ĂȘtre un moyen, mais je ne l'ai pas trouvĂ©.


Vous pouvez essayer un autre démon BGP, mais j'aime BIRD et il est utilisé partout avec moi, je ne veux pas produire d'entités.


Par consĂ©quent, j'ai cachĂ© dnstap-bgp Ă  l'intĂ©rieur de l'espace de noms du rĂ©seau, qui est connectĂ© Ă  la racine via l'interface veth: c'est comme un tuyau dont les extrĂ©mitĂ©s dĂ©passent dans diffĂ©rents espaces de noms. À chacune de ces extrĂ©mitĂ©s, nous suspendons des adresses IP p2p privĂ©es qui ne sortent pas de l'hĂŽte, elles peuvent donc ĂȘtre n'importe lesquelles. Il s'agit du mĂȘme mĂ©canisme que celui utilisĂ© pour accĂ©der aux processus Ă  l'intĂ©rieur du Docker bien - aimĂ© et d'autres conteneurs.


Pour cela, un script a Ă©tĂ© Ă©crit et dans dnstap-bgp la fonctionnalitĂ© dĂ©crite ci-dessus pour se glisser par les cheveux dans un autre espace de noms a Ă©tĂ© ajoutĂ©e. Pour cette raison, il doit ĂȘtre exĂ©cutĂ© en tant que root ou renvoyĂ© au binaire CAP_SYS_ADMIN via la commande setcap.


Exemple de script pour créer un espace de noms
 #!/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


Par dĂ©faut, dans Ubuntu, le binaire Unbound est bloquĂ© par le profil AppArmor, ce qui l'empĂȘche de se connecter Ă  n'importe quel socket DNSTap. Vous pouvez soit supprimer ce profil, soit le dĂ©sactiver:


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

Cela devrait probablement ĂȘtre ajoutĂ© au playbook. Il est idĂ©al, bien sĂ»r, de corriger le profil et d'accorder les droits nĂ©cessaires, mais j'Ă©tais trop paresseux.


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 

Téléchargement et traitement des listes


Script de téléchargement et de traitement d'une liste d'adresses IP
Il télécharge la liste, résume avant le préfixe pfx . Dans dont_add et dont_summarize, vous pouvez dire à IP et aux réseaux de sauter ou de ne pas résumer. J'en avais besoin parce que mon sous-réseau VPS était dans la liste de blocage :)


Le plus drÎle, c'est que l'API RosKomSvoboda bloque les demandes avec l'agent utilisateur Python par défaut. On dirait qu'un script kiddy l'a compris. Par conséquent, nous le changeons en Firelis.


Jusqu'à présent, cela ne fonctionne qu'avec IPv4 car IPv6 est petit, mais il sera facile à corriger. Sauf s'il est nécessaire d'utiliser également 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) 

Script Ă  mettre Ă  jour
Ça commence Ă  ma couronne une fois par jour, ça vaut peut-ĂȘtre la peine de la tirer toutes les 4 heures, parce que c'est, Ă  mon avis, la pĂ©riode de mise Ă  jour qu'ILV exige des fournisseurs. De plus, il existe d'autres serrures supplĂ©mentaires urgentes qui peuvent voler plus rapidement.


Fait ce qui suit:


  • ExĂ©cute le premier script et met Ă  jour la liste de routes ( rkn_routes.list ) pour BIRD
  • Recharger BIRD
  • Met Ă  jour et nettoie la liste des domaines pour dnstap-bgp
  • Relocaliser 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 

Ils ont Ă©tĂ© Ă©crits sans trop rĂ©flĂ©chir, donc si vous voyez ce qui peut ĂȘtre amĂ©liorĂ©, allez-y.


Configuration du client


Ici, je vais donner des exemples de routeurs Linux, mais dans le cas de Mikrotik / Cisco, cela devrait ĂȘtre encore plus simple.


Tout d'abord, configurez 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; } 

Ainsi, nous synchroniserons les routes reçues de BGP avec la table de routage du noyau numéro 222.


AprÚs cela, il suffit de demander au noyau de regarder cette plaque avant de regarder la valeur par défaut:


 # 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 

Il ne reste plus qu'Ă  configurer DHCP sur le routeur pour distribuer l'adresse IP du tunnel du serveur en DNS et le schĂ©ma est prĂȘt.


Inconvénients


Avec l'algorithme actuel de création et de traitement d'une liste de domaines, youtube.com et ses CDN y tombent.


Et cela conduit au fait que toutes les vidĂ©os passeront par le VPN, ce qui peut obstruer la chaĂźne entiĂšre. Il vaut peut-ĂȘtre la peine de compiler une liste des domaines d'exception populaires qui sont bloquĂ©s dans l'ILV pour le moment. Et sautez-les pendant l'analyse.


Conclusion


La méthode décrite vous permet de contourner presque tous les verrous que les fournisseurs implémentent actuellement.


En principe, dnstap-bgp peut ĂȘtre utilisĂ© Ă  toute autre fin nĂ©cessitant un certain niveau de contrĂŽle du trafic basĂ© sur un nom de domaine. Gardez Ă  l'esprit que de nos jours, un millier de sites peuvent s'accrocher Ă  la mĂȘme adresse IP (pour certains Cloudflare, par exemple), donc cette mĂ©thode a une prĂ©cision plutĂŽt faible.


Mais pour les besoins de contournement des verrous, cela suffit.


Les ajouts, les modifications et les quĂȘtes de tir sont les bienvenus!

Source: https://habr.com/ru/post/fr467547/


All Articles