So I stumbled upon the reseeding thing once more. Reseeding servers are required for the I2P network to run. Now this does not only sound utterly important, it really is. However that probably also means responsibility and whatnot. Let’s have a look …



I2P Reseeding

Reseeding is the process of giving brand new participants some connections to start with. As in, without they cannot. I think bootstrapping is used in other areas to denote a similar process: on-boarding new participants to some kind of (basic) level. Anyhow, without this, new routers would not get into the network at all. And if not done properly the mechanism could be abused to query all destinations the serving router knows, which I understand could weakened/compromise the anonymity of the router serving the data.

There is an Official Reseed Howto that describes the current (best) practice. In addition there is the Reseed Forum @ zzz, where one can find additional information also about the past and how things have and are developing on this front.

I firstly checked if reseeds are still needed by asking in #i2p-dev. I was told there are more than ever currently, but more is also better as some might disappear, the network might grow, etc. Ok, so all sounds like it’s not useless to at least look into it.

I then tried to follow the official howto, which turned out to be … not as easy as expected … There are several people sharing how they do the reseeding, but the software for it is not part of the i2p-router package. I decided to try out one of the solutions based on go here, simply because it seemed to be the most recently updated one.

Note, that while in the following not everything seemed polished, there is only something like a dozen reseeds or so. Not sure how to check exactly (I think they are hard-coded into the router-source somewhere), but the point is, that this is not for everybody and not even for a large number of people. This is something that some dedicated router-operators (need to) do in addition to just running the router.

Reseed software by idk

So I started by “just following the howto” basically and therein using the firstmentioned reseed software …

Install dependencies

This looks straight-forward and easy …

root@anon-i2p:~# apt install git golang-go

Get the code

Now here the guide starts with “Switch To User Running I2P” in the heading, but that won’t work. The i2psvc user used on Debian has it’s shell set to /bin/false. And that is for security reasons, so I’d rather stick with that actually. So let’s see if I can do this as another user. Of course it is possible to change i2psvc to have a shell etc. if you so want …

The guide then tells to visit a “non-official” looking site reseed.i2p to get a binary and skip the other steps. Firstly, the hint to skip steps should probably go before those steps. Secondly, the site seemed not reachable to me when I tried. I didn’t try very often, though, and it’s on I2P, so … But, then, thirdly, let’s not do that anyways, as “that’s not what I signed up for”. As in … at least I want to have the code to be able to look into it if something goes sideways at some point.

Now the next thing is, that the repository advertised in the guide as of today seems to be outdated. It has moved on the clearnet from [1] to [2], but that seemed outdated too compared to the one in the i2p-gitlab. The latter one has more current advise in it’s README.md.

So I’m gonna try with that. Let’s make that new user for all this …

root@anon-i2p:~# adduser i2p-reseeder
Adding user `i2p-reseeder' ...
Adding new group `i2p-reseeder' (1002) ...
Adding new user `i2p-reseeder' (1002) with group `i2p-reseeder' ...
Creating home directory `/home/i2p-reseeder' ...
Copying files from `/etc/skel' ...
New password: 
Retype new password: 
passwd: password updated successfully
Changing the user information for i2p-reseeder
Enter the new value, or press ENTER for the default
        Full Name []: 
        Room Number []: 
        Work Phone []: 
        Home Phone []: 
        Other []: 
Is the information correct? [Y/n] 

Now I can switch to that user and continue from there by setting proxies to be used for the downloads to follow …

root@anon-i2p:~# su - i2p-reseeder
i2p-reseeder@anon-i2p:~$ vim .gitconfig
[http]
        proxy = http://127.0.0.1:4444
[https]
        proxy = http://127.0.0.1:4444
i2p-reseeder@anon-i2p:~$ mkdir go
i2p-reseeder@anon-i2p:~$ cd go
i2p-reseeder@anon-i2p:~/go$ git clone http://git.idk.i2p/idk/reseed-tools
Cloning into 'reseed-tools'...
warning: redirecting to http://git.idk.i2p/idk/reseed-tools.git/
remote: Enumerating objects: 1877, done.
remote: Counting objects: 100% (792/792), done.
remote: Compressing objects: 100% (326/326), done.
Receiving objects: 100% (1877/1877), 1.20 MiB | 45.00 KiB/s, done.
remote: Total 1877 (delta 473), reused 717 (delta 422), pack-reused 1085
Resolving deltas: 100% (1045/1045), done.

Build it

Now the interesting part, will it build?

