
Das Thema ist ziemlich aus dem Bilde, ich weiß. Zum Beispiel gibt es einen ausgezeichneten Artikel , aber dort wird nur der IP-Teil der Sperrliste berücksichtigt. Wir werden auch Domains hinzufügen.
Aufgrund der Tatsache, dass die Gerichte und ILV alles rechts und links blockieren und die Anbieter sich bemühen, nicht unter die von „Revizorro“ verhängten Geldbußen zu fallen, sind die damit verbundenen Verluste aus den Schlössern recht groß. Ja, und unter den "legal" gesperrten Websites gibt es viele nützliche (Hallo, Rutracker)
Ich lebe außerhalb der Gerichtsbarkeit der ILV, aber meine Eltern, Verwandten und Freunde blieben zu Hause. Daher wurde beschlossen, eine Möglichkeit zu finden, um Sperren zu umgehen, die für IT-weit entfernte Personen, vorzugsweise ohne deren Teilnahme, einfach ist.
In diesem Artikel werde ich die grundlegenden Netzwerkelemente nicht schrittweise beschreiben, sondern die allgemeinen Prinzipien, wie dieses Schema implementiert werden kann. Kenntnisse darüber, wie das Netzwerk im Allgemeinen und unter Linux im Besonderen funktioniert, sind daher ein Muss.
Arten von Schlössern
Lassen Sie uns zunächst aktualisieren, was blockiert ist.
Es gibt verschiedene Arten von Sperren in ausgelagertem XML von ILV:
Der Einfachheit halber werden wir sie auf zwei reduzieren: IP und Domain, und wir werden die Domain einfach aus der URL-Blockierung herausziehen (genauer gesagt, wir haben dies bereits für uns getan).
Gute Leute von Roskomsvoboda haben eine wunderbare API implementiert, mit der wir bekommen können, was wir brauchen:
Zugriff auf blockierte Websites
Dazu benötigen wir einige kleine ausländische VPS, vorzugsweise mit unbegrenztem Verkehr - es gibt viele solcher 3-5 Dollar. Sie müssen es im nahen Ausland nehmen, damit der Ping nicht sehr groß ist, aber berücksichtigen Sie auch hier, dass das Internet und die Geografie nicht immer zusammenfallen. Und da es für 5 Dollar keine SLA gibt, ist es aus Gründen der Fehlertoleranz besser, 2+ Teile von verschiedenen Anbietern zu nehmen.
Als nächstes müssen wir den verschlüsselten Tunnel vom Client-Router zum VPS konfigurieren. Ich benutze Wireguard als das schnellste und am einfachsten zu konfigurierende seitdem Ich habe auch Client-Router, die auf Linux basieren ( APU2 oder etwas auf OpenWRT). Bei einigen Mikrotik / Cisco können Sie Protokolle wie OpenVPN und GRE-over-IPSEC verwenden.
Identifizierung und Umleitung des interessierenden Verkehrs
Natürlich können Sie den gesamten Internetverkehr im Ausland vollständig abschließen. Höchstwahrscheinlich wird jedoch die Geschwindigkeit der Arbeit mit lokalen Inhalten stark darunter leiden. Außerdem sind die Bandbreitenanforderungen an den VPS viel höher.
Daher müssen wir blockierten Sites irgendwie Verkehr zuweisen und ihn selektiv an den Tunnel senden. Selbst wenn ein Teil des "zusätzlichen" Verkehrs dort ankommt, ist es immer noch viel besser, als alles durch einen Tunnel zu fahren.
Zur Verwaltung des Datenverkehrs verwenden wir das BGP-Protokoll und geben den Kunden Routen zu den erforderlichen Netzwerken von unserem VPS bekannt. Nehmen wir als BGP-Daemon BIRD als einen der funktionalsten und bequemsten.
IP
Mit der IP-Blockierung ist alles klar: Wir kündigen nur alle blockierten IPs mit VPS an. Das Problem ist, dass die Liste, die die API angibt, ungefähr 600.000 Subnetze enthält und die überwiegende Mehrheit davon / 32 Hosts sind. Eine solche Anzahl von Routen kann für schwache Client-Router verwirrend sein.
Daher wurde beschlossen, bei der Verarbeitung der Liste eine Zusammenfassung zum Netzwerk / 24 zu erstellen, wenn zwei oder mehr Hosts darin enthalten sind. Somit wurde die Anzahl der Routen auf ~ 100.000 reduziert. Das Skript dafür wird als nächstes kommen.
Domänen
Es ist komplizierter und es gibt verschiedene Möglichkeiten. Beispielsweise können Sie jedem Client-Router einen transparenten Squid hinzufügen und im TLS-Handshake HTTP-Interception und Peeping durchführen, um im ersten Fall die angeforderte URL und im zweiten Fall die Domain von SNI abzurufen.
Aufgrund all der neuen TLS1.3 + eSNI wird die HTTPS-Analyse von Tag zu Tag realer. Und die Infrastruktur auf der Client-Seite wird immer komplizierter - Sie müssen mindestens OpenWRT verwenden.
Aus diesem Grund habe ich mich entschlossen, Antworten auf DNS-Abfragen abzufangen. Auch hier steigt jedes DNS-over-TLS / HTTPS über unseren Köpfen auf, aber wir können diesen Teil (vorerst) auf dem Client steuern - entweder deaktivieren oder unseren eigenen Server für DoT / DoH verwenden.
Wie kann ich DNS abfangen?
Es kann auch mehrere Ansätze geben.
- Abfangen des DNS-Verkehrs über PCAP oder NFLOG
Beide Abfangmethoden sind im Dienstprogramm sidmat implementiert. Es wurde jedoch schon lange nicht mehr unterstützt und die Funktionalität ist sehr primitiv. Sie müssen daher trotzdem eine Bindung dazu schreiben. - DNS-Server-Protokollanalyse
Leider wissen die mir bekannten Rekursoren nicht, wie man Antworten protokolliert, sondern nur Anfragen. Im Prinzip ist dies logisch, da Antworten im Gegensatz zu Anfragen eine komplexe Struktur haben und es schwierig ist, sie in Textform zu schreiben. - DNSTap
Glücklicherweise unterstützen viele von ihnen DNSTap bereits für diese Zwecke.
Was ist DNSTap?

