2004-07-20 11:51:47 +00:00
|
|
|
<p>Specified below is a simple client protocol for interacting with
|
|
|
|
I2P based on discussions between human and jrandom.</p>
|
|
|
|
|
|
|
|
<pre>----------------------------------------------------------------------
|
|
|
|
Simple Anonymous Messaging (SAM)
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Client application talks to SAM bridge, which deals with
|
|
|
|
all of the I2P functionality (using the ministreaming
|
|
|
|
lib for virtual streams, or I2CP directly for async messages).
|
|
|
|
|
|
|
|
All client<-->SAM bridge communication is unencrypted and
|
|
|
|
unauthenticated over a single TCP socket. Access to the SAM
|
|
|
|
bridge should be protected through firewalls or other means
|
|
|
|
(perhaps the bridge may have ACLs on what IPs it accepts
|
|
|
|
connections from).
|
|
|
|
|
|
|
|
All of these SAM messages are sent on a single line in plain ASCII,
|
|
|
|
terminated by the newline character (\n). The formatting shown
|
|
|
|
below is merely for readability, and while the first two words in
|
|
|
|
each message must stay in their specific order, the ordering of
|
|
|
|
the key=value pairs can change (e.g. "ONE TWO A=B C=D" or
|
|
|
|
"ONE TWO C=D A=B" are both perfectly valid constructions). In
|
|
|
|
addition, the protocol is case-sensitive.
|
|
|
|
|
|
|
|
Communication can take three distinct forms:
|
|
|
|
* Virtual streams
|
|
|
|
* Repliable datagrams (messages with a FROM field)
|
|
|
|
* Anonymous datagrams (raw anonymous messages)
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
SAM connection handshake
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
No SAM communication can occur until after the client and bridge have
|
|
|
|
agreed on a protocol version, which is done by the client sending
|
|
|
|
a HELLO and the bridge sending a HELLO REPLY:
|
|
|
|
|
|
|
|
HELLO VERSION MIN=$min MAX=$max
|
|
|
|
|
|
|
|
and
|
|
|
|
|
|
|
|
HELLO REPLY RESULT=$result VERSION=1.0
|
|
|
|
|
|
|
|
The current version for both must be "1.0".
|
|
|
|
|
|
|
|
The RESULT value may be one of:
|
|
|
|
|
|
|
|
OK
|
|
|
|
NOVERSION
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
SAM sessions
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
A SAM session is created by a client opening a socket to the SAM
|
|
|
|
bridge, operating a handshake, and sending a SESSION CREATE message,
|
|
|
|
and the session terminates when the socket is disconnected.
|
|
|
|
|
|
|
|
Each I2P Destination can only be used for one SAM session at a time,
|
|
|
|
and can only use one of those forms (messages received through other
|
|
|
|
forms are dropped).
|
|
|
|
|
|
|
|
The SESSION CREATE message sent by the client to the bridge is as
|
|
|
|
follows:
|
|
|
|
|
|
|
|
SESSION CREATE
|
|
|
|
STYLE={STREAM,DATAGRAM,RAW}
|
|
|
|
DESTINATION={$name,TRANSIENT}
|
|
|
|
[DIRECTION={BOTH,RECEIVE,CREATE}]
|
|
|
|
[option=value]*
|
|
|
|
|
|
|
|
DESTINATION specifies what destination should be used for
|
|
|
|
sending and receiving messages/streams. If a $name is given, the
|
|
|
|
SAM bridge looks through its own local storage for an associated
|
|
|
|
destination (and private key). If no association exists matching
|
|
|
|
that name, it creates a new one. If the destination is specified
|
|
|
|
as TRANSIENT, it always creates a new one.
|
|
|
|
|
|
|
|
The DIRECTION can be specified for STREAM sessions, instructing
|
|
|
|
the bridge that the client will either be creating or receiving
|
|
|
|
streams, or both. If this is not specified, BOTH will be assumed.
|
|
|
|
Attempting to create an outbound stream when DIRECTION=RECEIVE
|
|
|
|
should result in an error, and incoming streams when
|
|
|
|
DIRECTION=CREATE should be ignored.
|
|
|
|
|
|
|
|
Additional options given should be fed into the I2P session
|
|
|
|
configuration if not interpreted by the SAM bridge (e.g.
|
|
|
|
"tunnels.depthInbound=0").
|
|
|
|
|
|
|
|
The SAM bridge itself should already be configured with what router
|
|
|
|
it should communicate over I2P through (though if need be there may
|
|
|
|
be a way to provide an override, e.g. i2cp.tcp.host=localhost and
|
|
|
|
i2cp.tcp.port=7654).
|
|
|
|
|
|
|
|
After receiving the session create message, the SAM bridge will reply
|
|
|
|
with a session status message, as follows:
|
|
|
|
|
|
|
|
SESSION STATUS
|
|
|
|
RESULT=$result
|
|
|
|
DESTINATION={$name,TRANSIENT}
|
|
|
|
[MESSAGE=...]
|
|
|
|
|
|
|
|
The RESULT value may be one of:
|
|
|
|
|
|
|
|
OK
|
|
|
|
DUPLICATED_DEST
|
|
|
|
I2P_ERROR
|
|
|
|
INVALID_KEY
|
|
|
|
|
|
|
|
If it's not OK, the MESSAGE should contain human-readable information
|
|
|
|
as to why the session could not be created.
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
SAM virtual streams
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Virtual streams are guaranteed to be sent reliably and in order, with
|
|
|
|
failure and success notification as soon as it is available.
|
|
|
|
|
|
|
|
After establishing the session with STYLE=STREAM, both the client
|
|
|
|
and the SAM bridge may asynchronously send various messages back and
|
|
|
|
forth to manage the streams, as listed below:
|
|
|
|
|
|
|
|
STREAM CONNECT
|
|
|
|
ID=$id
|
|
|
|
DESTINATION=$base64key
|
|
|
|
|
|
|
|
This establishes a new virtual connection from the local destination
|
|
|
|
to the specified peer, marking it with the session-scoped unique ID.
|
|
|
|
The unique ID is an ASCII base 10 integer from 1 through (2^31-1).
|
|
|
|
The SAM bridge must reply to this with a stream status message:
|
|
|
|
|
|
|
|
STREAM STATUS
|
|
|
|
RESULT=$result
|
|
|
|
ID=$id
|
|
|
|
[MESSAGE=...]
|
|
|
|
|
|
|
|
The RESULT value may be one of:
|
|
|
|
|
|
|
|
OK
|
|
|
|
CANT_REACH_PEER
|
|
|
|
I2P_ERROR
|
|
|
|
INVALID_KEY
|
|
|
|
TIMEOUT
|
|
|
|
|
|
|
|
If the RESULT is OK, the destination specified is up and authorized
|
|
|
|
the connection; if the connection was not possible (timeout, etc),
|
|
|
|
RESULT will contain the appropriate error value (accompanied by an
|
|
|
|
optional human-readable MESSAGE).
|
|
|
|
|
|
|
|
On the receiving end, the SAM bridge simply notifies the client as
|
|
|
|
follows:
|
|
|
|
|
|
|
|
STREAM CONNECTED
|
|
|
|
DESTINATION=$base64key
|
|
|
|
ID=$id
|
|
|
|
|
|
|
|
This tells the client that the given destination has created a virtual
|
|
|
|
connection with them. The following data stream will be marked with
|
|
|
|
the given unique ID, that is an ASCII base 10 integer from -1 through
|
|
|
|
-(2^31-1).
|
|
|
|
|
|
|
|
When the client wants to send data on the virtual connection, they
|
|
|
|
do so as follows:
|
|
|
|
|
|
|
|
STREAM SEND
|
|
|
|
ID=$id
|
|
|
|
SIZE=$numBytes\n[$numBytes of data]
|
|
|
|
|
|
|
|
This adds the specified data to the buffer being sent to the peer
|
|
|
|
over the virtual connection. The send size $numBytes is how many
|
|
|
|
8bit bytes are included after the newline, which may be 1 through
|
|
|
|
32768 (32KB).
|
|
|
|
|
|
|
|
The SAM bridge will then do its best to deliver the message as
|
|
|
|
quickly and efficiently as possible, perhaps buffering multiple SEND
|
|
|
|
messages together. If there is an error delivering the data, or if
|
|
|
|
the remote side closes the connection, the SAM bridge will tell the
|
|
|
|
client:
|
|
|
|
|
|
|
|
STREAM CLOSED
|
|
|
|
RESULT=$result
|
|
|
|
ID=$id
|
|
|
|
[MESSAGE=...]
|
|
|
|
|
|
|
|
The RESULT value may be one of:
|
|
|
|
|
|
|
|
OK
|
|
|
|
CANT_REACH_PEER
|
|
|
|
I2P_ERROR
|
|
|
|
PEER_NOT_FOUND
|
|
|
|
TIMEOUT
|
|
|
|
|
|
|
|
If the connection has been cleanly closed by the other peer, $result
|
|
|
|
is set to OK. If $result is not OK, MESSAGE may convey a descriptive
|
|
|
|
message, such as "peer unreachable", etc. Whenever a client would
|
|
|
|
like to close the connection, they send the SAM bridge the close
|
|
|
|
message:
|
|
|
|
|
|
|
|
STREAM CLOSE
|
|
|
|
ID=$id
|
|
|
|
|
|
|
|
The bridge then cleans up what it needs to and discards that ID - no
|
|
|
|
further messages can be sent or received on it.
|
|
|
|
|
|
|
|
For the other side of the communication, whenever the peer has sent
|
|
|
|
some data and it is available for the client, the SAM bridge will
|
|
|
|
promptly deliver it:
|
|
|
|
|
|
|
|
STREAM RECEIVED
|
|
|
|
ID=$id
|
|
|
|
SIZE=$numBytes\n[$numBytes of data]
|
|
|
|
|
|
|
|
All streams are implicitly closed by the connection between the SAM
|
|
|
|
bridge and the client being dropped.
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
SAM repliable datagrams
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
While I2P doesn't inherently contain a FROM address, for ease of use
|
|
|
|
an additional layer is provided as repliable datagrams - unordered
|
|
|
|
and unreliable messages of up to 31KB in size that include a FROM
|
|
|
|
address (leaving up to 1KB for header material). This FROM address
|
|
|
|
is authenticated internally by SAM (making use of the destination's
|
|
|
|
signing key to verify the source) and includes replay prevention.
|
|
|
|
|
|
|
|
After establishing a SAM session with STYLE=DATAGRAM, the client can
|
|
|
|
send the SAM bridge:
|
|
|
|
|
|
|
|
DATAGRAM SEND
|
|
|
|
DESTINATION=$base64key
|
|
|
|
SIZE=$numBytes\n[$numBytes of data]
|
|
|
|
|
|
|
|
When a datagram arrives, the bridge delivers it to the client via:
|
|
|
|
|
|
|
|
DATAGRAM RECEIVED
|
|
|
|
DESTINATION=$base64key
|
|
|
|
SIZE=$numBytes\n[$numBytes of data]
|
|
|
|
|
|
|
|
The SAM bridge never exposes to the client the authentication headers
|
|
|
|
or other fields, merely the data that the sender provided. This
|
|
|
|
continues until the session is closed (by the client dropping the
|
|
|
|
connection).
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
SAM anonymous datagrams
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Squeezing the most out of I2P's bandwidth, SAM allows clients to send
|
|
|
|
and receive anonymous datagrams, leaving authentication and reply
|
|
|
|
information up to the client themselves. These datagrams are
|
|
|
|
unreliable and unordered, and may be up to 32KB in size.
|
|
|
|
|
|
|
|
After establishing a SAM session with STYLE=RAW, the client can
|
|
|
|
send the SAM bridge:
|
|
|
|
|
|
|
|
RAW SEND
|
|
|
|
DESTINATION=$base64key
|
|
|
|
SIZE=$numBytes\n[$numBytes of data]
|
|
|
|
|
|
|
|
When a raw datagram arrives, the bridge delivers it to the client
|
|
|
|
via:
|
|
|
|
|
|
|
|
RAW RECEIVED
|
|
|
|
SIZE=$numBytes\n[$numBytes of data]
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
SAM utility functionality
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
The following message can be used by the client to query the SAM
|
|
|
|
bridge for name resolution:
|
|
|
|
|
|
|
|
NAMING LOOKUP
|
|
|
|
NAME=$name
|
|
|
|
|
|
|
|
which is answered by
|
|
|
|
|
|
|
|
NAMING REPLY
|
|
|
|
RESULT=$result
|
|
|
|
NAME=$name
|
|
|
|
[VALUE=$base64key]
|
|
|
|
[MESSAGE=$message]
|
|
|
|
|
|
|
|
|
|
|
|
The RESULT value may be one of:
|
|
|
|
|
|
|
|
OK
|
|
|
|
INVALID_KEY
|
|
|
|
KEY_NOT_FOUND
|
|
|
|
|
|
|
|
If NAME=ME, then the reply will contain the base64key used by the
|
|
|
|
current session (useful if you're using a TRANSIENT one). If $result
|
|
|
|
is not OK, MESSAGE may convey a descriptive message, such as "bad
|
|
|
|
format", etc.
|
|
|
|
|
|
|
|
Public and private base64 keys can be generated using the following
|
|
|
|
message:
|
|
|
|
|
|
|
|
DEST GENERATE
|
|
|
|
|
|
|
|
which is answered by
|
|
|
|
|
|
|
|
DEST REPLY
|
|
|
|
PUB=$pubkey
|
|
|
|
PRIV=$privkey
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
RESULT values
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
These are the values that can be carried by the RESULT field, with
|
|
|
|
their meaning:
|
|
|
|
|
|
|
|
OK Operation completed succesfully
|
|
|
|
CANT_REACH_PEER The peer exists, but cannot be reached
|
|
|
|
DUPLICATED_DEST The specified Destination is already in use
|
|
|
|
I2P_ERROR A generic I2P error (e.g. I2CP disconnection, etc.)
|
|
|
|
INVALID_KEY The specified key is not valid (bad format, etc.)
|
|
|
|
KEY_NOT_FOUND The naming system can't resolve the given name
|
|
|
|
PEER_NOT_FOUND The peer cannot be found on the network
|
|
|
|
TIMEOUT Timeout while waiting for an event (e.g. peer answer)
|
2004-09-19 21:55:49 +00:00
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Client library implementations:
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
C/C++: libSAM: http://www.innographx.com/mpc/libsam/ or i2p/sam/c/
|
|
|
|
Python: Python/I2P: http://dev.i2p.net/contrib/apps/sam/python/index.html
|
|
|
|
Others: See apps/sam/ in I2P CVS.
|
2004-07-20 11:51:47 +00:00
|
|
|
</pre>
|