network-anonymous-i2p-0.9.0: Haskell API for I2P anonymous networking

Safe HaskellNone
LanguageHaskell2010

Network.Anonymous.I2P

Contents

Description

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

Synopsis

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 intended for privately using the internet, 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: the closest thing to reliable TCP sockets that I2P brings, and allows you to start a server, accept connections and establish connections with remote servers.
  • 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 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 DatagramRepliable withinSession

   where
     dest :: PublicDestination
     dest = undefined

     withinSession -> Context -> IO ()
     withinSession ctx = do
       sendDatagram 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 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 a DatagramAnonymous messages from remotes:

   main = withSession 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 the Maybe monad, and since we only accept anonymous
       -- messages, should always be Nothing.
       return ()
 

Setting up the context

createDestination Source

Arguments

:: (MonadIO m, MonadMask m) 
=> 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.

withSession Source

Arguments

:: (MonadIO m, MonadMask m) 
=> 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.

withSession' Source

Arguments

:: (MonadIO m, MonadMask m) 
=> 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

connectStream Source

Arguments

:: (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.

sendDatagram Source

Arguments

:: (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.