i2p-reseeder@anon-i2p:~/go/reseed-tools$ make build
go build -v -tags netgo -ldflags '-w -extldflags "-static"' -o reseed-tools-linux-"amd64"
go: downloading github.com/go-acme/lego/v4 v4.3.1
go: downloading github.com/cretz/bine v0.1.0
go: downloading github.com/libp2p/go-libp2p v0.13.0
go: downloading github.com/urfave/cli v1.22.5
go: downloading github.com/eyedeekay/sam3 v0.33.2
go: downloading github.com/libp2p/go-libp2p-core v0.8.0
go: downloading github.com/gorilla/handlers v1.5.1
go: downloading github.com/libp2p/go-libp2p-peerstore v0.2.6
go: downloading github.com/libp2p/go-libp2p-gostream v0.3.1
go: downloading github.com/libp2p/go-libp2p-tls v0.1.3
go: downloading gitlab.com/golang-commonmark/markdown v0.0.0-20191127184510-91b5b3c99c19
go: downloading github.com/eyedeekay/i2pkeys v0.0.0-20220310055120-b97558c06ac8
go: downloading github.com/libp2p/go-tcp-transport v0.2.1
go: downloading golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d
go: downloading github.com/libp2p/go-libp2p-http v0.2.0
go: downloading github.com/libp2p/go-libp2p-circuit v0.4.0
go: downloading github.com/multiformats/go-multiaddr v0.3.1
go: downloading github.com/multiformats/go-multiaddr-fmt v0.1.0
go: downloading github.com/multiformats/go-multiaddr-net v0.2.0
go: downloading github.com/minio/sha256-simd v0.1.1
go: downloading github.com/justinas/alice v1.2.0
go: downloading github.com/libp2p/go-reuseport-transport v0.0.4
go: downloading golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
go: downloading github.com/libp2p/go-libp2p-autonat v0.4.0
go: downloading github.com/libp2p/go-ws-transport v0.4.0
go: downloading github.com/libp2p/go-libp2p-yamux v0.5.1
go: downloading gitlab.com/golang-commonmark/mdurl v0.0.0-20191124015652-932350d1cb84
go: downloading github.com/multiformats/go-multiaddr-dns v0.2.0
go: downloading github.com/libp2p/go-stream-muxer-multistream v0.3.0
go: downloading github.com/eyedeekay/checki2cp v0.0.21
go: downloading github.com/throttled/throttled/v2 v2.7.1
go: downloading golang.org/x/text v0.3.5
go: downloading github.com/libp2p/go-yamux v1.4.1
go: downloading github.com/libp2p/go-libp2p-transport-upgrader v0.4.0
go: downloading github.com/libp2p/go-eventbus v0.2.1
go: downloading github.com/libp2p/go-libp2p-mplex v0.4.1
go: downloading gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f
go: downloading github.com/libp2p/go-libp2p-loggables v0.1.0
go: downloading github.com/gorilla/websocket v1.4.2
go: downloading github.com/libp2p/go-libp2p-noise v0.1.1
go: downloading github.com/libp2p/go-msgio v0.0.6  
go: downloading golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
go: downloading github.com/libp2p/go-buffer-pool v0.0.2
go: downloading github.com/jbenet/goprocess v0.1.4 
go: downloading github.com/libp2p/go-yamux/v2 v2.0.0
go: downloading github.com/libp2p/go-reuseport v0.0.2
go: downloading github.com/libp2p/go-libp2p-nat v0.0.6
go: downloading github.com/hashicorp/golang-lru v0.5.4
go: downloading gitlab.com/golang-commonmark/linkify v0.0.0-20191026162114-a0c2df6c8f82
go: downloading github.com/libp2p/go-libp2p-swarm v0.4.0
go: downloading gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181
go: downloading github.com/libp2p/go-addr-util v0.0.2
go: downloading github.com/cenkalti/backoff/v4 v4.1.0
go: downloading github.com/libp2p/go-mplex v0.3.0  
go: downloading github.com/ipfs/go-log v1.0.4
go: downloading github.com/google/uuid v1.1.1
go: downloading github.com/libp2p/go-nat v0.0.5
go: downloading github.com/libp2p/go-netroute v0.1.3
go: downloading github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6
go: downloading github.com/libp2p/go-libp2p-discovery v0.5.0
go: downloading github.com/ipfs/go-cid v0.0.7
go: downloading github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
go: downloading github.com/gogo/protobuf v1.3.1
go: downloading github.com/multiformats/go-multistream v0.2.0
go: downloading github.com/btcsuite/btcd v0.20.1-beta
go: downloading github.com/multiformats/go-varint v0.0.6
go: downloading github.com/multiformats/go-multihash v0.0.14
go: downloading github.com/libp2p/go-libp2p-blankhost v0.2.0
go: downloading go.uber.org/zap v1.15.0
go: downloading github.com/google/gopacket v1.1.17 
go: downloading github.com/libp2p/go-conn-security-multistream v0.2.0
go: downloading github.com/jbenet/go-temp-err-catcher v0.1.0
go: downloading go.uber.org/multierr v1.5.0
go: downloading github.com/jackpal/go-nat-pmp v1.0.2
go: downloading github.com/opentracing/opentracing-go v1.2.0
go: downloading github.com/ipfs/go-ipfs-util v0.0.2
go: downloading github.com/eyedeekay/go-i2cp v0.0.0-20190716135428-6d41bed718b0
go: downloading github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1
go: downloading github.com/pkg/errors v0.9.1
go: downloading github.com/miekg/dns v1.1.40
go: downloading github.com/huin/goupnp v1.0.0
go: downloading github.com/cpuguy83/go-md2man v1.0.10
go: downloading go.opencensus.io v0.22.4
go: downloading go.uber.org/atomic v1.6.0
go: downloading github.com/multiformats/go-multibase v0.0.3
go: downloading github.com/felixge/httpsnoop v1.0.1
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.0
go: downloading github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d
go: downloading github.com/spaolacci/murmur3 v1.1.0
go: downloading github.com/libp2p/go-flow-metrics v0.0.3
go: downloading github.com/ipfs/go-log/v2 v2.1.1   
go: downloading github.com/mr-tron/base58 v1.2.0   
go: downloading github.com/gomodule/redigo v2.0.0+incompatible
go: downloading github.com/multiformats/go-base36 v0.1.0
go: downloading github.com/libp2p/go-libp2p-pnet v0.2.0
go: downloading github.com/russross/blackfriday v2.0.0+incompatible
go: downloading github.com/multiformats/go-base32 v0.0.3
go: downloading gopkg.in/square/go-jose.v2 v2.5.1  
go: downloading github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018
go: downloading github.com/russross/blackfriday/v2 v2.0.1
go: downloading github.com/shurcooL/sanitized_anchor_name v1.0.0

