The Censorship Resistant Internet - Part 2: How to Run an I2P Hidden Service

by p4bl0

0x0 - Introduction

This is the second part of a series of articles explaining how to run censorship resistant services on the Internet.

The first one, which was about the Tor technology, appeared in the Summer 2017 issue, and I assume here that the reader is familiar with it.1  As the title says, this time I will talk about I2P2, the Invisible Internet Project.

Tor and I2P are comparable technologies in that they are made to enable anonymous usage of the Internet.  They differ in their threat-model and thus in their design.  From a user's point of view, we can simplify things and say that Tor is better as a proxy (anonymously going out of the mixnet) while I2P is better at hidden services (anonymously staying inside the mixnet).  Most other differences are more technical and I will discuss them as needed in the rest of the article.

To transmit data anonymously, I2P uses what is called "garlic routing," which is a loose name in reference to onion routing and to the fact that messages can be bundled (like cloves inside a garlic bulb).  The principle of garlic routing is that potentially bundled messages are sent to their destination (a cryptographic key) by going through tunnels.  Unlike Tor circuits, I2P tunnels are attached to a router and are unidirectional.

A router is simply a running instance of an I2P implementation: I2P being fully decentralized (contrary to Tor which needs centralized directories - that I incorrectly called "distributed hash table" in the previous article, sorry!), each client is also a router and participates to the network.

In addition to the participation to other routers' tunnels, each router is responsible for the creation of inbound and outbound tunnels (remember that tunnels are unidirectional) for itself and for its local destinations (understand "services").

Each tunnel is composed of one or more participants, which includes the local router itself.  Of course, a tunnel with less participants offers a weaker anonymity guarantee (down to no anonymity with a single participant).

The first participant of a tunnel is called the gateway and the last participant is called the endpoint.  For inbound tunnels the local router is the endpoint, and for outbound tunnels it is the gateway.  I do not have enough space here to details how tunnels are built, but it is sufficient for our purpose to know that there is a distributed database maintained by a subset of all routers (those which opted-in) called the NetDB which contains routers contact information (called "RouterInfos", which for example contains the public address of the router), and public destinations contact information (called LeaseSets, which for example contains the list of inbound gateways to the destination).

Each router has complete knowledge of the RouterInfos of the participants of its tunnels, but a participant of a tunnel does not know much about it: it only knows which router it receives data from and which one it has to sends data to, and thus, it is also aware if it is an inbound gateway or an outbound endpoint, but that's all.

Now let's have a quick look to how tunnels are used.

When a message is sent in I2P, it necessarily goes through an outbound tunnel of its source and then through an inbound tunnel of its destination.  The outbound gateway is responsible for preprocessing the message which involves splitting it into fixed-size (1 kB) fragments and iteratively encrypting them along with delivery instructions for layered decryption by the outbound tunnel participants.  After that, each fragment is forwarded to the next participant.  Each participant decrypts the fragments it receives and forward them to the next, until the endpoint is reached.

At this point, once the outbound endpoint has decrypted the fragments, it reassembles them to recover the preprocessed message, which is then forwarded to the inbound tunnel gateway.  In turn, the inbound gateway splits the message in fixed-size (still 1 kB) fragments, but this time it only encrypts them once, before forwarding them to the next participant.

Each participant encrypts the fragments it receives and forward them to the next, until the endpoint is reached.  Then, the endpoint iteratively decrypts the fragments and reassembles them.  The message is arrived at destination.

I'm simplifying things here as my goal is only to give an overview of how I2P routing works.  This way of transmitting messages allows I2P to use packet switching.  This is actually a major difference with how Tor circuits work: it means that I2P can take advantage of the existence of multiple tunnels not only for resilience but also for bandwidth (by balancing loads) and that tunnels can be short-lived (I2P renew them every 10 minutes by default) rather than long-lived like Tor circuits, which makes traffic analysis harder.

Just like Tor, I2P can be used for so many things besides running and using anonymous services.  The default install comes with a webserver and a BitTorrent client, for example.

Now that we have seen a quick overview of how I2P works under the hood (more curious readers are encouraged to give a look at the awesome I2P technical documentation), let's start working on our goal: how to run an I2P hidden service?

