Cette page a été mise à jour en Mai 2013 et est valide pour la version de routeur 0.9.6.

Pourquoi écrire du code spécifique à I2P ?

Il y a de multiples façons d'utiliser des applications dans I2P. En utilisant I2PTunnel, vous pouvez utiliser des applications classiques sans avoir besoin de programmer un support explicite à I2P. Ceci est très efficace pour un scénario client-serveur, où vous avez besoin de vous connecter à un simple site web. Vous pouvez simplement créer un tunnel utilisant I2PTunnel pour connecter à ce site Web, comme indiqué dans Figure 1.

Si votre application est distribuée, elle exigera des connexions vers une grande quantité de pairs. En utilisant I2PTunnel, vous devrez créer un nouveau tunnel pour chaque pair que vous voulez contacter, comme indiqué sur la Figure 2. Ce processus peut bien sûr être automatisé, mais exécuter beaucoup d'instances I2PTunnel crée une grande quantité d'en-têtes. De plus, avec beaucoup de protocoles vous devrez forcer tout le monde à utiliser le même ensemble de ports pour tous les pairs - par exemple si vous voulez exécuter de façon fiable un chat DCC, tout le monde doit être d'accord que le port 10001 est Alice, le port 10002 est Bob, le port 10003 est Charlie, et ainsi de suite, puisque le protocole inclut des informations spécifiques TCP/IP (hôte et port).

Les applications de réseau générales envoient souvent beaucoup de données supplémentaires qui pourraient être utilisées pour identifier des utilisateurs. Noms d''hôtes, numéros de ports, fuseaux horaires, jeux de caractères, etc sont souvent envoyés sans informer l''utilisateur. Par conséquent, concevoir le protocole de réseau avec spécifiquement l''anonymat en mémoire peut éviter de mettre en péril les identités d''utilisateurs.

Il y a aussi des considérations d'efficacité à examiner lorsqu'on détermine comment interagir au-dessus d'I2P. La bibliothèque streaming et les choses construites au-dessus d'elle opèrent avec des poignées de main semblables à TCP, tandis que les protocoles du cœur d'I2P (I2NP et I2CP) sont strictement basés-message (comme UDP ou dans quelques instances IP brut). La distinction importante est qu'avec I2P, la communication opère sur un long réseau gras - chaque message de bout en bout aura des latences non insignifiantes, mais peut contenir des charges utiles pesant jusqu'à PLUSIEURS KO. Une application qui a besoin d'une simple requête et d'une réponse peut se débarrasser de n'importe quel état et baisser tomber la latence encourue par le démarrage et les poignées de main de démontage en utilisant (meilleur effort) des datagrammes sans devoir s'inquiéter de la détection MTU ni de la fragmentation des messages.

La création d'une connexion client-serveur utilisant I2PTunnel exige seulement la création d'un seul tunnel.

Figure 1: La création d'une connexion client-serveur utilisant I2PTunnel exige seulement la création d'un seul tunnel.

Mettre en oeuvre des connexions pour une application pair-à-pair exige une très grande quantité de tunnels.

Figure 2 : Mettre en oeuvre des connexions pour une application pair-à-pair exige une très grande quantité de tunnels.

En résumé, un certain nombre de raisons d'écrire du code spécifique à I2P :
  • Créer une grande quantité d'instances I2PTunnel consomme une quantité non-insignifiante de ressources, ce qui est problématique pour des applications distribuées (un nouveau tunnel est exigé pour chaque pair).
  • Des protocoles réseau généraux envoient souvent beaucoup de données supplémentaires qui peuvent être utilisées pour identifier des utilisateurs. Programmer spécifiquement pour I2P permet la création d'un protocole de réseau qui ne laisse pas fuiter de telles informations, gardant les utilisateurs anonymes et sécurisés.
  • Les protocoles de réseau conçus pour l'utilisation sur l'Internet régulier peuvent être inefficaces sur I2P, qui est un réseau avec une latence beaucoup plus haute.