Dies ist ein Client-Server-Protokoll, das auf Protokollpuffern und Frame-Streams für die Übertragung von einem DNS-Server an einen Sammler strukturierter DNS-Abfragen und -Antworten basiert. Tatsächlich überträgt der DNS-Server Metadaten von Anforderungen und Antworten (Nachrichtentyp, Client / Server-IP usw.) sowie vollständige DNS-Nachrichten in der (binären) Form, in der er mit ihnen über das Netzwerk arbeitet.
Es ist wichtig zu verstehen, dass im DNSTap-Paradigma der DNS-Server als Client und der Collector als Server fungiert. Das heißt, der DNS-Server stellt eine Verbindung zum Collector her und nicht umgekehrt.
Heute wird DNSTap auf allen gängigen DNS-Servern unterstützt. Aber zum Beispiel wird BIND in vielen Distributionen (wie Ubuntu LTS) oft aus irgendeinem Grund ohne seine Unterstützung erstellt. Wir werden uns also nicht um den Wiederaufbau kümmern, sondern einen leichteren und schnelleren Rekorder verwenden - Ungebunden.
Wie fange ich DNSTap?
Es gibt eine Reihe von CLI-Dienstprogrammen für die Arbeit mit einem Stream von DNSTap-Ereignissen, die jedoch für unsere Aufgabe nicht gut geeignet sind. Also habe ich beschlossen, mein eigenes Fahrrad zu erfinden, das alles kann: dnstap-bgp
Operationsalgorithmus:
- Beim Start wird eine Liste von Domänen aus einer Textdatei geladen, diese invertiert (habr.com -> com.habr), gestrichelte Linien, Duplikate und Subdomänen ausgeschlossen (d. H. Wenn habr.com und www.habr.com in der Liste enthalten sind - wird sie geladen nur die erste) und erstellt einen Präfixbaum für die schnelle Suche in dieser Liste
- Als DNSTap-Server wartet er auf eine Verbindung vom DNS-Server. Im Prinzip werden sowohl UNIX- als auch TCP-Sockets unterstützt, aber die mir bekannten DNS-Server können nur UNIX-Sockets verwenden
- Eingehende DNSTap-Pakete werden zuerst in die Protobuf-Struktur deserialisiert, und dann wird die in einem der Protobuf-Felder befindliche binäre DNS-Nachricht auf die Ebene der DNS-RR-Einträge analysiert
- Überprüft, ob der angeforderte Host (oder seine übergeordnete Domäne) in der geladenen Liste enthalten ist. Andernfalls wird die Antwort ignoriert
- Aus der Antwort werden nur A / AAAA / CNAME RR ausgewählt und die entsprechenden IPv4 / IPv6-Adressen daraus abgerufen
- IP-Adressen werden mit benutzerdefinierten TTLs zwischengespeichert und allen konfigurierten BGP-Peers bekannt gegeben
- Nach Erhalt einer Antwort, die eine bereits zwischengespeicherte IP angibt, wird deren TTL aktualisiert
- Nach Ablauf der TTL wird der Datensatz aus dem Cache und aus BGP-Ankündigungen gelöscht
Zusätzliche Funktionalität:
- Domain-Liste von SIGHUP erneut lesen
- Synchronisieren des Cache mit anderen dnstap-bgp- Instanzen über HTTP / JSON
- Duplizieren des Caches auf der Festplatte (in der BoltDB-Datenbank), um den Inhalt nach einem Neustart wiederherzustellen
- Unterstützung für das Umschalten auf einen anderen Netzwerk-Namespace (warum dies unten beschrieben wird)
- IPv6-Unterstützung
Einschränkungen:
- IDN-Domänen werden noch nicht unterstützt
- Einige BGP-Einstellungen
Ich habe RPM- und DEB- Pakete für eine einfache Installation zusammengestellt. Sollte auf allen relativ neuen Betriebssystemen mit systemd funktionieren, wie Sie haben keine Abhängigkeiten.
Schema
Beginnen wir also mit dem Zusammenbau aller Komponenten. Als Ergebnis sollten wir so etwas wie diese Netzwerktopologie erhalten:

