Posts Tagged ‘Networking’
Zensursula: Teil 2 – Cleanfeed, DNS, DPI
Die mit Lügen und Erpressung der Provider gegen alle Vernunft durchgepeitschte, grundgesetzwidrige unkontrollierbare deutsche Zensurinfrastruktur wird gerade vom “zuständigen” BKA in aller Heimlichkeit geplant und wird genauso heimlich von den Providern implementiert werden. Das die erstmals angedachten DNS-Sperren vollständig wirkungslos sind, darüber sind sich wohl alle einig, genauso eindeutig ist es wohl das die DNS-Sperren nur den Einstieg hin zur Schaffung eines ausgefeilten Zensursystems mit Vorbild der Great Firewall of China sein wird. Schon jetzt vermuten einige das ein Cleanfeed Modell nach britischen Vorbild geplant ist.
Die Befristung auf 3 Jahre hilft natürlich auch nicht, entweder nach 3 Jahren stellt sich heraus, das es nur wenig gegen “Kinderpornographie” geholfen hat, dann muss noch mehr und tief greifender gesperrt werden, oder die Verbrechensstatistik (die im übrigen ohnehin vom BKA “erstellt” wird) geht zurück, dann war es ein Erfolg und muss genauso weitergeführt werden.

Cleanfeed - Bildquelle: Wikimedia Commons
Das Cleanfeed System wird von Providern in England eingesetzt um z.B.: bestimmte Wikipedia Artikel zu blockieren. Welche wahrscheinlich regimekritischen Seiten noch so alles gesperrt werden weiß man natürlich nicht, da die geheimen Listen(der IWF), natürlich nicht unabhängig kontrolliert werden. Cleanfeed filtert nach der IP und URL, was durch eine Kombination aus konventionellen IP-Filtern und Proxy-Servern ermöglicht wird. Zunächst wird der Traffic nur nach IP-Adressen gefiltert, bestimmte Verbindungen werden schon hier blockiert, andernfalls wird der fragwürdige Traffic durch ein Arsenal an transparenten Proxy-Servern geleitet(Man-in-the-middle-Angriff auf HTTP) die mit einer Blacklist ausgerüstet bestimmte URLs blockieren.
In China z.B. wird noch einen Schritt weiter gegangen, so wird jedes IP-Paket von DPI-Hardware genau untersucht, enthält es unerwünschte Suchbegriffe oder Inhalte wird von dem zensierenden Backbone TCP-RST-Pakete gesendet, die so die fragliche TCP-Verbindung sofort beendet. So implementiert die chinesische Suchmaschine Baidu dies bereits auf Server-Seite. Wer auf Baidu.com nach “Falun Gong” sucht, dessen Verbindung wird für einige Minuten gesperrt.
Beim Deep Packet Inspection wird jedes vorbeikommende Paket auseinandergenommen, so kann beispielsweise festgestellt werden ob es sich um eine HTTP Verbindung handelt und welche URL angefordert wird oder welche Daten gesendet werden. Das allein ist natürlich ein krasser verstoß gegen die Netzneutralität sowie gegen jedes noch so aufgeweichtes Fernmeldegeheimnis. Zum Vergleich, das wäre wie wenn die Post jeden Brief unbemerkt öffnet und nach bestimmten Stichworten durchsucht. Wenn es schon unbedingt DPI seien muss, dann wenigstens Open Source, dachten sich wahrscheinlich die Entwickler des OpenDPI Projektes
Im letzten Zensursula-Artikel habe ich mich mit den DNS-Filtern beschäftigt, insbesondere wie man einen eigenen DNS-Cache-Server betreibt der die Zensur über DNS verhindert. Wie erwähnt handelt es sich dabei nur um den Einstieg, die Einführung von Cleanfeed/DPI kann die Zensur wieder akut werden lassen, selbst mit eigenem DNS-Server. Wie es technisch geht hat jüngst Vodafone in ihrem UMTS Netz gezeigt, sie fangen jede Anfrage über Port 53 ab und leiten sie an ihre eigenen DNS-Server weiter.
Das Einzige wirksame Mittel gegen diese fortgeschrittenen Zensur Bemühungen, ist es den eigenen Traffic möglichst zu verschleiern, im einfacheren Fall seinen Traffic verschlüsselt über Rechner im Ausland zu leiten, bspw. über HTTP oder Socks4/5-Proxy-Server. Die Meisten Zensur-Regime sperren deshalb ebenfalls bekannte Ausländische Proxy bzw. Anonymisierungs-Dienste(Socks, VPN-Dienstleister oder Tor-Nodes) auf IP-Ebene.
Mittlerweile gibt es eine ganze Flut von VPN-Providern die bezahlte Zugänge zu Ausländischen VPN-Servern bereitstellen, Ivacy war hier auch schon Thema. Explizit erwähnen will ich hier außerdem Perfect-Privacy die zwar etwas teurer sind, aber dafür sehr schnell und Zugriff zu über 20 weltweit verteilten Servern bieten.
Auf FileShareFreak und Daten-Speicherung.de gibt es Listen von VPN-Providern. Wem es statt einer Zensur zu umgehen, um wirkliche Anonymität geht, reichen diese Anbieter nicht aus. Nur ein Onion Routing kann wirkliche Anonymität gewährleisten, z.B.: Tor oder JAP/JonDo. Diese haben natürlich den Nachteil, extrem Langsam und unzuverlässig zu sein. Daneben gibt es mit Xerobank einen Bezahl-Anbieter für schnelles Onion Routing.
Update: Auf ZDNet gibt es einen guten Artikel darüber, wie weit die DPI-Manipulationen bei den UMTS-Anbietern, wie Vodafone mittlerweile gehen. (via Netzpolitik)
Tagged: Networking, privacy, security, vpn
implementing bittorrent – DHT (teil 3)
Eigentlich wollte ich ja was über den BitTorrent Message-Flow schreiben, aber aus aktuellem Anlass gibt es heute einen “kleinen” Artikel über DHT.
DHT
Aus gegebenem Anlass schreibe ich nun etwas früher als geplant über DHT. Die ThePirateBay-Tracker sind nun schon etwas länger Down, es sind zwar etliche Ersatz-Tracker aus dem Boden gesprossen, aber meiner Meinung nach ist das dezentrale Tracking nun an der Reihe. Die Tracker waren bis jetzt einer der grössten Angriffs/Schwachpunkte der BitTorrent Technologie/ des BitTorrent Protokolls.
Doch das muss nicht so sein, denn es gibt ja DHT (BEP005). Ich will mich hier mal etwas näher mit DHT beschäftigen und das DHT Protokoll näher erklären.
Die Technologie hinter DHT im BitTorrent-Protokoll basiert auf Kademlia. Kademlia wurde von Petar Maymounkov und David Mazières entwickelt und “implementiert” bzw spezifiziert Distributed Hashtables in P2P-Netzen. Verschaffen wir uns erstmal einen kleinen Überblick über Kademlia.
BEP005 spezifiziert das die Daten per UDP übertragen werden. Zuerst generiert der Client eine Node ID, diese wird genauso wie der BitTorrent Infohash errechnet, bzw nutzt den selben Bit-raum (160Bit). Danach beginnt das Bootstrapping, der Client muss sich ja erstmal im DHT zurechtfinden und einen anderen Client finden dieser Teilt dann weitere IPs mit. Meist ist die erste Node “router.bittorrent.com” da ein Scannen durch die eigene IP-Range oder willkürliches suchen nach anderen Nodes nicht so erfolgversprechend ist.
Zur Indizierung von BitTorrent-Hashes wie es ein Tracker macht trägt bei DHT jeder Peer/Node bei.
Wenn wir nun einen bestimmten Hash suchen kann die Entfernung zu diesem Hash ausgerechnet werden. Dafür werden entweder Node IDs und Node IDs verglichen, oder Infohashes und Node IDs, durch den “Algorithmus” lässt sich die “nähe” der Node ID zur gesuchten ID (Infohash oder Node ID) errechnen. Die Routing Tabelle die der Client nun erstellt wird immer detaillierter je näher wir an den gesuchten ID-Wert kommen und die Node mit der gewünschten Information gefunden haben. Jede Node hat “Kontaktdaten” zu den Nodes mit “nahen” IDs.
Die Distanz zwischen 2 IDs wird per XOR berechnet:
distanz(A,B) = |A xor B|
Je kleiner das Ergebnis desto näher Liegen sich A und B.
Wenn nun eine Node (im DHT) Peers (für BitTorrent) finden will passiert folgendes:
Ich gehe davon aus das das Bootstrapping schon fertig ist, wir also ein Paar Nodes schon in unserer Routing-Tabelle haben. Unser Client nimmt nun den Infohash aus der Torrent-File. Wir nehmen Beispielsweise den Hash
362b0a1151013916896a9c98b52e0ead803c4ac3 (ubuntu-7.10-alternate-hppa.iso). Unser Client wird die Node mit dem geringstem Abstand zum Infohash nun Kontaktieren und diese Node nach Peer-Kontaktdaten Fragen. Wenn diese Node Peer-Kontaktdaten besitzt werden diese zu unserem Client übermittelt und dieser baut dann über das BitTorrent-Protokoll eine Verbindung zum Peer auf. Wenn die Node keine Peer-Kontaktdaten hat wird sie uns Kontaktdaten zu den Nodes aus ihrer Routing-Tabelle geben die am Nächsten an unserer ID liegen, und so weiter und so fort!
Die Antwort der Nodes auf die Anfrage nach Peers zu einem Infohash beinhaltet immer einen “token”. Wenn wir nun dem Node von dem wir die Peer-Kontaktdaten bekommen haben mitteilen wollen (wie beim Tracker ein sogenannter “announce”), müssen wir dem Node neben dem Announce auch den Token schicken den wir zuvor
von ihm erhalten haben.
Es liegt auf der Hand das dies eine Sicherheitsmaßnahme ist, damit nicht irgendwelche unbekannten Hosts (Bots von der MI) den DHT verseuchen. Die BEP005 spezifiziert das die Tokens alle 5 Minuten neu generiert werden, sie bestehen aus einem SHA1-Hashes auf die IP Adresse verknüpft mit einem Salt (welches alle 5 Minuten wechselt).
Routing
Kommen wir nun zum Aufbau der Routing Tabelle unseres Nodes. Die Routing Tabelle ist beinhaltet alle Bekannten Nodes die noch errechbar sind (das wird in einem Zeitraum von 15 Minuten getan) und diese Nodes dienen als Startpunkte für neue anfragen im DHT.
Die Nodes in unserer Routing Tabelle werden je nach ihrer Erreichbarkeit eingestuft. Die Erreichbarkeit jeder Node wird alle 15 Minuten überprüft. Eine Node wird als “good” eingestuft wenn sie uns eine Anfrage geschickt oder beantwortet hat innerhalb der letzten 15 Minuten. Wenn eine Node innerhalb von 15 Minuten nicht aktiv war wird sie “questionable” also Fragwürdig eingestuft. Ein Node wird als “bad” eingestuft wenn er auf mehrere Anfragen nicht geantwortet hat. Unsere Routing-Tabelle sollte nur “good”-Einträge enthalten.
Die Routing Tabelle deckt den kompletten Raum an möglichen IDs ab (von 0 bis zu 2^160). Die Routing-Tabelle ist in “Buckets” (Eimer) unterteilt. Eine leere Routing-Tabelle enthält einen Bucket mit dem ID-Raum von 0 (min) bis 2^169 (max). Wenn wir nun eine Node mit der hypothetischen ID “A” (normal ist die ID natürlich 20byte lang wie beim Infohash) dann wird diese in einen Bucket eingefügt der min < A < max ist. Also in einem Bereich bei dem
min kleiner als A ist und A kleiner als max ![]()
In einer leeren Routing-Tabelle ist nur ein Bucket also passen in diesen Bucket alle möglichen IDs rein. Allerdings kann ein Bucket nur K verschiedene Einträge enthalten, im Moment ist K=8. Wenn der Bucket voll mit “good”-Nodes ist, werden keine Nodes mehr hinzugefügt – AUßER die eigene Node ID fällt in den Bereich, in diesem Fall wird der Bucket durch zwei neue Buckets ersetzt und die Nodes aus dem Vorherigem Bucket werden auf die zwei neuen Buckets aufgeteilt. Diese zwei Buckets könnten bei einer Routing-Tabelle mit nur einem Bucket dann jeweils die Bereiche vor und nach unserer ID abdecken (min/max werte).
Jeder Bucket sollte (das ist natürlich jedem selbst überlassen, wenn man es denn Implementiert) eine “last changed” Eigenschaft haben um die “frische” des Buckets ablesen zu können. Auch hier sollte alle 15 Minuten die Erreichbarkeit der enthaltenen Nodes überprüft werden. Laut BEP005 wird dies folgendermaßen gemacht:
Eine zufällig ausgewählte ID aus dem Bereich des Buckets (min/max) wird mit einer “find_nodes” (dazu weiter unten im Protokoll-Bereich mehr) Anfrage kontaktiert – bei Antwort ist die Node noch zu gebrauchen, wenn
nicht sollte die Node aus dem Bucket entfernt werden. Wenn eine Node Anfragen von anderen Nodes nicht beantworten kann, z.B. wegen schlechten Router-Settings, dann sollte Sie ihre Buckets öfter Auffrischen als eine Node die auf Anfragen antworten kann, den eine solche Node erhält ja eh immer wieder neue Node IDs.
Die Node sollte zudem versuchen ihr selbst nahe liegende Nodes zu finden.
BitTorrent Protokoll
Wenn unser BitTorrent-Client DHT unterstützt, wird bei den Protokoll-Flags im Handshake das letzte Byte gesetzt. Wenn nun ein anderer Peer uns beim Handshake das er DHT Supported, senden wir ihm mit der PORT-Message des BitTorrent-Protokolls unseren UDP-Port auf dem unsere DHT-Implementierung lauscht. Die DHT-Implementierung Pingt dann die neue Node und wenn eine Antwort kommt wird diese nach den oben definierten Regeln in einen Bucket eingefügt oder auch nicht (bei keiner Antwort).
Torrent File
Die Torrent-File enthält keine “announce”-URL mehr, sondern einen “nodes”-Key. Dieses Nodes Dictionary enthält die K (K=8) nähsten bekannten Nodes von dem Client der die .torrent-File erstellt hat. Oder halt eine Liste mit K bekannten “good”-Nodes. Das Nodes-Dictionary ist wie folgt aufgebaut:
nodes = [["",], ["",], ...] nodes = [["127.0.0.1", 6881], ["your.router.node", 4804]]
Protokolle
Kademlia RPC Protololl
KRPC ist relativ schnelle und einfach erklärt. Die Einzelnen Messages sind wie bei BitTorrent üblich BEncoded. Auf einen Request kommt eine Antwort/Response. Es gibt drei Message-Typen: query, reponse und error.
Beim DHT-Protokoll sind es vier: ping, find_node, get_peers und announce_peer. Eine KPRC-Message besteht aus einem Dictionary mit zwei Keys, sowie zusätzlich je nach Message-Typ zusätzliche Felder.
Der Key “t” beinhaltet die “transaction id”, die “tansaction id” wird beim Query errechnet und dient dazu Anfragen und Antworten zuzuordnen. Sie besteht meistens nur aus 2 Buchstaben, da diese vollkommen ausreichen um eine große Anzahl von Anfragen abzudecken.
Der andere Key ist “y” und beinhaltet als Wert nur einen einzigen Buchstaben:
- q: query
- r: response
- e: error
Um die Kontaktdaten von Peers zu übertragen werden diese Kodiert. Hier kommt die selbe Kodierung wie beim Compact-Encoding bei BitTorrent zum Einsatz, ein 6-Byte String – wobei die ersten 4 Byte die IP repräsentieren und die letzten 2 den Port.
Um die Kontaktdaten von anderen Nodes zu übertragen werden diese ebenfalls Kodiert, dies geschieht jedoch mit dem “Compact Node Encoding”. Hier ist es ein 26-Byte String. Die ersten 20byte enthalten die Node ID die restlichen 6 sind die Compact-Encodierte IP und der Port wie oben.
Queries/Anfragen
Der “y” Key enthält als Wert “q” wie weiter oben schon erklärt. Zusätzlich noch die die zwei Keys “a” und “q”.
- q: enthält den Methodennamen des Queries (DHT Protokoll z.B. Ping)
- a: enthält die Argumente
Responses/Antworten
Der “y” Key enthält hier den Wert “r” für Response.
Zusätzlich enthält diese Message den Key “r”:
- r: ist ein Dictionary mit den Ergebnissen der Anfrage
Errors/Fehler
Der “y” Key enthält den Key “e” für Error.
- e: enthält eine Liste:
- das erste Element der Liste enthält den Fehler Code
- das zweite Element die Fehlermeldung
Mögliche Fehler und ihre Entsprechenden Messages:
| Code | Beschreibung |
|---|---|
| 201 | Generic Error |
| 202 | Server Error |
| 203 | Protocol Error, such as a malformed packet, invalid arguments, or bad token |
| 204 | Method Unknown |
Beispielhaftes Error Packet aus BEP005:
generic error = {"t":"aa", "y":"e", "e":[201, "A Generic Error Ocurred"]} bencoded = d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee
DHT Queries
Bei den DHT Anfragen enthält jeder Query einen “id”-Dictionary als Argument, neben etwaigen anderen Argumenten, welcher die Node ID der anfragenden Node beinhaltet (20-Byte String in Network Byte
Order) die Antworten enthalten natürlich die Node ID der antwortenden Node.
Hier die Möglichen Queries:
ping
Der Key “q” für den Query-Typ beinhaltet hier den Wert “ping”. Der Key “a” für die Argumente enthält einen Dictionary mit dem Key “id” und als Wert wie oben schon erklärt die Node ID in Network Byte Order.
Example Packets aus BEP005:
ping Query = {"t":"aa", "y":"q", "q":"ping", "a":{"id":"abcdefghij0123456789"}} bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}} bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
find_node:
Dieser Query wird benutzt um die Kontaktinformationen zu einer bestimmten Node anhand ihrer ID herauszufinden. Der “q”-Key enthält hier logischerweise “find_node”.
Die Argumente im “a”-Key enthalten wie immer die eigene Node ID und hier noch das Target-Dictionary welches folgende Keys enthält:
- “target”: ID der gesuchten Node
Als Antwort auf einen “find_node”-Query sollte die Antwort einen Key namens “nodes” enthalten der die Compact-Encoded-Node Informationen der gesuchten Node oder 8 (K) der nähsten bekannten “good”-Nodes enthalten.
Beispiel aus BEP005:
find_node Query ={"t":"aa", "y":"q", "q":"find_node","a":{"id":"abcdefghij0123456789","target":"mnopqrstuvwxyz123456"}} bencoded = d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e1:q9:find_node1:t2:aa1:y1:qe Response = {"t":"aa", "y":"r", "r": {"id":"0123456789abcdefghij", "nodes": "def456..."}} bencoded = d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t2:aa1:y1:re
get_peers:
Mit diesem Query erhält man Peers für den Torrent Download. “q” entspricht hier “get_peers”. Die Argumente sind “id” mit der Node ID und “info_hash” mit dem Infohash des Torrents. Die Antwort enthält den Key “values” der eine Liste von Strings enthält die entweder Compact-Encoded IP der Peers enthält, oder wenn keine Peers bekannt sind: einen Key “nodes” der eine Liste mit 8 (K) Nodes im Compact-Encoded Format enthält. In jedem Fall wird bei der Antwort ein Key “token” übertragen (der Token wird bei einem “announce” gebraucht).
Beispiele aus BEP005:
get_peers Query = {"t":"aa", "y":"q", "q":"get_peers", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456"}} bencoded = d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e1:q9:get_peers1:t2:aa1:y1:qe Response with peers = {"t":"aa", "y":"r", "r": {"id":"abcdefghij0123456789", "token":"aoeusnth", "values": ["axje.u", "idhtnm"]}} bencoded = d1:rd2:id20:abcdefghij01234567895:token8:aoeusnth6:valuesl6:axje.u6:idhtnmee1:t2:aa1:y1:re Response with closest nodes = {"t":"aa", "y":"r", "r": {"id":"abcdefghij0123456789", "token":"aoeusnth", "nodes": "def456..."}} bencoded = d1:rd2:id20:abcdefghij01234567895:nodes9:def456...5:token8:aoeusnthe1:t2:aa1:y1:re
announce_peer:
Der “q” Key enthält logischerweise den String “announce_peer”. Dazu kommen noch 4 Argumente in “a”, die da wären:
- id: Node ID
- info_hash: Infohash des Torrents
- port: BitTorrent Client Port (zb 6881)
- token: der token der beim vorherigem query nach peers vomentsprechendem Node gesendet wurde (dem Node welches usn die Peers geschickt hat)
Beispiel aus BEP005:
announce_peers Query = {"t":"aa", "y":"q", "q":"announce_peer", "a": {"id":"abcdefghij0123456789", "info_hash":"mnopqrstuvwxyz123456", "port": 6881, "token": "aoeusnth"}} bencoded = d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz1234564:porti6881e5:token8:aoeusnthe1:q13:announce_peer1:t2:aa1:y1:qe Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}} bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
Ich hoffe das war ein Verständlicher “kleiner” Überblick uber DHT im BitTorrent-Protokoll. Und im naechstem teil gehts dann ueber den Message-Flow im BitTorrent-Protokoll xxD Bevor wir dann auch zu anfassbarem Code kommen, bzw einem Release
Links:
Trotzallem noch tolle Ersatz-Indexer
- torrentbox Hier finde ich vor allem das Global-Search Feature ganz nettm da dort auch Torrentbox-Verified Torrents angezeigt werden
- 1337x Noch etwas kleines aber sympathisches Projekt
- h33t Die Oberfläche ist gewöhnungsbedürftig, ansonsten auch sehr nice xD
Tagged: bittorrent, Coding, dht, distributed hash table, hash tale, network, Networking, p2p, Torrent
Zensursula: Teil 1 – DNS
“Sie werden sich noch wünschen wir wären Politikverdrossen” (@343max)
Ich hatte in den letzten Wochen den Eindruck, als ob die gesamte Internet-Gemeinschaft in Deutschland Sturm lief, überall gab und gibt es nur ein Thema: Die Internetzensur Bestrebungen der großen Koalition. Dabei hatte man am Ende den Eindruck gegen eine Mauer von Unkenntnis, Ignoranz aber vielleicht auch einfach blanker böswilliger Berechnung einfach nichts ausrichten zu können.
Besonders Enttäuschend empfand ich die Medien, überraschend war es freilich nicht dass sie praktisch ausschließlich Parteipropaganda nachplapperten und die Mainstream Meinung nach dem Willen der Regierung formten. Von investigativem Journalismus jedenfalls war in den Holzmedien nichts zu sehen, das überlässt man offenbar anderen.
Ein wenig Ironisch ist es schon, ist doch gerade das Internet die einzige breit zugängliche alternative Informationsquelle(wie wir eindrucksvoll sehen konnten), die mit der jetzt beschlossenen Infrastruktur möglicherweise schon bald stark eingeschränkt wird. Dabei geht es auch um die Frage ob wir der Regierung soweit vertrauen, nach der Installation einer bis dato einmaligen Infrastruktur für Zensur, bei der Sperrung von Kinderpornographischen Inhalten zu bleiben. In den letzten Jahren hat uns die große Koalition keinen Grund geliefert das zu glauben.
Die eigentliche Kluft wie häufig Thematisiert, liegt nicht zwischen den Internet-Natives und den “Internet-Ausdruckern” sondern vielmehr in dem Teil der Bevölkerung der sich unabhängig Informiert und dem Teil, der den großen Medien und Agenturen(auch im Internet) blind vertaut und als einzige Informationsquelle zur eigenen Meinungsbildung heranzieht, also den überwiegenden Teil der Gesellschaft.
Gestern nun hat die EU die Zensur in China gerügt(so Merkwürdig wie das auch immer ist), demnach vergessen wir einfach alles was die EU-Länder sonst so treiben und beschäftigen uns nun, offensichtlich im Wohlwollen der EU, um die aktiven technischen Möglichkeiten der Umgehung jedweder Zensur-Infrastruktur, außerdem kann es nicht schaden die von den Zensoren eingesetzte Technologie mal etwas genauer zu beleuchten.
In diesem ersten Teil soll es um die Zensur durch DNS Manipulationen gehen.
Es ist noch die leichteste Form der Zensur, die Einstiegsdroge der Staaten sozusagen, denn DNS Manipulationen lassen sich Kinderleicht aushebeln was wohl schnell den Wunsch nach härteren Mitteln wecken dürfte. Bei dieser Form der Zensur installieren die ISP’s die Sperrlisten in ihren DNS-Servern, ist doch zumindest anzunehmen, das die Mehrheit der Internet Nutzer die Server ihres Providers verwenden, wobei das bei leibe nicht immer der Fall ist. So war und ist es schon immer möglich seinen eigenen DNS-Server zu betreiben. Jetzt wo man allen Grund hat den DNS-Servern der Provider zu misstrauen, ist das eine sehr praktikable Möglichkeit, zumindest für diejenigen die sich mit dem Internet auskennen.
Doch der Reihe nach, im Prinzip reicht es statt eines Domain-Namens in der Adresszeile die Ip-Adresse einzugeben um diese Zensur zu umgehen, besser ist es da schon einen alternativen DNS-Server zu verwenden, vorzugsweise im Ausland, aber auch der CCC und der Foebud stellen unzensierte DNS-Server (noch) frei zur Verfügung. Listen mit freien Servern gibt es z.B. bei Wikileaks, dem CCC oder die Server des Open NIC Projektes.
DNS Caching Server
Nützlich ist auch das Einrichten eines eigenen Caching DNS-Servers der zufällig aus einer Liste, öffentliche Servern abfragt. Ich verwende dafür den pdnsd, nicht zu verwechseln mit dem vollwertigen DNS-Server, PowerDNS. Je nach Distribution sollte sich die Installation einfach gestalten, z.B. reicht ein pacman -S pdnsd um mit Arch Linux den Server zu installieren. Jetzt sollte man sich die Beispiel Konfiguration kopieren und Anpassungen vornehmen. Hier eine mögliche Beispielkonfiguration, es muss nur die server_ip angepasst werden:
global { perm_cache=512000; # cache groesse in KB (hier "leicht" uebertriebene 500 MB) cache_dir="/var/cache/pdnsd"; run_as="nobody"; server_ip=10.0.0.4; # ANPASSEN status_ctl=on; paranoid=on; # prevents cache poisoning query_method=udp_tcp; min_ttl=15m; # min/max TTL max_ttl=4w; timeout=15; # global timeout 15 seconds neg_rrs_pol=auth; par_queries=2; # maximale parallele abfrage von servern } server { # ein paar oeffentliche server (alle getestet) label = "random"; randomize_servers = on; ip = 85.214.73.63, # foebud 204.152.184.76, # ISC (USA) 213.73.91.35, # CCC 194.95.202.198, # DFN 58.6.115.43, # Westnet (Australien) 82.229.244.191, # Frankreich 88.191.77.10, # Frankreich 216.87.84.209, # OpenNIC 88.191.77.10; # OpenNIC timeout=10; # 10 sekunden maximal uptest=ping; ping_timeout=400; #ms interval=30m; # uptest der server per ping } # Unveraendert aus Sample Conf: # This section is meant for resolving from root servers. server { label = "root-servers"; root_server = on; randomize_servers = on; # Give every root server an equal chance # of being queried. ip = 198.41.0.4 , 192.228.79.201 , 192.33.4.12 , 128.8.10.90 , 192.203.230.10 , 192.5.5.241 , 192.112.36.4 , 128.63.2.53 , 192.36.148.17 , 192.58.128.30 , 193.0.14.129 , 198.32.64.12 , 202.12.27.33 ; timeout = 5; uptest = query; # Test availability using empty DNS queries. interval = 30m; # Test every half hour. ping_timeout = 300; # Test should time out after 30 seconds. purge_cache = off; exclude = .localdomain; policy = included; preset = off; } # ganz praktisch, damit braucht man nur eine einzige hosts Datei im ganzen LAN zu pflegen: source { owner=localhost; serve_aliases=yes; file="/etc/hosts"; }
Ich habe alle DNS Server getestet. Eventuell die Konfiguration noch auf die eigenen Anforderungen anpassen, eine Dokumentation findet ihr hier. Die /etc/resolv.conf noch auf die lokale IP-Adresse umstellen dann den Server (neu)starten. Jetzt sollte er funktionieren, testen kann man das z.B. mit nslookup oder: dig 4poc.org [IP des DNS], dig zeigt auch wie lange er zum resolven brauchte.
Um festzustellen welche DNS-Server verwendet werden habe ich ein kleines Skript geschrieben, eigentlich passt die Thematik(siehe Anmerkung im Script) nicht direkt zum Thema aber den folgenden Artikeln sei schon mal etwas vorgegriffen: nstest.4poc.org (DNS Tester, falls jemanden einen besseren Namen dafür einfällt nur her damit.)
Tagged: Linux, Networking, zensursula
Web scraping mit Ruby/Mechanize
Praktisch jede Interaktion mit einer Website oder Webapplikation kann gescriptet, d.h. automatisiert werden. Das Abgrasen von Webseiten nach bestimmten Informationen wird auch als Scraping bezeichnet(für die nicht menschlichen Besucher dieser Seite sei das erwähnt *g*) Scripte können einem eine ganze Menge Arbeit abnehmen und sogar Dinge tun, die manuell unmöglich wären. Ich beschäftige mich mit dem Thema schon seit einer ganzen Weile und möchte hier nun die von mir favorisierte Methode dafür vorstellen, die Bibliothek Mechanize für die Scriptsprache Ruby.
Mechanize hat seinen Ursprung in Perl, mittlerweile gibt es jedoch auch Implementierungen der API für Python und eben Ruby. Für PHP gibt es mit Snoopy ein ähnliches Projekt, wenn es auch bei weitem nicht so fortgeschritten ist. Mechanize bietet die Möglichkeit mit einfachen Methoden eine art Webbrowser zu simulieren. Alle Beispiele wurden mit Mechanize Version 0.9.2 und Ruby 1.8.7 getestet.
Installation / Initialisierung
Mechanize kann mit Gems(ähnlich CPAN oder PEAR) installiert werden(# gem install mechanize --remote), einige Distributionen bieten aber auch eigene Pakete an. Ein Ruby-Script kann daraufhin Mechanize inkludieren und ein Objekt erstellen:
require 'rubygems' # ist unter Umständen notwendig require 'mechanize' agent = WWW::Mechanize.new
Jetzt ist Mechanize einsatzbereit, die folgenden Beispiele bauen darauf auf. Außerdem können mit dem agent nun noch grundlegende Einstellungen vorgenommen werden:
agent.set_proxy('localhost', '8000') agent.user_agent = 'Individueller User-Agent' agent.user_agent_alias = 'Linux Mozilla'
Die Einstellung ‘user_agent_alias‘ wählt einen User-Agent String aus dem folgenden Satz von Beispielen aus: Windows IE 6, Windows IE 7, Windows Mozilla, Mac Safari, Mac FireFox, Mac Mozilla, Linux Mozilla, Linux Konqueror, iPhone und Mechanize. Die Timing Einstellungen können ebenfalls sehr wichtig sein:
agent.open_timeout = 3 # setzt timeouts agent.read_timeout = 4 agent.keep_alive = false # default ist true
Hier folgen nun einige Beispiele, vielleicht werde ich mit der Zeit auch noch ein paar ergänzen, falls jemand Vorschläge hat, immer her damit. Ich habe auf http://apoc.sixserv.org/requestinfo ein kleines Skript am laufen das nützliche Informationen zum HTTP-Request liefert, das kann zum Experimentieren mit Mechanize sehr nützlich sein. Einige Beispiele findet man auch in den GUIDE und EXAMPLES Dateien des Mechanize Pakets. Read the rest of this entry »
Tagged: Coding, mechanize, Networking, Ruby
PoC: Real Bandwidth Limiting with PHP
vBrowseFile uses a slightly modificated Version of HTTP_Download. HTTP_Download is a Pear-Module to send local Files to Browser:
Provides an interface to easily send hidden files or any arbitrary data to HTTP clients. HTTP_Download can gain its data from variables, files or stream resources.
It features:
- Basic caching capabilities
- Basic throttling mechanism
- On-the-fly gzip-compression
- Ranges (partial downloads and resuming)
- Delivery of on-the-fly generated archives through Archive_Tar and Archive_Zip
- Sending of PgSQL LOBs without the need to read all data in prior to sending
I added a ThrottleCallback functionality to HTTP_Download, a function that is executed after the BufferSize is transferred and the ThrottleDelay Time is waited. Modifications in HTTP/Download.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var $throttleCallback = null; [...] function setThrottleCallback($callback) { $this->throttleCallback = $callback; } [...] function callThrottleCallback() { // execute callback if($this->throttleCallback != null) { $callback = $this->throttleCallback; $callback($this); } } [...] function sendChunk($chunk, $cType = null, $bound = null) { [...] // right after sleep is ex $this->callThrottleCallback(); [...] } |
This Callback could be used to track the download progress and to create a real bandwidth limitation. HTTP_Download supports a basic throttling mechanism to limit the bandwidth, but this only works for one connection, so e.g. you could limit 2 downloads to each 100 KiB/s but not all 2 downloads to each 50 KiB/s to limit the overall bandwidth to 100 KiB/s, instead it would be 200 KiB/s.
For this real bandwidth limiting you could use Apache modules like cband(seems not to work with php) or mod-bw, or you could use tc. Siyb from Geekosphere wrote an article about mod-bw: Limit Bandwidth per vHost in Apache2 (on Debian/Lenny)
Another possible way to limit the bandwidth is to implement it with HTTP_Download. The Theory is, to track all running downloads and change the BufferSize to := download limit * delay / active connections every
More detailed:
- We generate a random connection id(i call it rcid) for the tracking file.
- ThrottleDelay is set to 1 seconds.
- BufferSize is set to 100 KiB * 1 Seconds * 1024 to setup a maximum speed of 100KiB/s.
- The Callback would now be executed every 1 Seconds:
- create or overwrite our own rcid file with time() inside.
- search for other rcid files and check there time-stamp. tracking files older then 5 seconds would be deleted.
- count all rcid tracking files. e.g. 2 means there 2 open download connections.
- change the BufferSize. e.g. for 2 open connections: (100 KiB * 1 Seconds * 1024) / 2
This would limit the overall bandwidth of all active connections to a maximum of 100 KiB/s with a delay of ~ <5 Seconds. Without any Apache Modules or other standalone traffic sharping tools. For small installations this should work with no problem but for bigger installations a more efficient traffic shaping tool would be more effective.
Example Implementation: Read the rest of this entry »
Tagged: Coding, Networking, PHP, vbrowsefile
Ivacy VPN unter Linux: PPTP/OpenVPN und Socks5-Gateway
Die VPN Provider sprießen, dank der “Sicherheits-Politik” in Europa und den USA, wie Pilze aus dem Boden. Seit Juli 2008 gibt es Ivacy, einem durchaus interessanten VPN-Anbieter über den es möglich ist sich der Vorratsdatenspeicherung Europas zu entziehen. Hier geht es mir darum zu zeigen wie man Ivacy unter Linux nutzen kann, genauer gesagt wie man OpenVPN und PPTP unter Linux einrichtet, die Country-Selection Funktion von Ivacy nutzt und wie man einen Socks5 Proxy einrichtet der Verbindungen über Ivacy weiterleitet, dazu später mehr. Diese Anleitung sollte nicht nur mit Ivacy funktionieren, alle VPN-Anbieter bieten OpenVPN oder PPTP(das proprietäre VPN Protokoll von Microsoft).
Update: Habe einen OpenVPN-Abschnitt eingefügt.
Update 4.2.09@20:50: OpenVPN-Abschnitt überarbeitet.
Update 8.2.09@22:15: Artikel nochmals überarbeitet.
Update 21.4.09@22:00: Privoxy-Abschnitt eingefügt.
Bevor es losgeht sollte ich vielleicht noch erwähnen das es sich hierbei um keine Anleitung für Linux-Anfänger oder Ubuntu/Suse-”Profis” handelt. *g* Read the rest of this entry »
Tagged: ivacy, Linux, Networking, openvpn, pptp, proxy, socks, vpn
implementing bittorrent
Mal wieder was technisches. Ich geh mal ein bisschen ins Detail des BitTorrent Protokolls.
Ich werde das ganze in mehrere Teile aufteilen.
In den ersten Teilen wird es sehr Theoretisch.
In Teil 1 möchte ich auf das BEncoding eingehen und auf Metafile die euch sicherlich als “.torrent”-Datei bekannt ist.
Im nächstem Teil gehe ich dann auf grundsätzliches zur Aufgabe eines Trackers ein. Und danach wird es richtig interessant ![]()
Aber erstmal zum BEncoding und der Metafile, ohne die BitTorrent nicht funktioniert -
das BEncoding und die Metafile sind Essentiell!
Bevor ich auf das BEncoding eingehe spreche ich erstmal die MetaFile an, da dies die erste
Stelle (und auch wichtigste) ist an der das BEncoding im Protokoll vorgesehen ist.
Metafile
Die Metafile oder wie es die meisten von euch kennen die “.torrent”-Datei.
In ihr sind alle Informationen (und auch ein paar unwichtige
) die ein Client/Peer benötigt
gespeichert.
Also gehen wir mal näher auf den Inhalt der “.torrent”-Datei ein (optionale Teile sind mit *
gekennzeichnet):
- announce: Die Announce-URL des Trackers
- creation date*: Erstellungsdatum
- comment*: Platz für einen Kommentar zum Torrent oder andere Informationen
- created by*: der Name des Erstellers
- info: das info-Dictionary – der “kern” einer Metafile!(darauf gehe ich weiter unten ein)
Jetzt werden sich sicher einige denken “whuuut?! wtf? dictionary?!”
Ein Dictionary ist die Abbildunge einer Map, oder eines Arrays mit Schlüssel als Index
(ArrayList in Java) auf einen String (bzw. eine ByteFolge xD).
Das Info-Dictionary
Diese Keys enthält ein “info” Dictionary:
- piece length: Die Anzahl der Bytes pro Piece (BitTorrent-Peers tauschen die Daten in Pieces)
- pieces: Enthält die Hashes der Pieces
- info**: Das info-Dictionary für die Spezifizierung der im Torrent enthaltenen Datei/en. (wenn dieses info-Dictionary gemeint ist werde ich es mit ** markieren)
Es gibt 2 verschiedene Modi des Info-Dictionary** den Single-File und den Multifile-Mode,
dementsprechend gibt es auch
2 verschiedene Arten die Datei bzw. die Dateien näher zu Spezifizieren:
“info” im Single-File Mode
- name: Der Dateiname
- length: Länge der Datei in Bytes
“info” im Multi-File Mode
- name: Der Ordnername in dem sich die Dateien befinden
- files: Ein Dictionary das für jede Datei ein weiteres Dictionary enthält
Die Keys des “files”-Dictionaries:
- length: Die grösse der Datei in Bytes
- path: Der Pfad der Datei
Damit waren die wichtigsten Elemente des .torrent-Files erklärt und wir können uns mit de
Kodierung der entsprechenden Elemente/Einträge befassen – dem BEncoding.
BEncoding
Das BEncoding ist so genial wie einfach.
BitTorrent nutzt BEncoding für:
- Strings
- Integer
- Dictionaries
- Listen
Diese Typen werden alle nach dem selben Schema kodiert:
Strings:
: Beispiel: 5:w00t! (für den String "w00t!")
Integer:
ie Beispiel: i7e (Integer: "7") i-1e (Integer: "-1")
Dictionaries:
de Beispiel: d3:nks6:gentoo4:apoc4:arche*** *** Steht für folgendes dictionary: KEY VALUE [nks] = gentoo [apoc] = arch
Listen:
le Beispiel: l3:nks7:torrente (entspricht den Strings "nks" und "torrent")
Ist recht simpel oder?
Trotzdem muss man bei der Implementierung aufpassen, wenn hier ein Fehler passiert kann es sein
das man manchmal hinterher lange nach dem Fehler suchen muss ![]()
Das BEncoding verfolgt einen durch das ganze Protokoll hinweg.
Tagged: bittorrent, Coding, java, Networking, p2p, Torrent
xinetd: info script
Ich wollte von unterwegs aus den Status meines Heimservers abrufen können. Dabei ging es mir vorallem um die Temperatur von CPU, Mainboard und den Festplatten. Der auf sixserv.org laufende rbot(im Freenode idled der in #sixserv) soll auf Kommando den Status anzeigen. Soweit so gut. Ein kleines Ruby-Skript das auf dem Server zuhause läuft erfasst die Temperaturen per “sensors” und “hddtemp”. Der xinetd-Daemon konfigurierte ich daraufhin so das auf einen Port das Skript gebunden wird. Es erwartet bevor es die Daten übermittelt ein Passwort, einfach zum zusätzlichen Schutz auch wenn das vielleicht gar nicht nötig ist. Jemand der einen Portscan durchführt könnte eben so informationen zum System gelangen, die Passwortabfrage verhindert dies.
Zunächst zu dem Ruby-Script(z.B. /opt/botinfo.rb):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/usr/bin/ruby i = Kernel.gets if i.chomp != 'DASGEHEIMEPASSWORT' then # puts 'Wrong Password' exit end puts `uptime`.lstrip # HDD Temps: matches = `cat /proc/partitions`.scan /([s|h]d[a-z])/ matches.uniq! matches.each do |disk| print "#{disk}: #{`hddtemp -n /dev/#{disk}`.chomp}.0*C (#{$1}GB) " end puts systemp = `sensors` temp1 = systemp.scan /CPU Temp: \+([0-9]+)\.0.C/ temp2 = systemp.scan /M\/B Temp: \+([0-9]+)\.0.C/ puts "System: #{temp2[0]}.0*C #{temp2[1]}.0*C | CPUs: #{temp1[0]}.0*C #{temp1[1]}.0*C" |
Hier muss natürlich sensors und hddtemp installiert sein, aber dieses Script kann praktisch alles mögliche an Informationen sammeln und ausgeben.
Die Konfiguration von xinetd gestaltet sich sehr einfach, in dem Verzeichnis /etc/xinetd.d einfach eine neue Datei für das Script erstellen(z.B. “botinfo”):
1 2 3 4 5 6 7 8 9 10 11 | service botinfo { disable = no port = 8888 socket_type = stream protocol = tcp wait = no user = apoc server = /opt/botinfo.rb type = unlisted } |
Den Port, User und den Skript Pfad entsprechend anpassen und xinetd neu starten. Mit netcat kann es man danach testen:
1 2 3 4 5 | $ nc localhost 8888 DASGEHEIMEPASSWORT 18:40:35 up 3 days, 41 min, 4 users, load average: 0.00, 0.02, 0.20 sda: 30.0*C (10GB) sdb: 29.0*C (10GB) System: 39.0*C 38.0*C | CPUs: 37.0*C 36.0*C |
Der Port muss ggf. vom Router geforwarded werden damit ein Entfernter Server darauf zugreifen kann. Auch ein dyndns ist hilfreich, sofern man über keine statische IP verfügt. Ein einfaches rbot-Plugin um diese Daten vom irc aus abzufragen sieht z.B. so aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | require 'socket' class BotinfoPlugin < Plugin def help(plugin, topic="") 'info => return system information' end def info(m, params) sock = TCPSocket.new('heimserver.dyndns.org', 8888) sock.puts('DASGEHEIMEPASSWORT') m.reply sock.recv(1024) sock.close end end plugin = BotinfoPlugin.new plugin.map 'info' |
Die Daten können ebenfalls von einem PHP-Script aus abgefragt werden. Keines Beispiel:
1 2 3 4 5 6 7 8 9 | <?php $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); socket_connect($socket, "heimserver.dyndns.org", "8888"); $pass = "DASGEHEIMEPASSWORT\n\n"; socket_write($socket, $pass, strlen($pass)); echo socket_read($socket, 2048); ?> |
Vielleicht findet das ja irgendjemand interessant
Tagged: hddtemp, irc, Linux, Networking, PHP, plugin, RBot, Ruby, sensors, xinetd
kernel mode sockets part 2 (the clean way)
Version 0.3 - 23.01.2009
Willkommen zu teil 2 der linux kernel mode socket Serie. Nun befassen wir uns mit einem sauberem weg der socketcalls vom kernel aus. Auch hierfür gibt es noch andere Wege. In einem der nächsten Teile bauen wir uns eine socket()-Funktion selber, aber nun zum sauberem socket
Auch hier müssen wir wieder set_fs/get_fs (man kann sie auch weglassen, aber in diesem Fall garantiere ich für NICHTS, bzw das Modul lässt sich kompilieren aber die Funktion funktioniert im besten Fall nicht…) nutzen da file-Operationen im kernelmode nicht gestattet sind, der Zugriff auf sockets ist ein Dateizugriff. Die Funktion inet_addr müssen wir uns nicht extra schreiben, hab ich zwischenzeitlich herausgefunden in der “linux/inet.h” gibt es in_aton()
Die Hauptschwierigkeit besteht in den neuen Strukturen iovec und msghdr. Die ich allerdings anhand von Kommentaren erklären werde, soweit wichtig, bzw unter den beiden links steht alles was man wissen muss (obwohl es nicht spezifisch um die linux Strukturen geht).
Ab an den Code:
/* * lkm_clean_socket.c - nks */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/socket.h> #include <linux/net.h> #include <linux/in.h> #include <linux/inet.h> #include <net/sock.h> #include <asm/uaccess.h> int init_module(void) { struct socket *socket; struct sockaddr_in saddr; int errno; char buffer[1024]; struct msghdr msg; struct iovec iov; mm_segment_t old_fs; printk(KERN_INFO "#sixserv/sixserv.org presents:\n"); printk(KERN_INFO "simple & clean kernel mode socket - nks\n"); if ((errno = sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&socket))<0) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is up ...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); } saddr.sin_addr.s_addr = in_aton("79.140.33.153"); saddr.sin_port = htons(80); saddr.sin_family = AF_INET; if ((errno = socket->ops->connect(socket,(struct sockaddr*)&saddr,sizeof(saddr),0))<0) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is up an connected...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); } iov.iov_base = "GET / HTTP/1.0\r\n\r\n"; iov.iov_len = sizeof("GET / HTTP/1.0\r\n\r\n"); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_flags = 0; old_fs = get_fs(); set_fs(KERNEL_DS); if ((errno = sock_sendmsg(socket,&msg,sizeof("GET / HTTP/1.0\r\n\r\n")))<0) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is sending stuff...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); set_fs(old_fs); } iov.iov_base = buffer; iov.iov_len = 1024; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_name = NULL; msg.msg_namelen = 0; old_fs = get_fs(); set_fs(KERNEL_DS); if ((errno = sock_recvmsg(socket,&msg,1024,0))<0) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is recieving stuff...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); printk(KERN_INFO "++ Recieved: %s..\n",buffer); set_fs(old_fs); } return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye world.\n"); } MODULE_LICENSE("GPL");
Ein weiteres mal passen wir unsere Makfeile an:
obj-m += lkm_clean_socket.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Nach einem make ist das modul fertig und liegt unter dem namen “lkm_clean_socket.ko” im aktuellem verzeichnis.
Wenn alles geklappt hat machen wir folgendes:
# modinfo lkm_clean_socket.ko filename: lkm_clean_socket.ko license: GPL depends: vermagic: 2.6.25-gentoo-r7 SMP mod_unload PENTIUM4 # insmod lkm_clean_socket.ko # dmesg .... ++ Kernel Mode Socket is up ... ++ ERRNO: 0.. ++ Kernel Mode Socket is up an connected... ++ ERRNO: 0.. ++ Kernel Mode Socket is sending stuff... ++ ERRNO: 19.. ++ Kernel Mode Socket is recieving stuff... ++ ERRNO: 1024.. ++ Recieved: HTTP/1.1 200 OK Date: Sat, 30 Aug 2008 00:18:58 GMT Server: Apache X-Powered-By: PHP/5.2.0-8+etch11 X-Pingback: http://sixserv.org/xmlrpc.php Connection: close Content-Type: text/html; charset=UTF-8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="de-DE"> <head profile="http://gmpg.org/xfn/11"> <title>sixserv blog</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="description" content="welcome to teh #sixserv!" /> <meta name="generator" content="WordPress 2.6.1" /> <!-- leave this for stats please --> <link href="http://sixserv.org/wp-content/themes/journalist/style.css" rel="stylesheet" type="text/css" media="screen" /> <link rel="alternate" type="application/rss+xml" title="sixserv blog RSS Feed" href="http://sixserv.org/feed/" /> <link rel="shortcut icon" type="image/x-png" href="http://sixserv.org/wp-content/the .... # rmmod lkm_clean_socket.ko
Wie man sehen kann ist unser buffer ein wenig zu klein, und die errnos kann man sich eigtl. auch sparen wenn kein Fehler auftritt.
Seid gespannt auf den nächsten teil der kernel mode Serie
nks
quellen:
ps:
cuil.com und metager2.de lassen sich beide in die Suchleiste integrieren (klickt einfach auf den namen dann fragt euch FF). Nach einigem testen gefällt mir metager2 wesentlich besser weil es VIEL mehr findet. Allerdings gefällt mir die Aufmachung von cuil.com, ich sehe noch einiges an potenzial.
pps:
Mal wieder ein musikalischer Tipp:
http://www.myspace.com/blue_nine
edit: Unterschiede zu Version 0.1 haben nur mit der Rechtschreibung zu tun!
Tagged: Coding, kernel, Linux, Networking, security
kernel mode sockets part 1 (the dirty way)
Version 0.3 – 23.01.2009
Kernel mode sockets sind hoch-interessant. Im ersten teil befasse ich mich mit einer einfachen Implementierung eines ziemlich simplen kernel mode sockets, das ist nicht der Weg wie man es machen sollte allerdings hilft es erstmal dem grundsätzlichem Verständnis von lkm – also kernel modulen unter linux.
Es ist natürlich trotzdem möglich diesen Code in einem rootkit zu verwenden etc. aber ich finde das dieser Code nichts in einem produktiven Umfeld zu suchen hat, man öffnet keine Dateien aus derm kernel mode.
Wir beginnen mit den Basics eines lkm.
Zu erst das klassische “Hello world.”:
/* * lkm_hello_world.c */ #include <linux/module.h> #include <linux/kernel.h> int init_module(void) { printk(KERN_INFO "Hello world.\n"); } void cleanup_module(void) { printk(KERN_INFO "Goodbye world.\n"); }
Zum kompilieren des Moduls legen wir nun ein Makefile an:
obj-m += lkm_hello_world.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Vielleicht hat der ein oder andere versucht die sys/socket.h (etc.) einzubinden, aber das geht nicht. man sollte das auch nicht machen da das user-mode includes sind. Also machen wir weiter, wir erstellen wir einen simplen (dirty) socket im kernel mode. Ich hab mich dazu entschieden das wir den socket über den syscall “socketcall()” erstellen. Um syscalls aus dem kernel aufrufen zu können gab es bis kernel 2.6.19 die syscall macros (für alle mit einem neuerem kernel habe ich einen kleinen header mit den macros hoch geladen), allerdings kann man eigtl keine syscalls vom kernel aus machen, damit wir das können müssen wir aus dem kernel-space Adressraum in den user space Adressraum, das geschieht hier per set_fs(). und schon kann man userspace calls ausführen.
/* * lkm_dirty_socket.c - nks */ #include "syscall_macros.h" /* auskommentieren wenn die kernel version unter 2.6.19/18 ist! */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/socket.h> #include <linux/net.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/netdevice.h> #include <linux/init.h> #include <linux/syscalls.h> #include <linux/fcntl.h> #include <asm/uaccess.h> #include <linux/unistd.h> int errno; /* needed by socketcall() */ /* int socketcall(int call, unsigned long *args); wie wir sehen koennen werden der funktion socketcall() 2 call uebergeben, also benutzen wir das _syscall2-makro: */ static inline _syscall2(int, socketcall, int, call, unsigned long *, args); int init_module(void) { unsigned long arg[3]; int socket; mm_segment_t old_fs; struct sockaddr_in addr; struct sockaddr_in saddr; printk(KERN_INFO "#sixserv/sixserv.org presents:\n"); printk(KERN_INFO "simple kernel mode socket - nks\n"); old_fs = get_fs(); /* die argumente fuer socketcall vorbereiten*/ arg[0] = PF_INET; arg[1] = SOCK_STREAM; arg[2] = 0; set_fs(KERNEL_DS); if ((socket = socketcall(1, arg)) == -1) // SYS_SOCKET = 1 { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is up ...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); } return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye world.\n"); }
nun muessen wir die Makefile an das neue modul anpassen
obj-m += lkm_dirty_socket.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Nun können wir mit einem
# make #insmod lkm_dirty_socket
das Modul bauen und laden, mit dmesg sollte man dann die Meldungen sehen ob es geklappt hat sieht man wenn der folgende text in der debug Ausgabe erscheint:
++ Kernel Mode Socket is up …
Aber nur ein socket alleine ist ja bekanntlich ziemlich langweilig ![]()
Also verbinden wir uns mit einem http Server. Hierfür müssen wir noch ein paar Anpassungen an unserem bestehendem Code tätigen:
/* * lkm_dirty_socket.c - nks */ #include "syscall_macros.h" /* auskommentieren wenn die kernel version unter 2.6.19/18 ist! */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/socket.h> #include <linux/net.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/netdevice.h> #include <linux/init.h> #include <linux/syscalls.h> #include <linux/fcntl.h> #include <asm/uaccess.h> #include <linux/unistd.h> int errno; /* needed by socketcall() */ /* int socketcall(int call, unsigned long *args); wie wir sehen koennen werden der funktion socketcall() 2 parameter uebergeben, also benutzen wir das _syscall2-makro: */ static inline _syscall2(int, socketcall, int, call, unsigned long *, args); int init_module(void) { unsigned long arg[3]; int socket; mm_segment_t old_fs; struct sockaddr_in addr; struct sockaddr_in saddr; unsigned long arg1[3]; unsigned long args[4]; char buffer[1024]; printk(KERN_INFO "#sixserv/sixserv.org presents:\n"); printk(KERN_INFO "simple kernel mode socket - nks\n"); old_fs = get_fs(); arg[0] = PF_INET; arg[1] = SOCK_STREAM; arg[2] = 0; set_fs(KERNEL_DS); if ((socket = socketcall(1, arg)) == -1) // SYS_SOCKET = 1 { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is up ...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); } saddr.sin_addr.s_addr = inet_addr("79.140.33.153"); saddr.sin_port = htons(80); saddr.sin_family = AF_INET; /* argumente fuer connect(): int connect(int sockfd, struct sockaddr *serv_addr, int addrlen ); */ arg1[0] = socket; arg1[1] = (unsigned long)&saddr; arg1[2] = (unsigned long)sizeof(saddr); if ((socketcall(SYS_CONNECT, arg1)) == -1) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is up an connected...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); } /* argumente fuer send(): send(int s, const void *buf, size_t len, int flags); */ args[0] = socket; args[1] = "GET / HTTP/1.0\r\n\r\n"; args[2] = strlen("GET / HTTP/1.0\r\n\r\n"); args[3] = 0; if ((socketcall(SYS_SEND, args)) == -1) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "-- ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is sending stuff...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); } /* argumente fuer recv(): int recv(int s, void *buf, size_t len, int flags); */ args[0] = socket; args[1] = (unsigned long) buffer; args[2] = 1024; args[3] = 0; if ((socketcall(SYS_RECV, args)) == -1) { printk(KERN_INFO "-- Kernel Mode Socket ERROR...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); set_fs(old_fs); return 0; } else { printk(KERN_INFO "++ Kernel Mode Socket is recieving stuff...\n"); printk(KERN_INFO "++ ERRNO: %d..\n",errno); printk(KERN_INFO "++ Recieved: %s..\n",buffer); } set_fs(old_fs); return 0; } void cleanup_module(void) { printk(KERN_INFO "Goodbye world.\n"); } unsigned int inet_addr(char *str) { int a,b,c,d; char arr[4]; sscanf(str,"%d.%d.%d.%d",&a,&b,&c,&d); arr[0] = a; arr[1] = b; arr[2] = c; arr[3] = d; return *(unsigned int*)arr; }
Wieder ist eine neue Funktion hinzugekommen inet_addr, aber viel interessanter sind die neuen socketcalls, beim lesen kann man anhand des call-Arguments gut sehen welche socket-Funktion nun aufgerufen wird. zur Übergabe der Parameter verwenden wir ein char array bzw zwei da recv und send jeweils 4 Argumente haben.
Die syscall macros hab ich für euch hochgeladen
quellen:
- http://www.linuxjournal.com/node/8110/print
- http://www.ibm.com/developerworks/linux/library/l-system-calls/
- http://www.ibm.com/developerworks/linux/library/l-lkm/
- http://www.gnugeneration.com/mirrors/kernel-api/book1.html
- http://www.tldp.org/LDP/lkmpg/2.6/html/
- http://www.ussg.iu.edu/hypermail/linux/kernel/0303.2/2007.html (inet_addr())
- http://google.com/codesearch/
- http://lkml.org
- http://kerneltrap.org
- /usr/src/linux/*
- syscall_macros.h
Bei fragen etc. kommt doch einfach ins irc (#nullserv/#sixserv im freenode)
nks
ps:
benutzt öfters mal google-alternativen..
http://cuil.com oder http://metager2.de
pps:
chillig, und wie ich finde sehr geil: http://www.myspace.com/17thboulevard
bin gespannt auf das album…
Tagged: Coding, kernel, Linux, Networking, security