Ok, so to me this feels like a horrible amount of sources to check/trust while installing and especially for permanently running a software. It’s about 178MB in 2216 directories that got downloaded there. They would probably point out, that they do provide pre-compiled binaries of this (requiring only one download source). But of course I do not want pre-compiled - at least I want to be able to check what went wrong if something does. But that might just be me (as always!). And it sure is “easy” on the other hand, so for now let’s just hope that russross/blackfriday isn’t a russian backdoor software and mr-tron/base58 isn’t the NSAs (lol) ;)

I’m wondering, though, what the bunch of things is that are done with all this software - and if it would be hard to do it “just” with an already installed linux system with i2p. The (reseed) server does need to run some kind of logic to prohibit single clients from leeching all available data, so it definately is not “just a web-server”. However, from my currenty viewpoint, I need to trust that the developers have checked all this code that they use here. And the developers of those other packages as well then. And any packages those might include, etc. etc. It is widening the scope that I need to trust here by what feels an awfull lot. And “of course” I will not have the time to check anything in depth unless urgent reasons to do so came up. Even looking into the core functionality here will be limited to “having a glance at it”, if things go as they usually do. But hey, many glances migth still help where complete reviews are missing …

Anyways, only because I’m using a “dedicated virtual machine” for this, am I willing to continue at this point. But that’s just me and my way of thinking about security as a frightened noob … And no offense towards the developers at all, mind you. They are just doing things and sharing what they have done (thank you!) - there is no base here to demand anything at all, right? If I’d desire this as a package in Debian stable then I’d just have to become a Debian developer and do it (or pay someone to do so) - or, more likely in this case, realise why it is not even sensible to do so ;) Anyhow, let’s see how to proceede …

Install it

To install the software system-wide now:

root@anon-i2p:/home/i2p-reseeder/go/reseed-tools# make install
install -m755 reseed-tools-linux-"amd64" /usr/bin/reseed-tools
install -m644 etc/default/reseed /etc/default/reseed
install -m755 etc/init.d/reseed /etc/init.d/reseed
mkdir -p /etc/systemd/system/reseed.d/
mkdir -p /var/lib/i2p
install -g i2psvc -o i2psvc -d /var/lib/i2p/i2p-config/reseed/
cp -r content /var/lib/i2p/i2p-config/reseed/content
chown -R i2psvc:i2psvc /var/lib/i2p/i2p-config/reseed/
install -m644 etc/systemd/system/reseed.d/reseed.conf /etc/systemd/system/rese
ed.d/reseed.conf
install -m644 etc/systemd/system/reseed.d/reseed.service /etc/systemd/system/r
eseed.d/reseed.service

All looking good at the first glance. So does it run?

Run it?

Now the first run is described to create a key for ones email, so let’s see about that. The user I created will not have access to the netdb without adjusting the configuration, so note how I’m running this as the i2psvc user that is also used to run the I2P router itself. That user also needs write permissions to the current directory for the following.

root@anon-i2p:/home/i2p-reseeder/reseed# sudo -u i2psvc reseed-tools reseed --signer=lbt@mail.i2p --netdb=/var/lib/i2p/i2p-config/netDb --port=8443 --ip=127.0.0.1 --trustProxy
2023/01/03 19:50:45 /var/lib/i2p/.i2p
2023/01/03 19:50:45 /var/lib/i2p/i2p/i2prouter
2023/01/03 19:50:45 /var/lib/i2p/Library/Application Support/i2p/clients.confi
g
2023/01/03 19:50:45 Linux i2p router detected
Unable to read signing key 'lbt_at_mail.i2p.pem'
Would you like to generate a new signing key for lbt@mail.i2p? (y or n): y
Generating signing keys. This may take a minute...
        Signing certificate saved to: lbt_at_mail.i2p.crt
        Signing private key saved to: lbt_at_mail.i2p.pem
        Signing CRL saved to: lbt_at_mail.i2p.crl
2023/01/03 19:50:55 Rebuilding su3 cache...
2023/01/03 19:50:55 Building 50 su3 files each containing 77 out of 6006 route
rInfos.

So ya, it runs and seems to have created a key indeed. The --trustProxy makes this ignore SSL certs - I would prefer to provide those via letsencrypt/apache anyways.

systemd Integration

The concept seems to be to just activate the according service and this software would permanently provide the web-server. However, I will need to tell the systemd invocation about the parameters I used on the command-line there. At the very least we need to define what email-address should be used for the signing key, as done in the invocation above. The howto points out to define the signer like this:

root@anon-i2p:~# vim /etc/systemd/system/reseed.d/reseed.conf
Environment="RESEED_EMAIL=lbt@mail.i2p"

The service file itself is defined right there as well in reseed.service.

For systemd to recognise new/changed files one needs to reload the daemon:

root@anon-i2p:~# systemctl daemon-reload

Now it shows the service as loaded but inactive, so let’s start it:

root@anon-i2p:~# systemctl status reseed.service
root@anon-i2p:~# systemctl start reseed.service

Didn’t start and didn’t give much clue - as in no log to be found and only the following in the journal:

Jan 03 21:54:26 anon-i2p systemd[1]: Starting LSB: <DESCRIPTION>...
Jan 03 21:54:26 anon-i2p systemd[1]: Started LSB: <DESCRIPTION>.