I2P supporte une interface plugins standard pour les développeurs afin que les applications puissent être facilement intégrées et distribuées.

Les applications écrites en Java et accessible/exécutables en utilisant une interface HTML via le standard webapps/app.war peuvent être considérées pour inclusion dans la distribution i2p.

Concepts importants

Il y a peu de changements qui exigent un réglage lors de l''utilisation d''I2P :

Destination ~= hôte+port

Une application fonctionnant sur I2P envoie des messages depuis et reçoit des messages vers un unique point final sécurisé cryptographiquement - "une destination". En termes TCP ou UDP, une destination pourrait (largement) être considérée l'équivalent d'un nom d'hôte plus le numéro de port du pair, quoiqu'il y ait quelques différences.

  • Une destination I2P elle-même est une construction cryptographique - toutes les données envoyées l'une sont cryptées comme s'il y avait déploiement universel d'IPSEC avec l'emplacement (anonymisé) du point de fin signé comme s'il y avait déploiement universel de DNSSEC.
  • Les destinations I2P sont des identifiants mobiles - elles peuvent être déplacées d'un routeur I2P à un autre (ou elles peuvent même être "multi domiciles" - fonctionnant sur de multiples routeurs à la fois). Ceci diffère tout à fait du monde TCP et UDP où un seul point de fin (port) doit rester sur un seul hôte.
  • Les destinations I2P sont laides et grandes - dans les coulisses, elles contiennent une clé publique 2048 bit ElGamal pour chiffrage, clé publique 1024 bit DSA pour signature, et un certificat à taille variable, qui peut contenir la proof of work ou des données blinded.

    Il existe des façons de renvoyer vers ces grandes et laides destinations par de courts et mignons noms (par exemple "irc.duck.i2p"), mais ces techniques ne garantissent pas l'unicité globale (puisqu'ils sont stockés localement dans une base de données sur la machine de chaque personne) et le mécanisme actuel n'est pas particulièrement évolutif ni sécurisé (les mises à jour vers la liste d'hôte sont gérées en utilisant des "abonnements" à des services de nommage). Il pourrait y avoir un jour un système de nommage garantissent sécurité, lisibilité par humain, évolutivité, mise à l'échelle, et unicité globale, mais les applications ne devrait pas dépendre qu'il soit en place, puisqu'il y a ceux qui pensent qu'il n'est pas possible qu'une telle bête soit possible. Davantage d'informations sur le système de nommage sont disponibles.

Alors que la plupart des applications n'ont pas besoin de distinguer les protocoles et les ports I2P les supporte. Des applications complexes peuvent spécifier un protocole, depuis un port, et vers un port, sur une base par-message, pour communiquer en multiplexant le trafic sur une seule destination. Voir la page datagramme pour des détails. Les applications simples opèrent en écoutant "tous les protocoles" sur "tous les ports" d'une destination.

Anonymat et confidentialité

I2P possède un chiffrement bout à bout transparent et l''authentification de toutes les données passées sur le réseau - si Bob envoie à la destination Alice, seule la destination d'Alice peut recevoir, et si Bob utilise les datagrammes ou la bibliothèque streaming, Alice sait à coup sûr que la destination de Bob est celle qui a envoyé les données.

Bien sûr, I2P rend anonyme d'une manière transparente les données envoyées entre Alice et Bob, mais il ne fait rien pour rendre anonyme le contenu de ce qu'ils envoient. Par exemple, si Alice envoie un formulaire à Bob avec son nom complet, carte d'identité gouvernementale, et numéro de carte de crédit, il n'y a rien que I2P puisse faire. En tant que tel, les protocoles et les applications devraient garder à l'esprit quelles sont les informations qu'ils essaient de protéger et quelles sont les informations qu'ils sont enclins à exposer.

