Resumen
El Protocolo de Cliente I2P (I2CP) proporciona una fuerte separación de responsabilidades entre el enrutador y cualquier cliente que desee comunicarse a través de la red. Permite mensajería segura y asincrónica enviando y recibiendo mensajes sobre un único socket TCP. Con I2CP, una aplicación cliente le indica al enrutador quién es (su “destino”), qué compensaciones hacer en cuanto a anonimato, confiabilidad y latencia, y a dónde enviar los mensajes. A su vez, el enrutador utiliza I2CP para informar al cliente cuándo han llegado mensajes, y para solicitar autorización para utilizar ciertos túneles.
El protocolo en sí está implementado en Java, para proporcionar el SDK del cliente. Este SDK se expone en el paquete i2p.jar, que implementa el lado cliente de I2CP. Los clientes nunca deberían necesitar acceder al paquete router.jar, que contiene el enrutador mismo y el lado del enrutador de I2CP. Un cliente que no sea en Java también tendría que implementar la biblioteca de streaming para conexiones de estilo TCP.
Las aplicaciones pueden aprovechar el I2CP base junto con las bibliotecas de transmisión continua y datagramas mediante el uso del protocolo Simple Anonymous Messaging (SAM) , que no requiere que los clientes gestionen ningún tipo de criptografía. Además, los clientes pueden acceder a la red a través de varios proxies: HTTP, CONNECT y SOCKS 4/4a/5. Alternativamente, los clientes en Java pueden acceder a esas bibliotecas mediante ministreaming.jar y streaming.jar. Por tanto, existen varias opciones tanto para aplicaciones en Java como para aplicaciones no Java.
La encriptación de extremo a extremo en el lado del cliente (encriptar los datos a través de la conexión I2CP) fue deshabilitada en la versión 0.6 de I2P, dejando únicamente la encriptación de extremo a extremo ElGamal/AES que se implementa en el router. La única criptografía que aún deben implementar las bibliotecas cliente es la firma de claves pública/privada DSA para LeaseSets y Configuraciones de Sesión , así como la gestión de esas claves.
En una instalación estándar de I2P, el puerto 7654 es utilizado por clientes Java externos para comunicarse con el router local mediante I2CP. Por defecto, el router se enlaza a la dirección 127.0.0.1. Para enlazarlo a 0.0.0.0, establezca la opción avanzada de configuración del router i2cp.tcp.bindAllInterfaces=true y reinicie. Los clientes que se ejecutan en la misma JVM que el router pasan los mensajes directamente al router a través de una interfaz interna de la JVM.
Algunas implementaciones del router y del cliente también pueden admitir conexiones externas a través de SSL, según esté configurado mediante la opción i2cp.SSL=true. Aunque SSL no es el valor predeterminado, se recomienda encarecidamente para cualquier tráfico que pueda estar expuesto a Internet. El usuario y la contraseña de autorización (si los hay), la Clave Privada
y la Clave Privada de Firma
para el Destino
se transmiten en texto claro a menos que SSL esté habilitado. Algunas implementaciones del router y del cliente también pueden admitir conexiones externas mediante sockets de dominio.
Especificación del Protocolo I2CP
Consulta la página de la especificación I2CP para obtener la especificación completa del protocolo.
Inicialización de I2CP
Cuando un cliente se conecta al router, primero envía un único byte de versión de protocolo (0x2A). Luego envía un Mensaje GetDate y espera la respuesta del Mensaje SetDate . A continuación, envía un Mensaje CreateSession que contiene la configuración de la sesión. Después espera un Mensaje RequestLeaseSet del router, lo cual indica que los túneles entrantes han sido creados, y responde con un CreateLeaseSetMessage que contiene el LeaseSet firmado. El cliente ya puede iniciar o recibir conexiones desde otras destinaciones I2P.
Opciones I2CP
Opciones del lado del router
Las siguientes opciones se pasan tradicionalmente al router mediante un SessionConfig contenido en un CreateSession Message o un ReconfigureSession Message .
| 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:
| |
Nota: A partir de la versión 0.7.7, los nombres y valores de las opciones deben usar codificación UTF-8. Esto es principalmente útil para apodos. Antes de esa versión, las opciones con caracteres multibyte se corrompían. Dado que las opciones están codificadas en un Mapping , todos los nombres y valores de opciones están limitados a un máximo de 255 bytes (no caracteres).
Opciones del lado del cliente
Las siguientes opciones se interpretan en el lado del cliente y serán interpretadas si se pasan a la I2PSession mediante la llamada I2PClient.createSession(). La biblioteca de streaming también debería pasar estas opciones a I2CP. Otras implementaciones pueden tener valores predeterminados diferentes.
| 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. | ||
Formato de Datos de Carga I2CP y Multiplexación
Los mensajes de extremo a extremo gestionados por I2CP (es decir, los datos enviados por el cliente en un SendMessageMessage y recibidos por el cliente en un MessagePayloadMessage ) están comprimidos con un encabezado gzip estándar de 10 bytes que comienza con 0x1F 0x8B 0x08 según lo especificado por RFC 1952 . A partir de la versión 0.7.1, I2P utiliza partes ignoradas del encabezado gzip para incluir información de protocolo, puerto de origen y puerto de destino, lo que permite el uso de streaming y datagramas en el mismo destino, y hace posible que las consultas/respuestas mediante datagramas funcionen de forma confiable incluso con múltiples canales.
La función gzip no puede desactivarse completamente; sin embargo, establecer i2cp.gzip=false fija el nivel de compresión gzip en 0, lo cual podría ahorrar un poco de CPU. Las implementaciones pueden seleccionar distintos niveles de compresión gzip por socket o por mensaje, dependiendo de una evaluación de la capacidad de compresión del contenido. Debido a la capacidad de compresión del relleno del destino implementado en la API 0.9.57 (propuesta 161), se recomienda la compresión de los paquetes SYN del flujo en ambas direcciones, así como de los datagramas con respuesta, incluso si la carga útil no es compresible. Las implementaciones podrían considerar escribir una función trivial de gzip/gunzip para un esfuerzo de compresión 0, lo que proporcionaría grandes mejoras de eficiencia frente a una biblioteca gzip en este caso.
| 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) |
La integridad de los datos se verifica con el CRC-32 estándar de gzip según lo especificado en RFC 1952 .
Diferencias importantes con respecto a IP estándar
Los puertos I2CP son para sockets y datagramas de I2P. No tienen relación con tus sockets o puertos locales. Debido a que I2P no admitía puertos ni números de protocolo antes de la versión 0.7.1, los puertos y números de protocolo son algo diferentes a los del protocolo IP estándar, por compatibilidad con versiones anteriores:
- El puerto 0 es válido y tiene un significado especial.
- Los puertos 1-1023 no son especiales ni privilegiados.
- Los servidores escuchan en el puerto 0 por defecto, lo que significa “todos los puertos”.
- Los clientes envían al puerto 0 por defecto, lo que significa “cualquier puerto”.
- Los clientes envían desde el puerto 0 por defecto, lo que significa “no especificado”.
- Los servidores pueden tener un servicio escuchando en el puerto 0 y otros servicios escuchando en puertos superiores. En ese caso, el servicio del puerto 0 es el predeterminado y se conectará a él si el puerto del socket entrante o del datagrama no coincide con otro servicio.
- La mayoría de los destinos I2P solo tienen un servicio en ejecución, por lo que puedes usar los valores predeterminados e ignorar la configuración de puertos I2CP.
- El protocolo 0 es válido y significa “cualquier protocolo”. Sin embargo, no se recomienda y probablemente no funcione. El protocolo de streaming requiere que el número de protocolo se establezca en 6.
- Los sockets de streaming se rastrean mediante un ID interno de conexión. Por lo tanto, no es necesario que la 5-tupla de dest:puerto:dest:puerto:protocolo sea única. Por ejemplo, puede haber múltiples sockets con los mismos puertos entre dos destinos. Los clientes no necesitan elegir un “puerto libre” para una conexión saliente.
Trabajo Futuro
- El mecanismo de autorización actual podría modificarse para usar contraseñas hasheadas.
- La clave privada de firma se incluye en el mensaje Crear Conjunto de Arrendamiento (Create Lease Set), pero no es necesaria. La revocación no está implementada. Debería reemplazarse con datos aleatorios o eliminarse.
- Algunas mejoras podrían ser capaces de usar mensajes previamente definidos pero no implementados.