Commit e9d02049 authored by anonym's avatar anonym

Completely remove I2P.

We have decided to remove I2P (Refs: #11276) due to our failure of
finding someone interested in maintaining it in Tails.

Will-fix: #12263
parent eeb619ed
......@@ -46,7 +46,6 @@
......@@ -22,7 +22,7 @@ AMNESIA_ISOHYBRID_OPTS="-h 255 -s 63"
# Kernel version
| perl -p -E 's{\A (\d+ [.] \d+) [.] .*}{$1}xms'
......@@ -460,8 +460,6 @@ usr/bin/expr 32082
usr/bin/bc 32081
lib/live/config/2060-create-upgrader-run-directory 32079
usr/bin/install 32078
lib/live/config/2080-install-i2p 32077
usr/local/lib/tails-shell-library/ 32076
usr/local/lib/tails-shell-library/ 32075
usr/local/lib/tails-shell-library/ 32074
lib/live/config/7000-debug 32073
......@@ -2839,7 +2837,6 @@ usr/share/applications/mimeinfo.cache 29205
usr/share/gnome/applications/vim.desktop 29204
usr/share/gnome/applications/nm-connection-editor.desktop 29203
usr/share/gnome/applications/gnome-power-statistics.desktop 29202
usr/share/gnome/applications/openjdk-7-policytool.desktop 29201
usr/share/gnome/applications/orca.desktop 29200
usr/share/applications/gnome-bluetooth-panel.desktop 29199
usr/lib/libreoffice/share/xdg/xsltfilter.desktop 29198
......@@ -3122,7 +3119,6 @@ etc/xdg/menus/applications-merged/ 28920
usr/share/applications/gnome-power-statistics.desktop 28919
usr/share/applications/nm-connection-editor.desktop 28918
usr/lib/i386-linux-gnu/tracker-1.0/ 28917
usr/share/applications/openjdk-7-policytool.desktop 28916
usr/share/applications/orca.desktop 28915
usr/share/applications/vim.desktop 28914
usr/share/desktop-directories/ 28913
......@@ -4097,7 +4093,6 @@ usr/lib/i386-linux-gnu/ 27944
usr/share/ca-certificates/mozilla/Verisign_Class_3_Public_Primary_Certification_Authority.crt 27943
usr/lib/i386-linux-gnu/ 27942
usr/lib/i386-linux-gnu/ 27941
etc/NetworkManager/dispatcher.d/ 27940
etc/NetworkManager/dispatcher.d/ 27939
usr/local/sbin/tor-has-bootstrapped 27938
usr/bin/gettext 27937
set -e
# Create the i2pbrowser user.
# We run i2p-browser under this user
echo "Creating the i2pbrowser user"
adduser --system --quiet --group i2pbrowser
set -e
echo "Configuring I2P"
# This must be set in order for the i2p init script to work
sed -i 's/^RUN_DAEMON=.*$/RUN_DAEMON="true"/' /etc/default/i2p
# Remove the "i2prouter" script, its man page, and its apparmor profile
# since these are not used by Tails:
rm /etc/apparmor.d/usr.bin.i2prouter /usr/share/man/man1/i2prouter.1.gz
# Install custom i2prouter stub scripts
for script in ${I2PROUTER} ${I2PROUTER}-nowrapper; do
echo "Removing $script"
dpkg-divert --rename --add "${script}"
cat > "$script" << EOF
echo "This script is not used by Tails."
echo "See for more information."
exit 0
chmod 755 "$script"
# Remove the outproxy from the tunnel on port 4444
# This will remove the following lines:
# tunnel.0.proxyList=false.i2p
# tunnel.0.option.i2ptunnel.httpclient.SSLOutproxies=false.i2p
# The SSLOutproxies option was first set in I2P 0.9.15
sed -i '/^.*tunnel\.0\.\(proxyList\|option\.i2ptunnel\.httpclient\.SSLOutproxies\)/d' "$I2P/i2ptunnel.config"
# Disable the https outproxy (port 4445)
sed -i 's|^.*\(tunnel\.6\.startOnLoad\).*|\1=false|' "$I2P/i2ptunnel.config"
# Don't serve the router console on IPv6
sed -i 's|^clientApp\.0\.args=7657\s\+::1,127\.0\.0\.1|clientApp.0.args=7657|' "$I2P/clients.config"
# Disable IPv6 in the wrapper
sed -i 's|^.*\(wrapper\.java\.additional\.5=-Djava\.net\.preferIPv4Stack=\).*|\1true|' "$WRAPPER"
sed -i 's|^.*\(wrapper\.java\.additional\.6=-Djava\.net\.preferIPv6Addresses=\).*|\1false|' "$WRAPPER"
# Tails specific router configs:
# * i2cp: allows java clients to communicate with I2P outside of the JVM. Disabled.
# * IPv6: Disabled
# * HiddenMode: Enabled
# * In-I2P Network Updates: Disabled
# * Inbound connections: Disabled (setting is "i2cp.ntcp.autoip")
# * Disable I2P plugins
# * Disable NTP
cat > "$I2P/router.config" << EOF
# NOTE: This I2P config file must use UTF-8 encoding
cat > "$I2P/susimail.config" << EOF
# enforce apparmor
echo Setting the I2P apparmor profile to enforce mode
sed -i -re 's|flags=\(complain\)||' /etc/apparmor.d/system_i2p
set -e
set -u
echo "Building VirtualBox guest modules"
hw_arch="`dpkg --print-architecture`"
if [ "$hw_arch" != i386 -a "$hw_arch" != amd64 ]; then
exit 0
. /usr/share/amnesia/build/variables
# the -dkms package must be installed *after* dkms to be properly registered
apt-get install --yes build-essential dkms
# Note: we only build for the 32-bit kernel, since building for 64-bit is too painful
# with multiarch; and anyway, the 64-bit kernel module doesn't play well with
# a 32-bit userspace (, which is why
# we instruct users to set up a 32-bit VM.
# Installing the headers triggers the building of the modules for that kernel
apt-get install --yes \
"linux-headers-${KERNEL_VERSION}-686" \
MODULES_VERSION="$(dpkg-query -W -f='${Version}\n' virtualbox-guest-dkms \
| sed -E 's,-.*,,')"
dkms build \
-a i386 -k "${KERNEL_VERSION}-686" \
-m virtualbox-guest -v "$MODULES_VERSION"
dkms install \
-a i386 -k "${KERNEL_VERSION}-686" \
-m virtualbox-guest -v "$MODULES_VERSION"
# clean the build directory
rm -r /var/lib/dkms/virtualbox-guest/
# virtualbox-guest-dkms's postrm script deletes any previously
# built binary module; let's delete it before the package gets purged.
rm /var/lib/dpkg/info/virtualbox-guest-dkms.prerm
# Also copy the udev rules installed by virtualbox-guest-dkms to enable guest
# additions by default.
cp -a /lib/udev/rules.d/60-virtualbox-guest-dkms.rules /etc/udev/rules.d/
......@@ -11,7 +11,6 @@ gdomap
......@@ -78,7 +77,6 @@ systemctl disable ttdnsd.service
# We don't run these services by default
systemctl disable gdomap.service
systemctl disable hdparm.service
systemctl disable i2p.service
# Don't hide tails-kexec's shutdown messages with an empty splash screen
for suffix in halt kexec poweroff reboot shutdown ; do
set -u
set -e
# Everything moved by this hook script will be reversed in the event that
# the string "i2p" is entered at a boot prompt
[ -d "/usr/share/i2p" ] || return 0
mkdir "$DEST"
mv -f /usr/share/i2p "$DEST"
mv -f /usr/sbin/wrapper "$DEST"
mv -f /usr/share/applications/i2p-browser.desktop "$DEST"
# I2P isn't started automatically at system boot.
# Instead, it is started with this hook script.
# Import i2p_is_enabled().
. /usr/local/lib/tails-shell-library/
# Don't even try to run this script if I2P is not enabled.
i2p_is_enabled || exit 0
# don't run if interface is 'lo'
[ $1 = "lo" ] && exit 0
if [ $2 = "up" ]; then
/usr/local/sbin/tails-i2p start &
......@@ -3,11 +3,6 @@
# Configuration file for ferm(1).
# I2P rules that grant access to the "i2psvc" user (those with $use_i2p) will
# only be enabled if the string "i2p" is entered at the boot prompt.
# Deny or reject rules affecting "i2psvc" will always be set.
def $use_i2p = `test -d /usr/share/i2p && echo 1 || echo 0`;
# When ferm starts initially during early boot, the "amnesia" user does not
# exist yet, so we have to use its UID (#7018).
def $amnesia_uid = 1000;
......@@ -74,11 +69,6 @@ domain ip {
mod owner uid-owner $amnesia_uid ACCEPT;
# Whitelist access to Tor's DNSPort so I2P can resolve hostnames when bootstrapping
daddr proto udp dport 5353 {
@if $use_i2p mod owner uid-owner i2psvc ACCEPT;
# White-list access to ttdnsd
daddr proto udp dport 53 {
mod owner uid-owner $amnesia_uid ACCEPT;
......@@ -92,31 +82,6 @@ domain ip {
mod owner uid-owner $amnesia_uid ACCEPT;
# White-list access to I2P services for the amnesia user (IRC, SAM, POP3, SMTP, and Monotone)
# For more information, see https://tails/ and
daddr proto tcp syn mod multiport destination-ports (6668 7656 7659 7660 8998) {
@if $use_i2p mod owner uid-owner $amnesia_uid ACCEPT;
# Whitelist access to I2P services for the i2psvc user,
# otherwise mail and eepsite hosting won't work. The mail ports (7659 and 7660) are
# accessed by the webmail app
daddr proto tcp syn mod multiport destination-ports (7658 7659 7660) {
@if $use_i2p mod owner uid-owner i2psvc ACCEPT;
# Whitelist access to the i2pbrowser user
daddr proto tcp syn mod multiport destination-ports (4444 7657 7658) {
@if $use_i2p mod owner uid-owner i2pbrowser ACCEPT;
# White-list access to the java wrapper's (used by I2P) control ports
# (see:
# If, for example, port 31000 is in use, it'll try the next one in sequence.
daddr proto tcp sport (31000 31001 31002) dport (32000 32001 32002) {
@if $use_i2p mod owner uid-owner i2psvc ACCEPT;
# White-list access to CUPS
daddr proto tcp syn dport 631 {
mod owner uid-owner $amnesia_uid ACCEPT;
......@@ -143,12 +108,11 @@ domain ip {
# Local network connections should not go through Tor but DNS shall be
# rejected. I2P is explicitly blocked from communicating with the LAN.
# (Note that we exclude the VirtualAddrNetwork used for .onion:s here.)
# rejected. (Note that we exclude the VirtualAddrNetwork used for
# .onion:s here.)
daddr ( @subchain "lan" {
proto tcp dport domain REJECT;
proto udp dport domain REJECT;
mod owner uid-owner i2psvc REJECT;
......@@ -157,11 +121,6 @@ domain ip {
proto tcp syn mod state state (NEW) ACCEPT;
# i2p is allowed to do anything it wants to on the internet.
outerface ! lo mod owner uid-owner i2psvc {
@if $use_i2p proto (tcp udp) ACCEPT;
# Everything else is logged and dropped.
LOG log-prefix "Dropped outbound packet: " log-level debug log-uid;
REJECT reject-with icmp-port-unreachable;
<?xml version='1.0' encoding='UTF-8' ?>
<purple version='1.0'>
<group name='Discussions'>
<setting name='collapsed' type='bool'>0</setting>
<chat proto='prpl-irc' account='XXX_NICK_XXX@'>
<component name='channel'>#i2p</component>
<account proto='prpl-irc' name='' mode='1'/>
<account proto='prpl-irc' name='XXX_NICK_XXX@' mode='1'/>
# This script reverses everything done by config/chroot_local-hooks/97_remove_i2p
# when the string "i2p" is added to the boot prompt.
# Import i2p_is_enabled().
. /usr/local/lib/tails-shell-library/
mv "$SRC/wrapper" /usr/sbin/wrapper
mv "$SRC/i2p-browser.desktop" /usr/share/applications
mv "$SRC/i2p" /usr/share
rmdir "$SRC"
echo "amnesia ALL = NOPASSWD: /usr/local/sbin/i2p-browser" > /etc/sudoers.d/zzz_i2pbrowser
chown root:root /etc/sudoers.d/zzz_i2pbrowser
chmod 0440 /etc/sudoers.d/zzz_i2pbrowser
if i2p_is_enabled && [ -d "$SRC" ]; then
# XXX:Stretch: on Jessie, AppArmorProfile=system_i2p is a no-op, since
# AppArmor support was enabled in Debian's systemd 218-4 (#10925).
ExecStart=/usr/sbin/aa-exec --profile=system_i2p -- /usr/sbin/wrapper "$I2P_ARGS"
# Import set_simple_config_key().
. /usr/local/lib/tails-shell-library/
# Import language_code_from_locale().
. /usr/local/lib/tails-shell-library/
i2p_is_enabled() {
grep -qw "i2p" /proc/cmdline
i2p_eep_proxy_address() {
# We retrieve the host and port number from the I2P profile. This
# shouldn't be anywhere other than but in case
# someone modifies the hook scripts or the default changes in I2P,
# this check should still work.
local listen_host listen_port
listen_host=$(awk -F= '/^tunnel\.0\.interface/{print $2}' \
listen_port=$(awk -F= '/^tunnel\.0\.listenPort/{print $2}' \
echo ${listen_host}:${listen_port}
i2p_reseed_started() {
grep -q 'Reseed start$' "${I2P_WRAPPER_LOG}"
i2p_reseed_failed() {
grep -q 'Reseed failed, check network connection$' "${I2P_WRAPPER_LOG}"
i2p_reseed_completed() {
grep -q "Reseed complete" "${I2P_WRAPPER_LOG}"
i2p_reseed_status() {
if i2p_reseed_completed; then
echo success
elif i2p_reseed_failed; then
echo failure
elif i2p_reseed_started; then
echo running
i2p_built_a_tunnel() {
netstat -nlp | grep -qwF "$(i2p_eep_proxy_address)"
i2p_router_console_address() {
i2p_router_console_is_ready() {
netstat -nlp | grep -qwF "$(i2p_router_console_address)"
set_best_i2p_router_console_lang() {
# We will use the detected language even if I2P doesn't support it; it
# will default to English in that case.
local lang="$(language_code_from_locale "${LANG}")"
# We first try to set it in an existing "live" config, even though
# the effect will only appear after a restart.
local config
for config in "${I2P_CONFIG}/router.config" \
"${I2P_DEFAULT_CONFIG}/router.config"; do
if [ -e "${config}" ]; then
set_simple_config_key "${config}" "routerconsole.lang" "${lang}"
return 0
return 1
set -e
set -u
# Import the TBB_EXT variable, and guess_best_tor_browser_locale().
. /usr/local/lib/tails-shell-library/
# Import try_cleanup_browser_chroot(), setup_browser_chroot(),
# configure_chroot_dns_servers(), configure_chroot_browser(),
# configure_chroot_browser(), set_chroot_browser_locale()
# set_chroot_torbutton_browser_name(), set_chroot_browser_permissions()
# and run_browser_in_chroot().
. /usr/local/lib/tails-shell-library/
# Import i2p_router_console_is_ready() and i2p_is_enabled().
. /usr/local/lib/tails-shell-library/
error () {
local cli_text="${CMD}: `gettext \"error:\"` ${@}"
local dialog_text="<b><big>`gettext \"Error\"`</big></b>
echo "${cli_text}" >&2
sudo -u "${SUDO_USER}" zenity --error --title "" --text "${dialog_text}"
exit 1
verify_start () {
# Make sure the user really wants to start the browser in case the router console isn't available
local dialog_msg="<b><big>`gettext \"Do you still want to launch I2P Browser?\"`</big></b>
`gettext \"The I2P router console is not ready.\"`"
local launch="`gettext \"_Launch\"`"
local exit="`gettext \"_Exit\"`"
if ! sudo -u "${SUDO_USER}" \
zenity --question --title "" --text "${dialog_msg}" --default-cancel \
--cancel-label "${exit}" --ok-label "${launch}" ; then
exit 0
show_start_notification () {
local title="`gettext \"Starting the I2P Browser...\"`"
local body="`gettext \"This may take a while, so please be patient.\"`"
tails-notify-user "${title}" "${body}" 10000
copy_extra_tbb_prefs () {
local chroot="${1}"
local browser_name="${2}"
local browser_user="${3}"
local tbb_prefs="/etc/tor-browser/profile/preferences"
local browser_prefs_dir="${chroot}/home/${browser_user}/.${browser_name}/profile.default/preferences"
mkdir -p "${browser_prefs_dir}"
# Selectively copy the TBB prefs we want
sed '/\(security\|update\|download\|spell\|noscript\|torbrowser\)/!d' "${tbb_prefs}/0000tails.js" > \
sed '/\(capability\|noscript\)/!d' "${tbb_prefs}/extension-overrides.js" > \
chown -R "${browser_user}:${browser_user}" "${browser_prefs_dir}"
show_shutdown_notification () {
local title="`gettext \"Shutting down the I2P Browser...\"`"
local body="`gettext \"This may take a while, and you may not restart the I2P Browser until it is properly shut down.\"`"
tails-notify-user "${title}" "${body}" 10000
# Main script:
# This isn't very useful without I2P...
i2p_is_enabled || exit 0
CMD="$(basename "${0}")"
HUMAN_READABLE_NAME="`gettext \"I2P Browser\"`"
# Prevent multiple instances of the script.
exec 9>"${LOCK}"
if ! flock -x -n 9; then
error "`gettext \"Another I2P Browser is currently running, or being cleaned up. Please retry in a while.\"`"
if ! i2p_router_console_is_ready; then
echo "* Setting up chroot"
setup_chroot_for_browser "${CHROOT}" "${COW}" "${BROWSER_USER}" || \
error "`gettext \"Failed to setup chroot.\"`"
echo "* Configuring chroot"
configure_chroot_browser "${CHROOT}" "${BROWSER_USER}" "${BROWSER_NAME}" \
"${TBB_EXT}"/langpack-*.xpi "${NOSCRIPT_EXT_XPI}" "${TORBUTTON_EXT_DIR}" && \
copy_extra_tbb_prefs "${CHROOT}" "${BROWSER_NAME}" "${BROWSER_USER}" || \
error "`gettext \"Failed to configure browser.\"`"
echo "* Starting I2P Browser"
run_browser_in_chroot "${CHROOT}" "${BROWSER_NAME}" "${BROWSER_USER}" \
"${SUDO_USER}" || \
error "`gettext \"Failed to run browser.\"`"
echo "* Exiting the I2P Browser"
exit 0
set -e
set -u
# Get LANG
. /etc/default/locale
export LANG
# Initialize gettext support
# Import wait_until()
. /usr/local/lib/tails-shell-library/
# Import i2p_built_a_tunnel, i2p_reseed_failed, i2p_router_console_is_ready(),
# and set_best_i2p_router_console_lang().
. /usr/local/lib/tails-shell-library/
# When there are network problems (either local or remote), it can take up to 3
# minutes for all of the current reseed servers to be tried.
# After the router infos (RIs) are downloaded from the reseed servers
# it can take 3-5 minutes for a tunnel to be built, e.g.
# once we get to this point I2P should be ready to be used.
startup_failure() {
/usr/local/sbin/tails-notify-user \
"`gettext \"I2P failed to start\"`" \
"`gettext \"Something went wrong when I2P was starting. Check the logs in /var/log/i2p for more information.\"`"
service i2p dump # generate a thread dump
sleep 5 # Give thread dump ample time to complete
systemctl stop i2p # clean up, just in case
exit 1
wait_until_i2p_router_console_is_ready() {
wait_until ${I2P_STARTUP_TIMEOUT} i2p_router_console_is_ready
wait_until_i2p_has_bootstrapped() {
wait_until ${I2P_BOOTSTRAP_TIMEOUT} '[ "$(i2p_reseed_status)" = success ]'
notify_router_console_success() {
/usr/local/sbin/tails-notify-user \
"`gettext \"I2P's router console is ready\"`" \
"`gettext \"You can now access I2P's router console in the I2P Browser.\"`"
bootstrap_failure() {
/usr/local/sbin/tails-notify-user \
"`gettext \"I2P is not ready\"`" \
"`gettext \"Eepsite tunnel not built within six minutes. Check the router console in the I2P Browser or the logs in /var/log/i2p for more information. Reconnect to the network to try again.\"`"
exit 1
wait_until_i2p_builds_a_tunnel() {
wait_until ${I2P_TUNNEL_BUILD_TIMEOUT} i2p_built_a_tunnel
# static sleep to work around upstream bug.
sleep 240
notify_bootstrap_success() {
/usr/local/sbin/tails-notify-user \
"`gettext \"I2P is ready\"`" \
"`gettext \"You can now access services on I2P.\"`"
case "${1}" in