Problem Analysis

I contacted eyedeekay on IRC about this and together we started to look into what’s going wrong here. Looking at the service gives the clue if you know that the software provides both, a script for init.d and one for systemd:

root@anon-i2p:~# systemctl status reseed.service
● reseed.service - LSB: <DESCRIPTION>
     Loaded: loaded (/etc/init.d/reseed; generated)
     Active: active (exited) since Tue 2023-01-03 21:54:54 UTC; 18min ago
[...]
Process: 27174 ExecStart=/etc/init.d/reseed start (code=exited, status=0/SUCCESS)
[...]
Jan 03 21:54:54 anon-i2p systemd[1]: Starting LSB: <DESCRIPTION>...
Jan 03 21:54:54 anon-i2p systemd[1]: Started LSB: <DESCRIPTION>.

So the service is actually in-place and doing something, just not the right thing. It is actually calling the init.d script instead of executing the command defined in the service definition. What gives?

Luckily eyedeekay had the right hinch about this. There is some kind of mechanism in place to use init.d script from systemd-service - like to make them interchangeable or to easy the migration from init.d to systemd (see [3]). At least from a Debian perspective init.d is the old one and systemd is the modern replacement - although I remember there has been a lot of controversy/fights/opinions about this switch. Anyhow … Options at this point seemed to either configure the init.d script and just run that instead of the service definition, or to fix it somehow. I postponed that decision at that point, as eyedeekay as the developer much sounded like “about to do something about it”.

Re-Check and Update

I took a look at the repository again and saw like a dozen new commits in there addressing the problem. So I wanted to try those out:

i2p-reseeder@anon-i2p:~/go/reseed-tools$ git pull
warning: redirecting to http://git.idk.i2p/idk/reseed-tools.git/
remote: Enumerating objects: 96, done.
remote: Counting objects: 100% (96/96), done.
remote: Compressing objects: 100% (88/88), done.
remote: Total 96 (delta 52), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (96/96), 72.54 KiB | 73.00 KiB/s, done.
From http://git.idk.i2p/idk/reseed-tools
   ba06de9..aeb54da  master     -> origin/master
Updating ba06de9..aeb54da
Fast-forward
 Makefile                                                           | 147 ++++++++++----------
 README.md                                                          |  35 -----
 docs/DEBIAN.html                                                   | 174 ++++++++++++++++++++++++
 docs/DEBIAN.md                                                     |  32 +++++
 DOCKER.html => docs/DOCKER.html                                    |  48 ++++++-
 DOCKER.md => docs/DOCKER.md                                        |   0
 EXAMPLES.html => docs/EXAMPLES.html                                |  46 ++++++-
 EXAMPLES.md => docs/EXAMPLES.md                                    |   0
 docs/SERVICES.html                                                 | 214 ++++++++++++++++++++++++++++++
 docs/SERVICES.md                                                   |  34 +++++
 docs/showhider.css                                                 |  15 +++
 docs/style.css                                                     | 165 +++++++++++++++++++++++
 etc/systemd/system/{reseed.d => }/reseed.service                   |   3 +-
 .../{reseed.d/reseed.conf => reseed.service.d/override.conf}       |   0
 i2plogo.png                                                        | Bin 0 -> 46661 bytes
 index.html                                                         | 190 ++++++++++----------------
 postinstall-pak                                                    |  42 ++++--
 postremove-pak                                                     |   7 +
 showhider.css                                                      |  15 +++
 style.css                                                          |  10 +-
 21 files changed, 982 insertions(+), 273 deletions(-)
 create mode 100644 docs/DEBIAN.html
 create mode 100644 docs/DEBIAN.md
 rename DOCKER.html => docs/DOCKER.html (81%)
 rename DOCKER.md => docs/DOCKER.md (100%)
 rename EXAMPLES.html => docs/EXAMPLES.html (78%)
 rename EXAMPLES.md => docs/EXAMPLES.md (100%)
 create mode 100644 docs/SERVICES.html
 create mode 100644 docs/SERVICES.md
 create mode 100644 docs/showhider.css
 create mode 100644 docs/style.css
 rename etc/systemd/system/{reseed.d => }/reseed.service (81%)
 rename etc/systemd/system/{reseed.d/reseed.conf => reseed.service.d/override.conf} (100%)
 create mode 100644 i2plogo.png
 create mode 100755 postremove-pak
 create mode 100644 showhider.css

Ok, new code needs new build/install:

i2p-reseeder@anon-i2p:~/go/reseed-tools$ make build
go build -v -tags netgo -ldflags '-w -extldflags "-static"' -o reseed-tools-linux-"amd64"
root@anon-i2p:/home/i2p-reseeder/go/reseed-tools# make install
install -m755 reseed-tools-linux-"amd64" /usr/bin/reseed-tools
install -m644 etc/default/reseed /etc/default/reseed
install -m755 etc/init.d/reseed /etc/init.d/reseed
mkdir -p /etc/systemd/system/reseed.service.d/
mkdir -p /var/lib/i2p/
mkdir -p /var/lib/i2p/i2p-config/reseed/
install -g i2psvc -o i2psvc -d /var/lib/i2p/i2p-config/reseed/
cp -r content /var/lib/i2p/i2p-config/reseed/content
chown -R i2psvc:i2psvc /var/lib/i2p/i2p-config/reseed/
install -m644 etc/systemd/system/reseed.service.d/override.conf /etc/systemd/system/reseed.service.d/over
ride.conf
install -m644 etc/systemd/system/reseed.service /etc/systemd/system/reseed.service

