Aperçu
Le protocole client I2P (I2CP) assure une séparation stricte des responsabilités entre le routeur et tout client souhaitant communiquer via le réseau. Il permet des échanges sécurisés et asynchrones en envoyant et en recevant des messages sur une seule socket TCP. Grâce à I2CP, une application cliente indique au routeur son identité (sa « destination »), les compromis souhaités en matière d’anonymat, de fiabilité et de latence, ainsi que les destinataires des messages. En retour, le routeur utilise I2CP pour informer le client de l’arrivée de messages et pour demander l’autorisation d’utiliser certains tunnels.
Le protocole lui-même est implémenté en Java, afin de fournir le SDK client. Ce SDK est exposé dans le paquet i2p.jar, qui implémente le côté client d’I2CP. Les clients ne devraient jamais avoir à accéder au paquet router.jar, qui contient le routeur lui-même ainsi que le côté routeur d’I2CP. Un client non-Java devrait également implémenter la bibliothèque de streaming pour les connexions de type TCP.
Les applications peuvent tirer parti de l’I2CP de base ainsi que des bibliothèques de flux et de datagrammes en utilisant le protocole Simple Anonymous Messaging (SAM) , qui ne demande pas aux clients de gérer quelque forme de cryptographie que ce soit. De plus, les clients peuvent accéder au réseau via plusieurs types de proxys - HTTP, CONNECT, et SOCKS 4/4a/5. Alternativement, les clients Java peuvent accéder à ces bibliothèques via ministreaming.jar et streaming.jar. Il existe donc plusieurs options pour les applications Java comme pour celles qui ne le sont pas.
Le chiffrement de bout en bout côté client (chiffrement des données sur la connexion I2CP) a été désactivé dans la version 0.6 d’I2P, laissant en place le chiffrement de bout en bout ElGamal/AES qui est implémenté au niveau du routeur. La seule cryptographie que les bibliothèques clientes doivent encore implémenter est la signature de clés publique/privée DSA pour les LeaseSets et les Configurations de session , ainsi que la gestion de ces clés.
Dans une installation standard d’I2P, le port 7654 est utilisé par les clients Java externes pour communiquer avec le routeur local via I2CP. Par défaut, le routeur s’associe à l’adresse 127.0.0.1. Pour s’associer à 0.0.0.0, définissez l’option de configuration avancée du routeur i2cp.tcp.bindAllInterfaces=true et redémarrez. Les clients situés dans la même machine virtuelle Java (JVM) que le routeur transmettent les messages directement au routeur via une interface JVM interne.
Certaines implémentations de routeur et de client peuvent également prendre en charge les connexions externes via SSL, comme configuré par l’option i2cp.SSL=true. Bien que SSL ne soit pas activé par défaut, son utilisation est fortement recommandée pour tout trafic susceptible d’être exposé à Internet. Le nom d’utilisateur et le mot de passe d’autorisation (le cas échéant), la clé privée
et la clé privée de signature
pour la Destination
sont tous transmis en clair sauf si SSL est activé. Certaines implémentations de routeur et de client peuvent également prendre en charge les connexions externes via des sockets de domaine.
Spécification du protocole I2CP
Voir la page de spécification I2CP pour la spécification complète du protocole.
Initialisation I2CP
Lorsqu’un client se connecte au routeur, il envoie d’abord un unique octet indiquant la version du protocole (0x2A). Ensuite, il envoie un message GetDate et attend la réponse SetDate . Puis, il envoie un message CreateSession contenant la configuration de la session. Il attend ensuite un message RequestLeaseSet provenant du routeur, indiquant que les tunnels entrants ont été créés, et répond avec un message CreateLeaseSet contenant le LeaseSet signé. Le client peut désormais initier ou recevoir des connexions depuis d’autres destinations I2P.
Options I2CP
Options côté routeur
Les options suivantes sont traditionnellement transmises au routeur via un SessionConfig contenu dans un message CreateSession ou un message ReconfigureSession .
| Router-side Options | |||||
|---|---|---|---|---|---|
| Option | As Of Release | Recommended Arguments | Allowable Range | Default | Description |
| clientMessageTimeout | 8*1000 - 120*1000 | 60*1000 | The timeout (ms) for all sent messages. Unused. See the protocol specification for per-message settings. | ||
| crypto.lowTagThreshold | 0.9.2 | 1-128 | 30 | Minimum number of ElGamal/AES Session Tags before we send more. Recommended: approximately tagsToSend * 2/3 | |
| crypto.ratchet.inboundTags | 0.9.47 | 1-? | 160 | Inbound tag window for ECIES-X25519-AEAD-Ratchet. Local inbound tagset size. See proposal 144. | |
| crypto.ratchet.outboundTags | 0.9.47 | 1-? | 160 | Outbound tag window for ECIES-X25519-AEAD-Ratchet. Advisory to send to the far-end in the options block. See proposal 144. | |
| crypto.tagsToSend | 0.9.2 | 1-128 | 40 | Number of ElGamal/AES Session Tags to send at a time. For clients with relatively low bandwidth per-client-pair (IRC, some UDP apps), this may be set lower. | |
| explicitPeers | null | Comma-separated list of Base 64 Hashes of peers to build tunnels through; for debugging only | |||
| i2cp.dontPublishLeaseSet | true, false | false | Should generally be set to true for clients and false for servers | ||
| i2cp.fastReceive | 0.9.4 | true, false | false | If true, the router just sends the MessagePayload instead of sending a MessageStatus and awaiting a ReceiveMessageBegin. | |
| i2cp.leaseSetAuthType | 0.9.41 | 0 | 0-2 | 0 | The type of authentication for encrypted LS2. 0 for no per-client authentication (the default); 1 for DH per-client authentication; 2 for PSK per-client authentication. See proposal 123. |
| i2cp.leaseSetEncType | 0.9.38 | 4,0 | 0-65535,... | 0 | The encryption type to be used, as of 0.9.38. Interpreted client-side, but also passed to the router in the SessionConfig, to declare intent and check support. As of 0.9.39, may be comma-separated values for multiple types. See PublicKey in common structures spec for values. See proposals 123, 144, and 145. |
| i2cp.leaseSetOfflineExpiration | 0.9.38 | The expiration of the offline signature, 4 bytes, seconds since the epoch. See proposal 123. | |||
| i2cp.leaseSetOfflineSignature | 0.9.38 | The base 64 of the offline signature. See proposal 123. | |||
| i2cp.leaseSetPrivKey | 0.9.41 | A base 64 X25519 private key for the router to use to decrypt the encrypted LS2 locally, only if per-client authentication is enabled. Optionally preceded by the key type and ':'. Only "ECIES_X25519:" is supported, which is the default. See proposal 123. Do not confuse with i2cp.leaseSetPrivateKey which is for the leaseset encryption keys. | |||
| i2cp.leaseSetSecret | 0.9.39 | "" | Base 64 encoded UTF-8 secret used to blind the leaseset address. See proposal 123. | ||
| i2cp.leaseSetTransientPublicKey | 0.9.38 | [type:]b64 The base 64 of the transient private key, prefixed by an optional sig type number or name, default DSA_SHA1. See proposal 123. | |||
| i2cp.leaseSetType | 0.9.38 | 1,3,5,7 | 1-255 | 1 | The type of leaseset to be sent in the CreateLeaseSet2 Message. Interpreted client-side, but also passed to the router in the SessionConfig, to declare intent and check support. See proposal 123. |
| i2cp.messageReliability | BestEffort, None | BestEffort | Guaranteed is disabled; None implemented in 0.8.1; the streaming lib default is None as of 0.8.1, the client side default is None as of 0.9.4 | ||
| i2cp.password | 0.8.2 | string | For authorization, if required by the router. If the client is running in the same JVM as a router, this option is not required. Warning - username and password are sent in the clear to the router, unless using SSL (i2cp.SSL=true). Authorization is only recommended when using SSL. | ||
| i2cp.username | 0.8.2 | string | |||
| inbound.allowZeroHop | true, false | true | If incoming zero hop tunnel is allowed | ||
| outbound.allowZeroHop | true, false | true | If outgoing zero hop tunnel is allowed | ||
| inbound.backupQuantity | number from 0 to 3 | No limit | 0 | Number of redundant fail-over for tunnels in | |
| outbound.backupQuantity | number from 0 to 3 | No limit | 0 | Number of redundant fail-over for tunnels out | |
| inbound.IPRestriction | number from 0 to 4 | 0 to 4 | 2 | Number of IP bytes to match to determine if two routers should not be in the same tunnel. 0 to disable. | |
| outbound.IPRestriction | number from 0 to 4 | 0 to 4 | 2 | Number of IP bytes to match to determine if two routers should not be in the same tunnel. 0 to disable. | |
| inbound.length | number from 0 to 3 | 0 to 7 | 3 | Length of tunnels in | |
| outbound.length | number from 0 to 3 | 0 to 7 | 3 | Length of tunnels out | |
| inbound.lengthVariance | number from -1 to 2 | -7 to 7 | 0 | Random amount to add or subtract to the length of tunnels in. A positive number x means add a random amount from 0 to x inclusive. A negative number -x means add a random amount from -x to x inclusive. The router will limit the total length of the tunnel to 0 to 7 inclusive. The default variance was 1 prior to release 0.7.6. | |
| outbound.lengthVariance | number from -1 to 2 | -7 to 7 | 0 | Random amount to add or subtract to the length of tunnels out. A positive number x means add a random amount from 0 to x inclusive. A negative number -x means add a random amount from -x to x inclusive. The router will limit the total length of the tunnel to 0 to 7 inclusive. The default variance was 1 prior to release 0.7.6. | |
| inbound.nickname | string | Name of tunnel - generally used in routerconsole, which will use the first few characters of the Base64 hash of the destination by default. | |||
| outbound.nickname | string | Name of tunnel - generally ignored unless inbound.nickname is unset. | |||
| outbound.priority | 0.9.4 | number from -25 to 25 | -25 to 25 | 0 | Priority adjustment for outbound messages. Higher is higher priority. |
| inbound.quantity | number from 1 to 3 | 1 to 16 | 2 | Number of tunnels in. Limit was increased from 6 to 16 in release 0.9; however, numbers higher than 6 are incompatible with older releases. | |
| outbound.quantity | number from 1 to 3 | No limit | 2 | Number of tunnels out | |
| inbound.randomKey | 0.9.17 | Base 64 encoding of 32 random bytes | Used for consistent peer ordering across restarts. | ||
| outbound.randomKey | 0.9.17 | Base 64 encoding of 32 random bytes | |||
| inbound.* | Any other options prefixed with "inbound." are stored in the "unknown options" properties of the inbound tunnel pool's settings. | ||||
| outbound.* | Any other options prefixed with "outbound." are stored in the "unknown options" properties of the outbound tunnel pool's settings. | ||||
| shouldBundleReplyInfo | 0.9.2 | true, false | true | Set to false to disable ever bundling a reply LeaseSet. For clients that do not publish their LeaseSet, this option must be true for any reply to be possible. "true" is also recommended for multihomed servers with long connection times. Setting to “false” may save significant outbound bandwidth, especially if the client is configured with a large number of inbound tunnels (Leases). If replies are still required, this may shift the bandwidth burden to the far-end client and the floodfill. There are several cases where “false” may be appropriate:
| |
Remarque : À partir de la version 0.7.7, les noms et valeurs des options doivent utiliser l’encodage UTF-8. Cela est principalement utile pour les surnoms. Avant cette version, les options contenant des caractères multioctets étaient corrompues. Étant donné que les options sont encodées dans une Mapping , les noms et valeurs d’options sont limités à un maximum de 255 octets (et non caractères).
Options côté client
Les options suivantes sont interprétées côté client et seront prises en compte si elles sont transmises à la I2PSession via l’appel I2PClient.createSession(). La bibliothèque de streaming devrait également transmettre ces options à I2CP. D’autres implémentations peuvent avoir des valeurs par défaut différentes.
| Client-side Options | |||||
|---|---|---|---|---|---|
| Option | As Of Release | Recommended Arguments | Allowable Range | Default | Description |
| i2cp.closeIdleTime | 0.7.1 | 1800000 | 300000 minimum | (ms) Idle time required (default 30 minutes) | |
| i2cp.closeOnIdle | 0.7.1 | true, false | false | Close I2P session when idle | |
| i2cp.encryptLeaseSet | 0.7.1 | true, false | false | Encrypt the lease | |
| i2cp.fastReceive | 0.9.4 | true, false | true | If true, the router just sends the MessagePayload instead of sending a MessageStatus and awaiting a ReceiveMessageBegin. | |
| i2cp.gzip | 0.6.5 | true, false | true | Gzip outbound data | |
| i2cp.leaseSetAuthType | 0.9.41 | 0 | 0-2 | 0 | The type of authentication for encrypted LS2. 0 for no per-client authentication (the default); 1 for DH per-client authentication; 2 for PSK per-client authentication. See proposal 123. |
| i2cp.leaseSetBlindedType | 0.9.39 | 0-65535 | See prop. 123 | The sig type of the blinded key for encrypted LS2. Default depends on the destination sig type. See proposal 123. | |
| i2cp.leaseSetClient.dh.nnn | 0.9.41 | b64name:b64pubkey | The base 64 of the client name (ignored, UI use only), followed by a ':', followed by the base 64 of the public key to use for DH per-client auth. nnn starts with 0. See proposal 123. | ||
| i2cp.leaseSetClient.psk.nnn | 0.9.41 | b64name:b64privkey | The base 64 of the client name (ignored, UI use only), followed by a ':', followed by the base 64 of the private key to use for PSK per-client auth. nnn starts with 0. See proposal 123. | ||
| i2cp.leaseSetEncType | 0.9.38 | 0 | 0-65535,... | 0 | The encryption type to be used, as of 0.9.38. Interpreted client-side, but also passed to the router in the SessionConfig, to declare intent and check support. As of 0.9.39, may be comma-separated values for multiple types. See also i2cp.leaseSetPrivateKey. See PublicKey in common structures spec for values. See proposals 123, 144, and 145. |
| i2cp.leaseSetKey | 0.7.1 | For encrypted leasesets. Base 64 SessionKey (44 characters) | |||
| i2cp.leaseSetOption.nnn | 0.9.66 | srvKey=srvValue | A service record to be placed in the LeaseSet2 options. Example: "_smtp._tcp=1 86400 0 0 25 ...b32.i2p". nnn starts with 0. See proposal 167. | ||
| i2cp.leaseSetPrivateKey | 0.9.18 | Base 64 private keys for encryption. Optionally preceded by the encryption type name or number and ':'. For LS1, only one key is supported, and only "0:" or "ELGAMAL_2048:" is supported, which is the default. As of 0.9.39, for LS2, multiple keys may be comma-separated, and each key must be a different encryption type. I2CP will generate the public key from the private key. Use for persistent leaseset keys across restarts. See proposals 123, 144, and 145. See also i2cp.leaseSetEncType. Do not confuse with i2cp.leaseSetPrivKey which is for encrypted LS2. | |||
| i2cp.leaseSetSecret | 0.9.39 | "" | Base 64 encoded UTF-8 secret used to blind the leaseset address. See proposal 123. | ||
| i2cp.leaseSetSigningPrivateKey | 0.9.18 | Base 64 private key for signatures. Optionally preceded by the key type and ':'. DSA_SHA1 is the default. Key type must match the signature type in the destination. I2CP will generate the public key from the private key. Use for persistent leaseset keys across restarts. | |||
| i2cp.leaseSetType | 0.9.38 | 1,3,5,7 | 1-255 | 1 | The type of leaseset to be sent in the CreateLeaseSet2 Message. Interpreted client-side, but also passed to the router in the SessionConfig, to declare intent and check support. See proposal 123. |
| i2cp.messageReliability | BestEffort, None | None | Guaranteed is disabled; None implemented in 0.8.1; None is the default as of 0.9.4 | ||
| i2cp.reduceIdleTime | 0.7.1 | 1200000 | 300000 minimum | (ms) Idle time required (default 20 minutes, minimum 5 minutes) | |
| i2cp.reduceOnIdle | 0.7.1 | true, false | false | Reduce tunnel quantity when idle | |
| i2cp.reduceQuantity | 0.7.1 | 1 | 1 to 5 | 1 | Tunnel quantity when reduced (applies to both inbound and outbound) |
| i2cp.SSL | 0.8.3 | true, false | false | Connect to the router using SSL. If the client is running in the same JVM as a router, this option is ignored, and the client connects to that router internally. | |
| i2cp.tcp.host | 127.0.0.1 | Router hostname. If the client is running in the same JVM as a router, this option is ignored, and the client connects to that router internally. | |||
| i2cp.tcp.port | 1-65535 | 7654 | Router I2CP port. If the client is running in the same JVM as a router, this option is ignored, and the client connects to that router internally. | ||
Format des données utiles I2CP et multiplexage
Les messages de bout en bout gérés par I2CP (c’est-à-dire les données envoyées par le client dans un SendMessageMessage et reçues par le client dans un MessagePayloadMessage ) sont compressés avec un en-tête gzip standard de 10 octets commençant par 0x1F 0x8B 0x08, tel que spécifié par la RFC 1952 . À compter de la version 0.7.1, I2P utilise des parties ignorées de l’en-tête gzip pour inclure des informations sur le protocole, le port d’origine (from-port) et le port de destination (to-port), permettant ainsi aux flux et aux datagrammes d’utiliser la même destination, et rendant fiables les échanges requête/réponse par datagrammes en présence de plusieurs canaux.
La fonction gzip ne peut pas être complètement désactivée, mais définir i2cp.gzip=false règle l’effort de compression gzip à 0, ce qui peut permettre d’économiser un peu de CPU. Les implémentations peuvent choisir différents niveaux d’effort gzip selon les sockets ou les messages, en fonction d’une évaluation de la compressibilité du contenu. En raison de la compressibilité du remplissage de destination mise en œuvre dans l’API 0.9.57 (proposition 161), il est recommandé de compresser les paquets SYN de flux dans les deux sens ainsi que les datagrammes avec accusé de réception, même si la charge utile n’est pas compressible. Les implémentations peuvent souhaiter écrire une fonction gzip/gunzip simplifiée pour un effort gzip de 0, ce qui offrirait de grandes améliorations d’efficacité par rapport à une bibliothèque gzip dans ce cas précis.
| Bytes | Content |
|---|---|
| 0-2 | Gzip header 0x1F 0x8B 0x08 |
| 3 | Gzip flags |
| 4-5 | I2P Source port (Gzip mtime) |
| 6-7 | I2P Destination port (Gzip mtime) |
| 8 | Gzip xflags (set to 2 to be indistinguishable from the Java implementation) |
| 9 | I2P Protocol (6 = Streaming, 17 = Datagram, 18 = Raw Datagrams) (Gzip OS) |
L’intégrité des données est vérifiée à l’aide du CRC-32 standard gzip tel que spécifié par la RFC 1952 .
Différences importantes par rapport à l’IP standard
Les ports I2CP sont destinés aux sockets et aux datagrammes I2P. Ils n’ont aucun rapport avec vos sockets ou ports locaux. Étant donné qu’I2P ne prenait pas en charge les ports et les numéros de protocole avant la version 0.7.1, les ports et les numéros de protocole sont légèrement différents de ceux utilisés dans l’IP standard, pour des raisons de compatibilité ascendante :
- Le port 0 est valide et a une signification particulière.
- Les ports 1 à 1023 ne sont ni spéciaux ni privilégiés.
- Les serveurs écoutent sur le port 0 par défaut, ce qui signifie « tous les ports ».
- Les clients envoient vers le port 0 par défaut, ce qui signifie « n’importe quel port ».
- Les clients envoient depuis le port 0 par défaut, ce qui signifie « non spécifié ».
- Un serveur peut avoir un service à l’écoute sur le port 0 et d’autres services à l’écoute sur des ports supérieurs. Dans ce cas, le service sur le port 0 est celui par défaut, et une connexion sera établie avec lui si le port de la socket entrante ou du datagramme ne correspond à aucun autre service.
- La plupart des destinations I2P n’exécutent qu’un seul service, vous pouvez donc utiliser les valeurs par défaut et ignorer la configuration du port I2CP.
- Le protocole 0 est valide et signifie « n’importe quel protocole ». Toutefois, cela n’est pas recommandé et ne fonctionnera probablement pas. Le streaming nécessite que le numéro de protocole soit défini à 6.
- Les sockets de streaming sont suivis par un identifiant de connexion interne. Par conséquent, il n’est pas nécessaire que le 5-tuple de dest:port:dest:port:protocole soit unique. Par exemple, il peut exister plusieurs sockets avec les mêmes ports entre deux destinations. Les clients n’ont pas besoin de choisir un « port libre » pour une connexion sortante.
Travaux futurs
- Le mécanisme d’autorisation actuel pourrait être modifié pour utiliser des mots de passe hachés.
- La clé privée de signature est incluse dans le message Create Lease Set, ce qui n’est pas nécessaire. La révocation n’est pas implémentée. Elle devrait être remplacée par des données aléatoires ou supprimée.
- Certaines améliorations pourraient être capables d’utiliser des messages précédemment définis mais non implémentés.