Les datagrammes I2P peut avoir une taille jusqu'à plusieurs KO

Les applications qui utilisent des datagrammes I2P (soit bruts ou réflexibles) peuvent essentiellement être pensées en termes d''UDP - les datagrammes ne sont pas ordonnés, meilleur effort, et sans connexion - mais contrairement à UDP, les demandes ne doivent pas s''inquiéter de la détection MTU et peuvent décharger simplement de grands datagrammes. Tandis que la limite supérieure est nominalement 32 KO, le message est fragmenté pour le transport, baissant ainsi la fiabilité de l''ensemble. On ne recommande pas actuellement les datagrammes de 10 KO. Voyez la page datagrammes pour des détails. Pour beaucoup d''applications, 10 KO de données sont suffisantes pour une requête entière ou une réponse, leur permettant d'opérer d''une manière transparente dans I2P telle une application comme-UDP sans devoir pour écrire fragmentation, renvoi, etc.

Options de développement

Il y a plusieurs moyens d'envoyer des données par I2P, chacune avec ses propres pour et contre. La bibliothèque streaming est l'interface recommandée, utilisée par la majorité des applications I2P.

Lib streaming

La bibliothèque full streaming est maintenant l'interface standard. Elle permet de programmer en utilisant des douilles comme-TCP, comme expliqué dans le Guide de développement streaming.

BOB

BOB est le Basic Open Bridge, permettant à une application dans n'importe quelle langage de faire des connexions en continu vers et depuis I2P. En ce moment il lui manque d'être capable de soutenir UDP, mais le soutient d'UDP est planifié dans un proche avenir. BOB contient aussi plusieurs outils, tels que la génération de clé de destination et la vérification qu'une adresse se conforme aux spécifications I2P. Des infos à jour et des applications qui utilisent BOB peuvent être trouvées sur cet eepsite.

SAM, SAM V2, SAM V3

SAM n'est pas recommandé. Sam V2 est okay, SAM V3 est recommandé.

SAM est le protocole Simple Anonymous Messaging, permettant à une application écrite dans n'importe quelle langage de parler à un pont SAM à travers une douille plein TCP et que ce pont multiplexe tout son trafic I2P, coordonnant d'une manière transparente le chiffrage/déchiffrage et le traitement basé événement. SAM supporte trois styles d'opération :

  • streams, pour quand Alice et Bob veulent envoyer des données l'un à l'autre de façon fiable et en ordre
  • datagrammes réflexibles, pour quand Alice veut envoyer un message à Bob auquel Bob puisse répondre
  • datagrammes en brut, pour quand Alice veut serrer la plupart de la bande passante et performance autant que possible et que Bob ne se soucie pas si l'expéditeur des données est authentifié ou pas (par exemple si les données transférées sont elles-mêmes authentifiantes)

SAM V3 vise le même but que SAM et SAM V2, mais ne nécessite pas de multiplexage/démultiplexage. Chaque stream I2P est traité par sa propre douille entre l'application et le pont SAM. En plus, les datagrammes peuvent être envoyés et reçus par l'application à travers les communications de datagramme avec le pont SAM.

SAM V2 est une nouvelle version utilisée par imule qui résoud certains des problèmes dans SAM.
SAM V3 est utilisé par imule depuis sa version 1.4.0.

I2PTunnel

L'application I2PTunnel permet aux applications de construire des tunnels TCP-semblables spécifiques aux pairs en créant soit des applications I2PTunnel 'clientes' (lequelles écoutent sur un port spécifique et connectent à une destination I2P spécifique quand une douille vers ce port est ouverte) ou des applications I2PTunnel 'serveur' (lequelles écoutent une destination I2P spécifique et quand elles obtiennent une nouvelle connexion I2P elle l'outproxie vers un hôte/port TCP spécifique). Ces streams sont 8-bit clean, et sont authentifiés et sécurisé par la même bibliothèque streaming que SAM utilise, mais il y a une en-tête non-insignifiante impliquée avec la création de multiples instances I2PTunnel uniques, puisque chacune a sa propre destination I2P unique et son propre ensemble de tunnels, clés, etc.