So let’s see if it still runs as before if started from the command-line:

root@anon-i2p:/home/i2p-reseeder/reseed# sudo -u i2psvc reseed-tools reseed --signer=lbt@mail.i2p --netdb
=/var/lib/i2p/i2p-config/netDb --port=8443 --ip=127.0.0.1 --trustProxy
2023/01/04 13:34:32 /var/lib/i2p/.i2p
2023/01/04 13:34:32 /var/lib/i2p/i2p/i2prouter
2023/01/04 13:34:32 /var/lib/i2p/Library/Application Support/i2p/clients.config
2023/01/04 13:34:32 Linux i2p router detected
2023/01/04 13:34:32 Rebuilding su3 cache...
2023/01/04 13:34:32 Building 50 su3 files each containing 77 out of 5802 routerInfos.
2023/01/04 13:34:32 Done rebuilding.
2023/01/04 13:34:32 HTTP server starting on
2023/01/04 13:34:32 HTTP server started on 127.0.0.1:8443

It does. So let’s re-check the service (notice the reload to make the system aware of new/changed files):

root@anon-i2p:~# systemctl daemon-reload
root@anon-i2p:~# systemctl status reseed.service
● reseed.service - I2P reseed service
     Loaded: loaded (/etc/systemd/system/reseed.service; disabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/reseed.service.d
             └─override.conf
     Active: active (exited) since Tue 2023-01-03 21:54:54 UTC; 15h ago
      Tasks: 0 (limit: 2332)
     Memory: 0B
        CPU: 0
     CGroup: /system.slice/reseed.service

This reference the service file now, instead of the init.d file as before. So looking good.

Next I edited the service file (new location now) to include the parameters I used on the command-line as well (--signer=lbt@mail.i2p --port=8443 --ip=127.0.0.1 --trustProxy):

root@anon-i2p:~# vim /etc/systemd/system/reseed.service
ExecStart=/usr/bin/reseed-tools reseed --yes=true --netdb=/var/lib/i2p/i2p-config/netDb --signer=lbt@mail.i2p --port=8443 --ip=127.0.0.1 --trustProxy

While I might be done at this point, I did notice “that other file there”:

root@anon-i2p:~# vim /etc/systemd/system/reseed.service.d/override.conf 
# Use this file to configure the contact/signer email used for the reseed service.
# without it the reseed will fail to start.

[Service]
Environment="RESEED_EMAIL=lbt@mail.i2p"

That notice sounded so important, that I filled in the email here in addition to above - hope that doesn’t mix things up, let’s see …

root@anon-i2p:~# systemctl daemon-reload
root@anon-i2p:~# systemctl restart reseed.service
root@anon-i2p:~# systemctl status reseed.service
● reseed.service - I2P reseed service
     Loaded: loaded (/etc/systemd/system/reseed.service; disabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/reseed.service.d
             └─override.conf
     Active: active (running) since Wed 2023-01-04 13:47:19 UTC; 1s ago
   Main PID: 30757 (reseed-tools)
      Tasks: 5 (limit: 2332)
     Memory: 46.5M
        CPU: 1.086s
     CGroup: /system.slice/reseed.service
             └─30757 /usr/bin/reseed-tools reseed --yes=true --netdb=/var/lib/i2p/i2p-config/netDb --sig>

Jan 04 13:47:19 anon-i2p reseed-tools[30757]: Unable to read signing key 'lbt_at_mail.i2p.pem'
Jan 04 13:47:19 anon-i2p reseed-tools[30757]: Generating signing keys. This may take a minute...
Jan 04 13:47:20 anon-i2p reseed-tools[30757]:         Signing certificate saved to: lbt_at_mail.i2p.crt
Jan 04 13:47:20 anon-i2p reseed-tools[30757]:         Signing private key saved to: lbt_at_mail.i2p.pem
Jan 04 13:47:20 anon-i2p reseed-tools[30757]:         Signing CRL saved to: lbt_at_mail.i2p.crl
Jan 04 13:47:20 anon-i2p reseed-tools[30757]: 2023/01/04 13:47:20 Rebuilding su3 cache...
Jan 04 13:47:20 anon-i2p reseed-tools[30757]: 2023/01/04 13:47:20 Building 50 su3 files each containing >
Jan 04 13:47:20 anon-i2p reseed-tools[30757]: 2023/01/04 13:47:20 Done rebuilding.
Jan 04 13:47:20 anon-i2p reseed-tools[30757]: 2023/01/04 13:47:20 HTTP server starting on
Jan 04 13:47:20 anon-i2p reseed-tools[30757]: 2023/01/04 13:47:20 HTTP server started on 127.0.0.1:8443

Ya, that very much looks like what is wanted :) Let’s double-check by looking at open ports and whether the desired port appears there:

root@anon-i2p:~# netstat --listening --numeric | grep 8443
tcp        0      0 127.0.0.1:8443          0.0.0.0:*               LISTEN     

I check if the service is enabled to auto-start, but it isn’t yet. I also stop the service as the forwarding apache isn’t in place yet anyways.

root@anon-i2p:~# systemctl is-enabled reseed.service
disabled
root@anon-i2p:~# systemctl stop reseed.service

Note: Installing the new version “over” the old one as I did above wasn’t too smart. I now have several (at least 2) config-files of which only one is used, so I should have removed/purged the old installation first.

Reverse Proxy to “connect it”

What’s missing now should “only” be to redirect traffic to this server by using the “reverse proxy” mechanismn as described in the howto (and secure that via SSL + put measures in place against possible ((d)dos) attacks) …

As I want to use apache, installation is kind of simple:

root@anon-i2p:~# apt install apache2

Configuring proxy behaviour is something where one needs to be careful then. A proxy can become something like an “open relay” on email, a service allowing anyone to contact anyone on the net - with you (the proxy operator) being the visible source of those requests. With apache this would transport http traffic instead of emails, which would probably make it worse than an open relay with email ;) In the old-net that is something you most definately do not want to do.