Die Logik der Arbeit, denke ich, geht aus dem Diagramm hervor:
- Der Client hat unseren Server als DNS konfiguriert, und DNS-Abfragen müssen auch über das VPN erfolgen. Dies ist erforderlich, damit der Anbieter die DNS-Überwachung nicht zum Blockieren verwenden kann.
- Wenn die Site geöffnet wird, sendet der Client eine DNS-Abfrage in der Form "Welche IPs hat xxx.org?"
- Ungebunden löst xxx.org auf (oder nimmt es aus dem Cache) und sendet eine Antwort an den Client "xxx.org hat solche und solche IPs", wobei es parallel über DNSTap dupliziert wird
- dnstap-bgp kündigt diese Adressen in BIRD von BGP an, wenn die Domain in der Liste der blockierten Domänen enthalten ist
- BIRD kündigt die Route zu diesen IPs mit dem
next-hop self
Client-Router des next-hop self
- Nachfolgende Pakete vom Client zu diesen IPs durchlaufen den Tunnel
Auf dem Server habe ich für Routen zu blockierten Sites eine separate Tabelle in BIRD, die sich nicht mit dem Betriebssystem überschneidet.
Dieses Schema weist einen Nachteil auf: Das erste SYN-Paket des Clients wird höchstwahrscheinlich seitdem Zeit haben, über den inländischen Anbieter abzureisen Die Route wird nicht sofort angekündigt. Und hier sind Optionen möglich, je nachdem, wie der Anbieter die Sperre macht. Wenn er nur den Verkehr fallen lässt, gibt es keine Probleme. Und wenn er es auf eine DPI umleitet, sind (theoretisch) Spezialeffekte möglich.
Wunder sind auch möglich, wenn Clients DNS-TTL nicht beachten. Dies kann dazu führen, dass der Client einige veraltete Einträge aus seinem faulen Cache verwendet, anstatt Unbound zu fragen.
In der Praxis hat mir weder der erste noch der zweite Probleme bereitet, aber Ihr Kilometerstand kann variieren.
Server-Setup
Um das Rollen zu vereinfachen, habe ich eine Rolle für Ansible geschrieben . Es kann sowohl Server als auch Linux-basierte Clients konfigurieren (entwickelt für deb-basierte Distributionen). Alle Einstellungen sind ziemlich offensichtlich und werden in inventar.yml festgelegt . Diese Rolle wurde aus meinem großen Spielbuch herausgeschnitten, daher kann sie Fehler enthalten - Pull-Anfragen sind willkommen :)
Lassen Sie uns die Hauptkomponenten durchgehen.
BGP
Beim Starten von zwei BGP-Daemons auf demselben Host tritt ein grundlegendes Problem auf: BIRD möchte das BGP-Peering nicht mit einem lokalen Host (oder einer lokalen Schnittstelle) auslösen. Vom Wort überhaupt. Googeln und Lesen von Mailinglisten haben nicht geholfen, sie behaupten, dass es beabsichtigt ist. Vielleicht gibt es einen Weg, aber ich habe ihn nicht gefunden.
Sie können einen anderen BGP-Daemon ausprobieren, aber ich mag BIRD und es wird überall bei mir verwendet. Ich möchte keine Entitäten erstellen.
Deshalb habe ich dnstap-bgp im Netzwerk-Namespace versteckt, der über die veth-Schnittstelle mit dem Root verbunden ist: Es ist wie eine Pipe, deren Enden in einem anderen Namespace herausragen. An jedem dieser Enden hängen wir private p2p-IP-Adressen auf, die nicht außerhalb des Hosts liegen, sodass sie beliebig sein können. Dies ist derselbe Mechanismus, der für den Zugriff auf Prozesse im geliebten Docker und anderen Containern verwendet wird.
Zu diesem Zweck wurde ein Skript geschrieben und in dnstap-bgp die oben beschriebene Funktionalität hinzugefügt, um sich an den Haaren in einen anderen Namespace zu ziehen. Aus diesem Grund muss es als root ausgeführt oder über den Befehl setcap an die Binärdatei CAP_SYS_ADMIN zurückgegeben werden.
Beispielskript zum Erstellen eines Namespace 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
In Ubuntu wird die ungebundene Binärdatei standardmäßig vom AppArmor-Profil geklemmt, wodurch verhindert wird, dass eine Verbindung zu DNSTap-Sockets hergestellt wird. Sie können dieses Profil entweder entfernen oder deaktivieren:
# cd /etc/apparmor.d/disable && ln -s ../usr.sbin.unbound . # apparmor_parser -R /etc/apparmor.d/usr.sbin.unbound
Dies sollte wahrscheinlich zum Playbook hinzugefügt werden. Es ist natürlich ideal, das Profil zu korrigieren und die erforderlichen Rechte zu erteilen, aber ich war zu faul.
ungebunden.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
Download und Listenverarbeitung
Skript zum Herunterladen und Verarbeiten einer Liste von IP-Adressen
Es lädt die Liste herunter und fasst sie vor dem pfx- Präfix zusammen. In dont_add und dont_summarize können Sie IP und Netzwerken anweisen, zu überspringen oder nicht zusammenzufassen. Ich brauchte es, weil Mein VPS-Subnetz war in der Blockliste :)
Das Lustige ist, dass die RosKomSvoboda-API Anforderungen mit dem Standard-Python-Benutzeragenten blockiert. Sieht aus wie ein Drehbuchkind hat es verstanden. Deshalb ändern wir es in Firelis.
Bisher funktioniert es nur mit IPv4, weil IPv6 ist klein, lässt sich aber leicht beheben. Es sei denn, es ist notwendig, auch bird6 zu verwenden.
Zu aktualisierendes Skript
Es beginnt einmal am Tag an meiner Krone, vielleicht lohnt es sich, sie alle 4 Stunden zu ziehen, weil Dies ist meiner Meinung nach der Aktualisierungszeitraum, den ILV von Anbietern benötigt. Außerdem gibt es einige andere besonders dringende Schleusen, mit denen sie schneller fliegen können.
Tut folgendes:
- Führt das erste Skript aus und aktualisiert die
rkn_routes.list
( rkn_routes.list
) für BIRD - BIRD neu laden
- Aktualisiert und bereinigt die Domain-Liste für dnstap-bgp
- Verschieben Sie dnstap-bgp
Sie wurden ohne viel Nachdenken geschrieben. Wenn Sie also sehen, was verbessert werden kann, versuchen Sie es.
Client-Setup
Hier werde ich Beispiele für Linux-Router geben, aber im Fall von Mikrotik / Cisco sollte dies noch einfacher sein.
Konfigurieren Sie zunächst 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; }
Daher werden wir die von BGP empfangenen Routen mit der Kernel-Routing-Tabelle Nummer 222 synchronisieren.
Danach reicht es aus, den Kernel zu bitten, sich diese Platte anzusehen, bevor Sie sich die Standardeinstellung ansehen:
# 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
Sie müssen lediglich DHCP auf dem Router so konfigurieren, dass die Tunnel-IP-Adresse des Servers als DNS verteilt wird und das Schema bereit ist.
Nachteile
Mit dem aktuellen Algorithmus zum Erstellen und Verarbeiten einer Liste von Domains fallen youtube.com
und seine CDNs hinein.
Dies führt dazu, dass alle Videos über das VPN übertragen werden, wodurch der gesamte Kanal verstopft werden kann. Vielleicht lohnt es sich, eine Liste der gängigen Ausnahmedomänen zusammenzustellen, die vorerst in der ILV blockiert sind. Und überspringen Sie sie beim Parsen.
Fazit
Mit der beschriebenen Methode können Sie fast alle Sperren umgehen, die Anbieter derzeit implementieren.
Im Prinzip kann dnstap-bgp für jeden anderen Zweck verwendet werden, bei dem ein bestimmtes Maß an Verkehrssteuerung basierend auf einem Domänennamen erforderlich ist. Denken Sie jedoch daran, dass heutzutage tausend Websites an derselben IP-Adresse hängen können (z. B. für einige Cloudflare), sodass diese Methode eine relativ geringe Genauigkeit aufweist.
Für die Umgehung von Schlössern ist dies jedoch völlig ausreichend.
Ergänzungen, Änderungen, Pull-Quests sind willkommen!