Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module provides the main interface for establishing secure and anonymous connections with other hosts on the interface using the Invisible Internet Project (I2P). For more information about the I2P network, see: geti2p.net
- defaultEndPoint :: EndPoints
- createDestination :: (MonadIO m, MonadMask m) => EndPoints -> Maybe SignatureType -> m (PrivateDestination, PublicDestination)
- withSession :: (MonadIO m, MonadMask m) => EndPoints -> SocketType -> (Context -> m a) -> m a
- withSession' :: (MonadIO m, MonadMask m) => EndPoints -> SocketType -> (PrivateDestination, PublicDestination) -> (Context -> m a) -> m a
- connectStream :: (MonadIO m, MonadMask m) => Context -> PublicDestination -> ((Socket, PublicDestination) -> IO ()) -> m ()
- serveStream :: (MonadIO m, MonadMask m) => Context -> ((Socket, PublicDestination) -> IO ()) -> m ()
- serveDatagram :: (MonadIO m, MonadMask m) => Context -> ((ByteString, Maybe PublicDestination) -> IO ()) -> m ()
- sendDatagram :: (MonadIO m, MonadMask m) => Context -> PublicDestination -> ByteString -> m ()
Introduction to I2P
This module is an implementation of the SAMv3 protocol for I2P. I2P is an internet anonimization network, similar to Tor. Whereas Tor is primarily intended for privately browsing the world wide web, I2P is more application oriented, and is intended for private communication between applications.
The general idea of the SAM interface to I2P is that you establish a master connection with the SAM bridge, and create new, short-lived connections with the SAM bridge for the communication with the individual peers.
I2P provides three different ways of communicating with other hosts:
- Virtual Streams: similar to reliable TCP sockets, data is guaranteed to be delivered, and in order. You can accept virtual streams and connect to remote virtual streams, and use regular sockets to transmit the actual messages.
- Repliable Datagrams: unreliable delivery of messages to a remote host, but adds a reply-to address to the message so the remote host can send a message back.
- Anonymous Datagrams: unreliable delivery of messages to a remote host, and the remote host has no way to find out who sent the message.
Different methods of communication have different performance characteristics, and an application developer should take these into careful consideration when developing an application.
Client side
Virtual Stream
Establishing a VirtualStream
connection with a remote works as follows:
main =withSession
defaultEndPoint
VirtualStream
withinSession where dest ::PublicDestination
dest = undefined withinSession ::Context
-> IO () withinSession ctx =connectStream
ctx dest worker worker (sock, addr) = do -- Now you may use sock to communicate with the remote; addr contains -- the address of the remote we are connected to, which on our case -- should match dest. return ()
Datagram
Sending a DatagramRepliable
message to a remote:
main =withSession
defaultEndPoint
DatagramRepliable
withinSession where dest ::PublicDestination
dest = undefined withinSession ::Context
-> IO () withinSession ctx = dosendDatagram
ctx dest "Hello, anonymous world!" -- SAM requires the master connection of a session to be alive longer -- than any opertions that occur on the session are. Since sending a -- datagram returns before the datagram might be actually handled by -- I2P, it is adviced to wait a little while before closing the session. threadDelay 1000000
Server side
Virtual Stream
Running a server that accepts VirtualStream
connections.
main =withSession
defaultEndPoint
VirtualStream
withinSession where withinSession ::Context
-> IO () withinSession ctx =serveStream
ctx worker worker (sock, addr) = do -- Now you may use sock to communicate with the remote; addr contains -- the address of the remote we are connected to, which we might want -- to store to send back messages asynchronously. return ()
Datagram
Receiving DatagramAnonymous
messages from remotes:
main =withSession
defaultEndPoint
DatagramAnonymous
withinSession where withinSession ::Context
-> IO () withinSession ctx =serveDatagram
ctx worker worker (sock, addr) = do -- Now you may use sock to communicate with the remote; addr is an -- instance of theMaybe
monad, and since we only accept anonymous -- messages, should always beNothing
. return ()
Setting up the context
defaultEndPoint :: EndPoints Source
The default host/port SAM uses
:: (MonadIO m, MonadMask m) | |
=> EndPoints | Our SAM bridge endpoints |
-> Maybe SignatureType | Algorithm to use for signature encryption. As per I2P spec defaults to DSA_SHA1. |
-> m (PrivateDestination, PublicDestination) | The private and public destinations. |
Create a new I2P destination endpoint.
All communication in I2P starts with having our own host endpoint
other people can use to communicate with us. This destination consists
of a public and a private part: the PrivateDestination
you can use
to accept connections / messages from other people, the PublicDestination
you can give out to other people to send messages to you.
Warning: Never give out your PrivateDestination
to other people. It
contains your private key, and could be used by other people
to effectively MITM you. Use your PublicDestination
to announce
the address other people can connect to.
:: (MonadIO m, MonadMask m) | |
=> EndPoints | Our SAM bridge endpoints |
-> SocketType | The type of socket we will be using. |
-> (Context -> m a) | The computation to run |
-> m a |
Starts a new I2P session. A connection with the SAM bridge will be
established, and a Context
object will be created and passed to the
callback. This context object is then required for all further operations.
After the callback computation finishes, all acquired resources will be properly closed.
:: (MonadIO m, MonadMask m) | |
=> EndPoints | Our SAM bridge endpoints |
-> SocketType | The type of socket we will be using. |
-> (PrivateDestination, PublicDestination) | Destination to use |
-> (Context -> m a) | The computation to run |
-> m a |
Alternative implementation of withSession
that explicitly accepts a
Destination
pair to use to set up the session. This can be useful
if you want to use a specific SignatureType
to create a local
endpoint.
Virtual streams
:: (MonadIO m, MonadMask m) | |
=> Context | Our state |
-> PublicDestination | Destination to connect to. |
-> ((Socket, PublicDestination) -> IO ()) | Computation to run once connection has been established. |
-> m () |
Connects to a remote VirtualStream
host. Any acquired resources are
cleaned up when the computation ends. Automatically creates a local return
destination required for bi-directional communication.
serveStream :: (MonadIO m, MonadMask m) => Context -> ((Socket, PublicDestination) -> IO ()) -> m () Source
Starts a server to accept VirtualStream
connections from other hosts
and handles them concurrently in different threads. Any acquired resources
are cleaned up when the computation ends.
Datagrams
serveDatagram :: (MonadIO m, MonadMask m) => Context -> ((ByteString, Maybe PublicDestination) -> IO ()) -> m () Source
Starts a server to accept DatagramAnonymous
or DatagramRepliable
connections from other hosts and handles them concurrently in different
threads. Any acquired resources are cleaned up when the computation ends.
:: (MonadIO m, MonadMask m) | |
=> Context | Our context |
-> PublicDestination | Destination to send message to |
-> ByteString | The message to send |
-> m () |
Sends a datagram to a remote destination.
Warning: This function returns before the actual datagram has arrived at
and handled by the SAM bridge. If you close the session opened
with withSession
, a race condition will occur where the datagram
will possibly arrive after the session has been closed, and as
such will never be delivered.