SOCKS

I2P supporte les proxy SOCKS V4 et V5. Les connexions en partance (outbound) marchent bien. Inbound (arrivant, serveur) et la fonctionnalité UDP peuvent être incomplètes et non testées.

Ministreaming

Enlevé

Il y a eu une simple librairie "ministreaming", mais maintenant ministreaming.jar contient seulement les interfaces pour la librairie ministreaming complète.

Datagrammes

Recommandé pour les applications semblables-UDP

The Bibliothèque de datagramme permet d'envoyer des paquets semblables-UDP-. Il est possible d'utiliser :

  • Datagrammes réflexibles
  • Datagrammes bruts

I2CP

Non recommandé

I2CP lui-même est un protocole indépendant du language, mais mettre en œuvre une bibliothèque I2CP dans quelque chose d'autre que Java nécessite une quantité significative de code à écrire (des routines de chiffrage, rassemblement d''objet, traitement de message asynchrone, etc). Tandis que quelqu'un pourrait écrire une bibliothèque I2CP en C ou en quelque chose d''autre, au lieu de cela il serait très probablement plus utile d'utiliser la bibliothèque C de SAM.

Applications Web

I2P arrive avec le serveur web Jetty, et au lieu de cela vous pouvez directement configurer I2P pour utiliser le serveur Apache. N''importe quelle technologie d''application Web standard devrait marcher.

Commencer à développer - un guide simple

Développer en utilisant I2P exige de travailler sur une installation d''I2P et un environnement de développement de votre propre choix. Si vous utilisez Java, vous pouvez commencer le développement avec la bibliothèque streaming ou la bibliothèque de datagramme. Si vous utilisez un autre language de programmation, vous pouvez utiliser SAM ou BOB.

Développer avec la bibliothèque streaming

L'exemple suivant montre comment créer des applications client et serveur semblables-TCP en utilisant la bibliothèque streaming.

Ceci exigera les bibliothèques suivantes dans votre classpath :

  • $I2P/lib/streaming.jar: La bibliothèque streaming elle-même
  • $I2P/lib/mstreaming.jar: Factory (?) et interfaces pour la bibliothèque streaming
  • $I2P/lib/i2p.jar: Classes standard I2P, structures de données, API et utilitaires

You can fetch these from an I2P installation, or add the following dependencies from Maven Central:

  • net.i2p:i2p:0.9.29
  • net.i2p.client:streaming:0.9.29

La communication réseau exige l'utilisation de douilles du réseau I2P. Pour démontrer ceci, nous créerons une application dans laquelle un client peut envoyer des messages texte à un serveur qui imprimera les messages et les renverra au client. Autrement dit, le serveur fonctionnera comme un écho.

Nous commencerons par initialiser l'application serveur. Ceci exige d'obtenir un I2PSocketManager et la création d'une I2PServerSocket. Nous ne fournirons pas l'I2PSocketManagerFactory avec les clés sauvées pour une Destination existante, donc il créera pour nous une nouvelle Destination. Ainsi nous demanderons une I2PSession à l'I2PSocketManager, afin que nous puissions découvrir la Destination qui a été créé, car nous devrons copier-coller des informations plus tard afin que le client puisse se connecter à nous.

package i2p.echoserver;

import net.i2p.client.I2PSession;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;

public class Main {

    public static void main(String[] args) {
        //Initialize application
        I2PSocketManager manager = I2PSocketManagerFactory.createManager();
        I2PServerSocket serverSocket = manager.getServerSocket();
        I2PSession session = manager.getSession();
        //Print the base64 string, the regular string would look like garbage.
        System.out.println(session.getMyDestination().toBase64());
        //The additional main method code comes here...
    }

}