So, I’ll need the proxy module (+ the sub-module for http traffic) and then to configure for that:

root@anon-i2p:~# a2enmod proxy
Enabling module proxy.
To activate the new configuration, you need to run:
  systemctl restart apache2
root@anon-i2p:~# a2enmod proxy_http
Considering dependency proxy for proxy_http:
Module proxy already enabled
Enabling module proxy_http.
To activate the new configuration, you need to run:
  systemctl restart apache2
root@anon-i2p:~# cp -a /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/reseed-proxy.conf
root@anon-i2p:~# vim /etc/apache2/sites-available/reseed-proxy.conf
				SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
				SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

        # Do not turn this on, instead make sure it's off (the open relay thingy)
        ProxyRequests Off

        # Define (in general) what and for whom to proxy
        <Proxy *>
                Order deny,allow
                Allow from all
        </Proxy>

        # Define URLs and where to (reverse)proxy them to/from
        ProxyPass / http://127.0.0.1:8443/
        ProxyPassReverse / http://127.0.0.1:8443/

Note that here the SSL files need to be specified - I’m currently running all this in a testing environment and for now didn’t do the official SSL part (which seems kind of trivial if you are used to requesting letsencrypt certificates - you will just point to them here). Let’s for now just say “different story for another time”.

So finally, to put these things into effect, I’ll need to start the reseed-server and restart the apache:

root@anon-i2p:~# systemctl start reseed.service
root@anon-i2p:~# systemctl restart apache2

Testing it

Testing the Web Server

At this point I’m able to test if the web server is working at all simply by putting it’s public ip into a browser. For me in my testing environment that is an internal LAN ip, only, and I’m using port 80 without SSL. Otherwise I would want to test that non-ssl gets redirected to ssl as well at this point.

I assumed I would need to query a certain URL to get some data from this then, but there actually is a web-site displayed with hints as to what kind of service this is and including a button to download a single reseed file. I did feel the urge to press it and indeed got a download of a reseed file like immediately.

So on the one hand, I’m like dancing thinking “nice, technically I got a reseed server set up”. But on the other hand, I see dark clouds on the horizon here. Let me explain …

Depending on the country you are planning to host this in, there might be legal things to take into account when operating a web-site. In my case I would be obliged to provide contact information there. So I couldn’t “just run” the service as it stands there now. I’m not sure if that would also be the case if the root of the webpage would display nothing and only certain paths would provide files (?). This seems a pretty interesting question to me.

Testing the (re)seed

So the web-server is running and providing seeds, do we really have a “working reseed” at this point?

Local checks

So I had already downloaded a file by pressing that button above. The howto included the hint to check this using zipinfo like this:

root@anon-i2p:/home/i2p-reseeder# sudo -u i2psvc zipinfo -z ./i2pseeds.su3
[...]

It shows a list of routerInfo-xyzxyz=.dat entries there.

The file can also be retrieved by using wget on the URL /i2pseeds.su3 as in

wget --user-agent="Wget/1.11.4" http://192.168.1.101/i2pseeds.su3

Note that specifying the user agent there is necessary, otherwise the request will be denied. And of course this would have to be a public ip address used from “outside” when really doing this and not just in a test-environment.

The router-console offers a way to upload files generated by another router. Trying to do that with this file brings up:

Reseed from file failed - java.io.IOException: No seeds extracted
No seeds extracted

Now this might be due to the signature not being trusted? idk provided help how to locally check the signature with these reseed-tools:

root@anon-i2p:/home/i2p-reseeder# sudo -u i2psvc reseed-tools verify --signer=lbt@mail.i2p --keystore=/var/lib/i2p/i2p-config/reseed/ i2pseeds.su3
[...]
Signature is valid for signer 'lbt@mail.i2p'

So the file is looking good and the signature is (technically) good as well - just not trusted by anyone at this point?

remote check

Testing the reseeding functionality from a router includes having to manually include the used reseed-key to that router. That’s the part that would be distributed with the installation packages for the router once your reseed is officially included. The old howto specified ~/i2p/certificates/reseed/ as the path for this, but I wasn’t able to find a corresponding /var/lib/i2p/i2p-config/certificates. So where are those when using i2p installed as a service? Turns out that directory would be valid but is not created automatically. There is /usr/share/i2p/certificates in addition which contain the currently used certificates (as I received them with the router installation package).

So if I throw the .crt generated by the reseed-tools into there, then the router will accept the file?

root@anon-i2p:~# cp /var/lib/i2p/i2p-config/reseed/lbt_at_mail.i2p.crt /usr/share/i2p/certificates/reseed/

… and …

Reseed successful, loaded 77 router infos from file

Yes it does. At least if using it without SSL or with “official” certs, otherwise the self-signed cert needs to go into /usr/share/i2p/certificates/ssl first:

root@anon-i2p:~# openssl x509 -outform der -in /etc/ssl/certs/ssl-cert-snakeoil.pem -out /usr/share/i2p/certificates/ssl/ssl-cert-snakeoil.crt