0x1 - Installations

There are several implementations of I2P.  The two major ones are the original I2P (written in Java) and the more recent i2pd (in C++)3.  The latter probably has a smaller footprint than the former and its configuration is easier to manage (flat files instead of web UI), but it still crashed way too often the last time I tried to switch to it (I confess it has been almost a year).

Just like in the previous part on Tor, I will be giving instructions for Debian stable (which, unlike last time, is now Stretch).

So, to install I2P, create a new file /etc/apt/sources.list.d/i2p.list with this content (you need to be root or to use sudo):

deb https://deb.i2p2.de/ stretch main
deb-src https://deb.i2p2.de/ stretch main

Save it and then add the GPG key that signs I2P packages to apt by issuing the following commands:

$ wget https://geti2p.net/_static/i2p-debian-repo.key.asc
$ sudo apt-key add i2p-debian-repo.key.asc

The first one will retrieve the key and the second one will add it to apt.  You can now issue the usual sudo apt-get update and it will retrieve the list of packages from the I2P repository.  Then, install I2P and the I2P keyring so that the necessary GPG keys will be kept in sync and you do not have to worry about that later:

$ sudo apt-get install i2p i2p-keyring

That's it.  If you encounter any trouble regarding the use of HTTPS, installing the apt-transport-https package should fix it.

0x2 - The I2P Console

Once I2P is installed, your router should be running and its console waiting for you on: http://127.0.0.1:7657

If it is not running, you can issue the command sudo service i2p start to start the router.

When you point your browser on the I2P web console, you will be able to see the network status in the sidebar.  At the beginning I2P is starting and searching for peers to build tunnels.  If after a little while the network status is not "O.K.", you can click on it and you will be redirected to a page which explains the problem and provide potential leads on how to fix the problem (for example, if you are behind a firewall and need to configure it).

By default, the I2P configuration on bandwidth usage is pretty conservative, you can go to http://127.0.0.1:7657/config to change the default to better suit your network connectivity.  Remember that by sharing more you improve your anonymity, as more traffic that is not yours will go through your router.

After that you are all set.  I strongly encourage you to explore what the I2P console has to offer, not only in terms of configuration and information but also in terms of services.

0x3 - Setting Up Your Hidden Service

Please report to the previous part about Tor for my recommendations on where to run your hidden service.  If you install I2P on a remote host (e.g., a VPS), you will still need to access its web console.  For that we are going to use SSH port forwarding ( -L ).  Let's call your remote host vps and assume that your username there is user.  The following SSH command:

$ ssh -C -N -L 7757:127.0.0.1:7657 user@vps

will open a local socket on port 7757 that forwards traffic to and from 127.0.0.1:7657 on vps.

The -C flag enable compression, and the -N tells SSH to not execute any remote command so that it only does the port forwarding and do not open a remote session.

Now you can point your browser to http://127.0.0.1:7757 and you will see your remote I2P console.  Your local I2P console (if any) is still accessible on http://127.0.0.1:7657.  I will now use console as a shortcut for the console host and port - please adapt to your particular situation (local or remote).

To set up a hidden service, you need to go to the tunnel manager, which you will find at http://console/i2ptunnelmgr.  There you will be able to manage both client tunnels and hidden services (which could also be called "server tunnels").

By default there are multiple client tunnels.  You will see that each have a type.  The "standard" type is equivalent to Tor hidden services: you can use it for any TCP service.  Another important type is "Streamr", which can be used to tunnel UDP traffic through I2P (which Tor is incapable of).  All other types are derived from the standard type to specialize for specific services: for example HTTP and IRC types of service respectively filters HTTP headers and IRC commands to minimize risks of breaking your anonymity.

An interesting client tunnel that exists by default is "I2P HTTP Proxy", which binds 127.0.0.1:4444 to, well, an I2P HTTP proxy.  This means that if you tell your browser to use this proxy (in Firefox you go to "Preferences > Advanced > Network", click the "Settings" button of the "Connection" section, choose "Manual proxy configuration" and fill out the host and port for "HTTP Proxy") you will be able to browse eepsites (.i2p websites), but more on that later.