Exemple de code 1 : initialisation de l'application serveur.

Une fois que nous avons une I2PServerSocket, nous pouvons créer des instances I2PSocket pour accepter des connexions issues de clients. Dans cet exemple, nous créerons une seule instance I2PSocket, qui peut seulement traiter un client à la fois. Un vrai serveur devrait pouvoir traiter de multiples clients. Pour faire ceci, de multiples instances I2PSocket devraient être créés, chacune dans des fils séparés. Une fois que nous avons créé l'instance I2PSocket, nous lisons les données, les imprimons et les renvoyons au client. Le code en gras est le nouveau code que nous ajoutons.

package i2p.echoserver;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.util.I2PThread;

import net.i2p.client.I2PSession;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;

public class Main {

    public static void main(String[] args) {
        I2PSocketManager manager = I2PSocketManagerFactory.createManager();
        I2PServerSocket serverSocket = manager.getServerSocket();
        I2PSession session = manager.getSession();
        //Print the base64 string, the regular string would look like garbage.
        System.out.println(session.getMyDestination().toBase64());

        //Create socket to handle clients
        I2PThread t = new I2PThread(new ClientHandler(serverSocket));
        t.setName("clienthandler1");
        t.setDaemon(false);
        t.start();
    }

    private static class ClientHandler implements Runnable {

        public ClientHandler(I2PServerSocket socket) {
            this.socket = socket;
        }

        public void run() {
            while(true) {
                try {
                    I2PSocket sock = this.socket.accept();
                    if(sock != null) {
                        //Receive from clients
                        BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                        //Send to clients
                        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
                        String line = br.readLine();
                        if(line != null) {
                            System.out.println("Received from client: " + line);
                            bw.write(line);
                            bw.flush(); //Flush to make sure everything got sent
                        }
                        sock.close();
                    }
                } catch (I2PException ex) {
                    System.out.println("General I2P exception!");
                } catch (ConnectException ex) {
                    System.out.println("Error connecting!");
                } catch (SocketTimeoutException ex) {
                    System.out.println("Timeout!");
                } catch (IOException ex) {
                    System.out.println("General read/write-exception!");
                }
            }
        }

        private I2PServerSocket socket;

    }

}

Exemple de code 2 : acceptation de connexions issues de clients et traitement de messages.

Quand vous exécutez le code de serveur ci-dessus, il devrait imprimer quelque chose comme ceci (mais sans les fins de ligne, il devrait juste être un énorme bloc de caractères) :

    y17s~L3H9q5xuIyyynyWahAuj6Jeg5VC~Klu9YPquQvD4vlgzmxn4yy~5Z0zVvKJiS2Lk
    poPIcB3r9EbFYkz1mzzE3RYY~XFyPTaFQY8omDv49nltI2VCQ5cx7gAt~y4LdWqkyk3au
    6HdfYSLr45zxzWRGZnTXQay9HPuYcHysZHJP1lY28QsPz36DHr6IZ0vwMENQsnQ5rhq20
    jkB3iheYJeuO7MpL~1xrjgKzteirkCNHvXN8PjxNmxe-pj3QgOiow-R9rEYKyPAyGd2pe
    qMD-J12CGfB6MlnmH5qPHGdZ13bUuebHiyZ1jqSprWL-SVIPcynAxD2Uu85ynxnx31Fth
    nxFMk07vvggBrLM2Sw82pxNjKDbtO8reawe3cyksIXBBkuobOZdyOxp3NT~x6aLOxwkEq
    BOF6kbxV7NPRPnivbNekd1E1GUq08ltDPVMO1pKJuGMsFyZC4Q~osZ8nI59ryouXgn97Q
    5ZDEO8-Iazx50~yUQTRgLMOTC5hqnAAAA
    
Ceci est la représentation base64 du serveur Destination. Le client aura besoin de cette chaîne pour atteindre le serveur.