At this point I have a working reseed server here that now would need to be made “fit for service” by adding (rather enforcing?) encryption with a proper certificate and adding rate-limits as advised in the howto.

Hardening (ssl, fail2ban rate-limits)

Hardening is kind of too big of a word for the following steps, but also kind of match going from the state of a working but not encrypting server to working properly encrypting. But the howto had some details that I was curious about after the first glance, so let’s have a look …

SSL

In the intended production environment I would just request a letsencrypt certificate as I have done so often already. Assumingly for a subdomain like “i2p.yourdomain.net”. Far as I have looked into it, there isn’t much one could fine-tune concerning what kind of certificate is created and how it is signed. The deployment and how the certificate is used can be fine-tuned in many ways then, though.

In particular the howto suggests the following options:

SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder On
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
SSLCompression off 
SSLUseStapling on 
SSLStaplingCache "shmcb:logs/stapling-cache(150000)" 
SSLSessionTickets Off

They also pointed to cipherli.st as a source of good practice configuration and I remember to have been there (or similar) before, when setting up web-servers. The domain cipherli.st and what was announced as its successor cipherl.ist were both not reachable for me (for several days now), but there seems to cipherlist.eu now. That says:

SSLCipherSuite EECDH+AESGCM:EDH+AESGCM
SSLProtocol -all +TLSv1.3 +TLSv1.2
SSLOpenSSLConfCmd Curves X25519:secp521r1:secp384r1:prime256v1
SSLHonorCipherOrder On
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
SSLCompression off
SSLUseStapling on
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
SSLSessionTickets Off

Limiting ciphers is usually a difficult path. Often you don’t want to exclude old clients (otherwise your service “just doesn’t work” for them anymore), but if you want security you’d actually have to. It’s the kind of “do I want to support Internet Explorer 0.1” type of question, but when offering a service it actually is a decision that has to be made - a line that needs to be drawn somewhere. Just as we are at it, let’s compare to what is recommended as a cipher suite directive for backwards compatibility at [6]:

SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4

That’s what comes instead of SSLCipherSuite EECDH+AESGCM:EDH+AESGCM, kinda funny isn’t it? Especially in this case I wouldn’t even think about it much and try to go with the suggested version there. The short one. If clients are too old to connect, that’s their problem :P The test is to see if the router still accepts it as it’s the only relevant source to address here.

However, take note of the following warning they issue together with this:

The settings are very secure, but if you don’t know what you are doing might make your website and subdomains unavailable for a long, long time (see HSTS). Research what you are doing and think before you act.

If you are doing somethin else with the same (sub-)domain, this could hit you.

Back to the topic (and with a too short max age on the HSTS here) I wanted to test if the router will accept these settings. Some of those directives rewrite headers, so note that the according module needs to be enabled:

root@anon-i2p:~# vim /etc/apache2/sites-available/reseed-proxy.conf
<IfModule mod_ssl.c>
        
        # see https://cipherlist.eu/
        SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
        SSLProtocol All -SSLv2 -SSLv3
        SSLHonorCipherOrder On
        Header always set Strict-Transport-Security "max-age=60; includeSubDomains; preload"
        Header always set X-Frame-Options DENY
        Header always set X-Content-Type-Options nosniff
        SSLCompression off
        SSLUseStapling on
        SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
        SSLSessionTickets Off

        <VirtualHost _default_:443>
[...]
root@anon-i2p:~# a2enmod headers 
Enabling module headers.
To activate the new configuration, you need to run:
  systemctl restart apache2
root@anon-i2p:~# a2ensite reseed-proxy.conf
Enabling site reseed-proxy.
To activate the new configuration, you need to run:
  systemctl reload apache2
root@anon-i2p:~# systemctl restart apache2

Entering the https address to the reverse proxy (for me something like https://name.local.domain/i2pseeds.su3 into the router now yields a Reseed successful, fetched 77 router infos. So ya, those settings would do I guess.

fail2ban

I revisited fail2ban then, because the howto advised to use that or something like that. Basic installation:

root@anon-i2p:~# apt install fail2ban
[...]
root@anon-i2p:~# systemctl is-enabled fail2ban
enabled

There are some predefined rules one can use for apache, e.g. to ban ip addresses after unsuccessful login attempts and according to certain bot behaviour. Is it enough to just enable these? To enable them the practice seems to be to copy the jail.conf file to a jail.local file in /etc/fail2ban and then adding lines enabled = true inside that .local file to all sections one wants to enable - plus any additional customisation that one wants. The existing defaults-debian.conf in /etc/fail2ban/jail.d enables the sshd checking by a simple

[sshd]
enabled = true

so I assume that just gets added to the otherwise configured stuff, i.e. I should be able to enable modules by just giving them that enable line there, or? But which will make sense? Like … if we are not using http-auth then banning unsuccessful login attempts will have no effect (aside from some wasted processing time). The apache-badbots module filters out bots that tell you their name (by the means of the user-agent header it seems). Now of course, if you are getting hammered by a gazillion requests from those, then this rule is golden. However, I would expect future attacks to just use a different name, so this will only be worth “what it’s updated” ;)

After having looked at the remaining apache-xyz rules, I feel like these are good to have available to block things according to what is in the logs if there is something in the logs. However, I don’t feel the urge to run these for just in case to be honest, because I assume it’s likely they will miss the “next generation attack” anyways - most of them seem very specific in what they catch. Getting familiar with this in advance probably is a good idea though - for example to have email notifications from fail2ban configured for when you need them. Before I would go live with a reseed server, I would need to have a word with some of the current operators about what they have experienced and how they fought the ddos battles if so …