An interesting hidden service that exists by default is "I2P webserver".  Indeed, I2P comes bundle with a web server which is by default binded to 127.0.0.1:7658 and serves files from /usr/share/i2p/eepsite/docroot/.  If you want to use that to host an eepsite, just put your HTML files in the docroot directory and you are almost all set.  You may need to manually start it (there "Start" button in the "Control" column of the table listing your hidden services) and you probably want to edit the configuration of the service (by clicking on its name) and check the "Automatically start tunnel when router starts" box.

I am personally not using the bundled web server but rather the same setup as for my .onion (please refer to Ref. #1).

So, before going further on making the eepsite available to all, let's see how to set up an arbitrary service.  I will use the same simple service as last time with Tor, but keep in mind that the process is the same for an SSH server for instance.

As a reminder, the little service initializes the counter variable at 0 and then for ever: increments counter by one, waits for a connection on port 2600, answers with a single line saying 'Hi' and displaying the number of connection to the service since it has been (re)started:

#!/bin/sh
counter=0
while true; do
  counter=$((counter + 1))
  echo "Hi, 2600 reader! Counter: "$counter"." | busybox nc -l -p 2600
done

In the I2P tunnel manager, we create a new hidden service by clicking the "Create" button at the bottom of the hidden services list after having selected the "Standard" type in the dropdown menu next to it.

This takes us to a rather long form but do not worry, most of the important stuff are at the top.  We chose a name and a description for the service.  Check the "Auto start" box.  The host is 127.0.0.1 (localhost) and the port is 2600 (the one where our little service is waiting for connections).  A default filename for the private key file is filled, I suggest that you customize it to be able to recognize that file later.  Leave the "Local destination" field blank.  The rest of the parameter have sane defaults, but I encourage you to checkout the different options (most of it is either self-explanatory or you probably should not modify it).  Remark that you can choose to encrypt the LeaseSet of your service before it is sent to the netDb, which will only allow people you share your key with to access it.

Important:  Your private key file corresponds to the cryptographic identity of your hidden service.  You want to have a backup of it as you will need it to move your hidden service on another machine or to reinstall it after a crash.  It is located in the /var/lib/i2p/i2p-config directory (you will need to be root to access it).  To reinstall a hidden service you can simply copy your private key file in this directory and indicate its name in the hidden service creation form.

0x4 - Accessing Your Hidden Service

To access I2P hidden services you will need to go through a client tunnel.  For eepsites, you can configure the I2P HTTP Proxy in your web browser as explained above and then go to ̀i2p-projekt.i2p for example (this is an eepsite mirror of I2P project's website).  If it does not work on the first try to not despair, sometimes I2P can be a bit slow to get all the necessary information and setup everything to work properly.

While your browser uses I2P HTTP Proxy, it will use the default outproxy (false.i2p) if you visit the classical web.  As said in introduction, I2P is not intended for that, so you may want to use a different browser or switch back to no proxy settings.  A good solution could be to create a Firefox profile that always uses I2P proxy that you would use only for accessing eepsites.  To do that, launch Firefox with the command firefox -no-remote -ProfileManager.

The -no-remote argument tells Firefox to ignore any running instance of itself (otherwise it would ignore the command line arguments and simply open a new window of the running instance).  Once in the profile manager, create a new profile that you name I2P, select it, and start a Firefox instance for this profile.  Configure it to use the I2P proxy.  Now when you want to browse eepsites, you can launch firefox -no-remote -P I2P (the -P selects the desired profile).

Note that Firefox profiles do not share extensions nor preferences.  This is good privacy-wise as a vanilla browser is harder to uniquely fingerprint than a strongly customized one.  A less optimal but more convenient solution is to use an extension such as FoxyProxy which can tell Firefox to use different proxy settings depending on the URL, so you could tell it to use Tor when the URL matches this regexp ^https?://[^/]*\.onion/.* and I2P when it matches the same regexp but with i2p instead of onion.

To access other types of I2P hidden services, such as an SSH server or our own little greeting-and-counter service, the easier way is to create a SOCKS client tunnel.

Go back to http://127.0.0.1:7567/i2ptunnelmgr and create a new client tunnel of type SOCKS 4/4a/5.

Name it something like "I2P SOCKS Proxy", choose if you want to start it automatically when the router starts, and assign it a port, e.g., 5555.  The rest of the options already have sane defaults, but as for the creation of the hidden service, I encourage you to look at everything.  Once the SOCKS client tunnel is created and started.  You can use it just like we did last time with Tor.

The attentive reader will notice that we still do not know the .i2p name of the hidden service we created!

To get it you need to go back to the tunnel manager at http://console/i2ptunnelmgr and check your list of hidden services.  For services of type HTTP such as the default eepsite, you will have a "Preview" button: it is actually a link so you can right-click it and choose "Copy Link Location" in the context menu to get its address in your clipboard.

For other types of services you will directly be given its "Base32 Address" instead of the button.  For our little service, this address is:

khpazz3f747z5zet72s6g3dccw53bfdqyhxt5da4sv7ouve5veuq.b32.i2p

Yes, this is quite long.  It is the I2P equivalent of Tor's .onion names: the Base32 address of a service is derived from the public-key of the destination.  The good thing is that I2P has a mechanism for getting a .i2p domain that you can freely choose, but before going into how that works, let's connect to our service:

$ nc -X 5 -x 127.0.0.1:5555 khpazz3f747z5zet72s6g3dccw53bfdqyhxt5da4sv7ouve5veuq.b32.i2p 1
Hi, 2600 reader! Counter: 1.

Notice that I give Netcat port number 1.  That is because I2P does not care about the port number.

Apart from that, the SOCKS proxy works like any other including Tor's, so you can configure your SSH client to automatically use it when the host ends in .i2p in the same way that we did last time for Tor.

0x5 - Getting Your Own .i2p Domain

There are three desirable properties that a naming system should meet: it should be decentralized, and names should to be at the same time meaningful and securely unique.  The theory is that you can only get two out of three (this is called Zooko's triangle).

There actually are some sketchs of solutions to get the three at the same time, such as Namecoin or GNU Name System, a part of GNUnet.

Tor's naming system is decentralized and secure but not human readable.  I2P is the same at the level of base32 addresses but has an additional layer which is decentralized and human-meaningful, but where names are not necessarily uniques.

The idea is that each I2P router has its own address book, which you can access at: http://console/dns

The address book associates .i2p domains to destination keys.  There are several parts in the address book: the local part (which includes a private part that will never be published even if your address book is public), and the subscriptions part.

By default your local address book is empty and your only subscription is: http://i2p-projekt.i2p/hosts.txt

You can get more subscriptions from registry website such as inr.i2p, no.i2p, stats.i2p/i2p, or identiguy.i2p.

For example, you can add http://inr.i2p/export/alive-hosts.txt to your subscriptions.

To make your domain usable by others, either they have to manually add an entry for your domain in their address book, or you will need to submit it to services that provides subscription lists that people are actually subscribed to.

The first step for that is to verify that your name is not already taken by someone else (otherwise the registry service will not accept it as the main ones work on a "first come, first serve" basis).  Then, we will submit it to one or more of the main registries (listed above).

The procedure is similar for all of them so we will use inr.i2p.  Go there and use the search box to check that the domain you want is not already in use.  If it is not, click "Register a domain" in the menu.  Then enter your desired domain, it's Base64 hash (you can find it it the "Local destination" field when you edit your hidden service configuration), and a description of your hidden service.

If it gets accepted and is indeed alive when tested, it will be added to the host file of the service you submitted it to (and it will probably be picked up by the other services).

There, you completed the final step!

0x6 - Conclusions

I hope you enjoyed reading this article and that you will put the freedom and the privacy provided by I2P to good use.

Next time, we'll learn how to do use the InterPlanetary File System (IPFS), to host a decentralized website.

0x7 - References

  1. 2600 Magazine, Issue 34:2.  If you missed it, the article is now also available on my web page (pablo.rauzy.name/outreach.html).
  2. I2P  (geti2p.net)
  3. i2pd  (i2pd.website)
  4. Namecoin  (namecoin.org)
  5. GNUnet  (gnunet.org)
Return to $2600 Index