Maintenant, nous allons créer l'application cliente. De nouveau, un certain nombre d'étapes sont exigées pour l'initialisation. De nouveau, nous allons devoir commencer en obtenant une I2PSocketManager. Nous n'utiliserons pas d'I2PSession ni de I2PServerSocket cette fois. Au lieu de cela, nous utiliserons la chaîne de serveur Destination pour commencer notre connexion. Nous demanderons à l'utilisateur chaîne de Destination et créerons un I2PSocket utilisant cette chaîne. Une fois que nous aurons un I2PSocket, nous pourrons commencer à envoyer et recevoir des données vers et depuis le serveur.

package i2p.echoclient;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;

public class Main {

    public static void main(String[] args) {
        I2PSocketManager manager = I2PSocketManagerFactory.createManager();
        System.out.println("Please enter a Destination:");
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String destinationString;
        try {
            destinationString = br.readLine();
        } catch (IOException ex) {
            System.out.println("Failed to get a Destination string.");
            return;
        }
        Destination destination;
        try {
            destination = new Destination(destinationString);
        } catch (DataFormatException ex) {
            System.out.println("Destination string incorrectly formatted.");
            return;
        }
        I2PSocket socket;
        try {
            socket = manager.connect(destination);
        } catch (I2PException ex) {
            System.out.println("General I2P exception occurred!");
            return;
        } catch (ConnectException ex) {
            System.out.println("Failed to connect!");
            return;
        } catch (NoRouteToHostException ex) {
            System.out.println("Couldn't find host!");
            return;
        } catch (InterruptedIOException ex) {
            System.out.println("Sending/receiving was interrupted!");
            return;
        }
        try {
            //Write to server
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("Hello I2P!\n");
            //Flush to make sure everything got sent
            bw.flush();
            //Read from server
            BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String s = null;
            while ((s = br2.readLine()) != null) {
                System.out.println("Received from server: " + s);
            }
            socket.close();
        } catch (IOException ex) {
            System.out.println("Error occurred while sending/receiving!");
        }
    }

}

Exemple de code 3 : lancer le client et le connecter à l'application serveur.

Finalement, vous pouvez exécuter à la fois l'application serveur et la cliente. D'abord, lancez l'application serveur. Elle imprimera une chaîne Destination (comme montré ci-dessus). Ensuite, lancez l'application cliente. Quand elle demande une chaîne Destination, vous pouvez entrer la chaîne imprimée par le serveur. Le client enverra alors 'Hello I2P!' (avec un retour à la ligne) au serveur, qui imprimera le message et le renverra au client.

Félicitations, vous avez communiqué avec succès au moyen d''I2P !

Applications existantes

Contactez-nous si vous voudriez contribuer.

See also all the plugins on plugins.i2p, the applications and source code listed on echelon.i2p, and the application code hosted on git.repo.i2p.

See also the bundled applications in the I2P distribution - SusiMail and I2PSnark.

Idées d''applications

  • Serveur NNTP - il y en a eu certains dans le passé, mais aucun à l'heure actuelle
  • Serveur Jabber - il y en a eu certains dans le passé, et il y en a un à l'heure actuelle, avec l'accès à Internet public
  • Serveur de clé PGP et/ou proxy
  • Diffusion de contenus/ applications DHT - ressusciter feedspace, porter dijjer, chercher des alternatives
  • Donner un coup de main au développement de Syndie
  • Applications basées sur le Web - le ciel est la limite pour les applications d'hébergement basées-serveur-Web telles que blogs, pastebins, stockage, tracking, feeeds, etc N'importe quelle technologie Web ou CGI telle que Perl, PHP, Python, ou Ruby marcheront.
  • Ressusciter quelques vieilles applications, plusieurs précédemment inclues dans le paquet de source d''I2P - bogobot, pants, proxyscript, q, stasher, socks proxy, i2ping, feedspace