Feedback to the i2p documentation

While I’m still going through the whole process, it already feels as if I might be able to improve the howto some. It’s not that I really feel the need for a polished howto there. But as I am going through this, I might be able to do so with not-so-big-effeort as a side-track - and feeding back results into projects is one of the things I do want to do more.

Having a first glance at the sources for the documentation, I think to have found it in project i2p.www on that very same gitlab system from above. However, I also noticed that idk has not only updated those pages already, but from the looks started an overhaul there. I will need to revisit the pages and see if I can maybe contribute something by streamlining my notes from here. Even if I end up never running one myself in the end.

Summary/Conclusions/Something like that

So to recap: Reseeding is not for everyone.

Loss of Anonymity

Reseeding is building a bridge between the old-net (by providing access to reseed-data in the old-net under an old-net address) and the i2p network (in which routers then use the reseed-data to build tunnels). It seems you should assume to loose your anonymity on the identity (i2p email in doubt) that you use to register with the i2p project. The reason for this is, that the project needs a way to contact you in case of problems/changes etc. as one of the few running a reseed. However, reseeding is tied to an old-net address, i.e. an ipv4 or v6 ip address. Hence people will be able to connect the dots from your identity to those addresses and using the mechnisms of the old-net will usually be able to determine your real life contact details as required by the mechanisms of that old-net.

So do note: If your life depends on using the network anonomously (or something like that) then you probably do not want to run a reseed or at the very least need to be super careful about the steps involved. Luckily I’m in the situation I wouldn’t need to care much about this aspect currently. Though it feels different thinking one is anonymous than if not, so there is that to loose for my lbt identity ;)

Exposing a service that is “in the focus”

Reseeding is providing a very limited interface to the old-net structures. Other routers usually only need it when first getting online, but for that need to be able to access it without using i2p. As such this service you are about to offer as a reseed operator unfolds to have two major looking aspects:

  1. There are only a dozen reseeds, so if an attacker can mount some kind of attack against these they only need to deal with a dozen targets (in the opposite to thousands of routers composing the i2p network).
  2. The reseed addresses are public knowledge as they are contained in the source code of the i2p routers (you will actually find the list in the router-console). So no guessing for them, they can straighforward start hammering you.

I think this makes it obvious that you are basically carrying around a big sign labelled “interesting target, come try something” for those targeting i2p. I think I read that there had been attacks in the past. For one the basically to-be-expected (d)dos attempts. An attacker exhausting the ressources of these few servers could probably deny new routers from connecting to the network at all even (?).

But then there have also been discussion on how to attack the anonymity of new routers. idk explained this to me a bit and this what I understood. There is a bottle-neck situation when new routers start from scratch and need to learn their first router identities that they then contact to explore the net further (i.e. learn about additional routers). If an attacker was to control both of the two reseeds providing these for a newcomer, then they could direct the new router towards two routers that they control - and by running manipulated routers there kind of catch those routers in a net of hostile routers. However, some i2p addresses are hard-coded into the router software, which such an attacker can not manipulate. As addresses in i2p are also the cryptographic keys used in the connections, the attacker wouldn’t be able to fake these unless using different keys (which wouldn’t match the hardcoded ones). If the attacker has been able to serve manipulated software as an “to be i2p router”, then all is lost (of course), but that’s another scenario and not related to controlling the reseed servers.

But it seems to be a vulnerable phase and hence likely that other ideas on how to attack the reseeds could do something. And in the end it doesn’t even matter for the sole viewpoint of operating the reseed service - if one still is getting DoS:ed then it helps little to know it won’t do the attacker any good ;)

Shitting my pants / Is this for me?

Anyways, it does sound a lot as if you are making yourself quite a target if volunteering to run a reseed. And to be honest, I have started shitting my pants about it :( I do not currently have a dedicated ip address with dedicated hardware that I could use for this. Hence, I would need to use an ip address/hardware that I also use for other things. So ddos things might well affect my other services even in cases when no harm is actually done to i2p. But it also is easy to determine what other services I’m running there, so the “target here, come try something” kind of carries over to everything else. So it’s not really the new service that frightens me here (I’d mitigate that by having it in a virtualised environment to limit the impact of possible attacks), but actually the attention I might get. Now that sounds like security by obscurity in a way - a concept I often argue against. So I will need to make up my mind about this. But ya, for now there is some brown in my pants ;) As there currently is no urgent need for more reseeders, I will settle for “I don’t have the balls” for now and keep in mind that getting a dedicated machine for i2p just for this purpose would be a nice thing.

In the end …

A lot of noise for … nothing? Nah … However it’s not “I’m running a reseed now” :( I’d know how to get one running in pretty much no time now, though. I also learned a lot new things about the process in i2p and why it’s a critical step. And I refreshed some things about the apache configuration and looked into fail2ban again. So still feels well worth my time :) Big thx go to idk for taking so much time to help me understand things. Now I need to check if can feed something back into the documentation, just as I’m at it …


ClearNet Links:

[1] https://github.com/martin61/i2p-tools

[2] https://gitlab.com/herman2019/i2p-tools

[3] https://unix.stackexchange.com/questions/233468/how-does-systemd-use-etc-init-d-scripts

[4] https://httpd.apache.org/docs/2.4/mod/mod_proxy.html

[5] https://cipherlist.eu/ (used to cipherli.st and cipherl.ist or so)

[6] https://raymii.org/s/tutorials/Strong_SSL_Security_On_Apache2.html