Come configurare più relays Tor sulla stessa interfaccia con IP diversi

4 febbraio 2025

Il principale collo di bottiglia nei relay Tor è spesso la velocità di clock del processore, e siccome Tor non supporta il multithreading, solitamente la soluzione migliore è eseguire un’istanza di Tor per ogni core (o thread). Dato il costo dell’elettricità, stiamo cercando hardware che consumi e costi poco, ma che sia comunque in grado di saturare la banda. Gli apu2, sebbene non più in produzione, restano ottime macchine, usate da anni e con supporto stabile a coreboot. Il modello che stiamo testando ha queste specifiche:

  • 4 core fisici / 4 thread @ 1GHz
  • 2GB DDR3 DRAM
  • 4x Gigabit Ethernet

Vogliamo individuare la configurazione che ottimizza al meglio le risorse, avendo a disposizione un’intera subnet IPv4 e 2.5 Gbit di banda in upload.

Setup iniziale #

E’ disponibile un insieme di script molto pratico per gestire più processi Tor nello stesso sistema.

Prima di tutto, bisogna disabilitare il servizio Tor di default:

systemctl disable tor
systemctl stop tor

Creiamo quindi l’istanza desiderata:

tor-instance-create <name of the instance>

Tutte le configurazioni si trovano in /etc/tor/instances e possono essere gestite come servizi di sistema separati.

systemctl start tor@<name of the instance>
systemctl enable tor@<name of the instance>

Abbiamo provato con 4 processi (uno per ogni core), ma a causa della poca RAM a disposizione, le singole istanze non superavano i 4 MB/s: il minimo di memoria necessaria per ciascuno sembra essere intorno a 400-500M. Abbiamo quindi cambiato configurazione e applicato alcune ottimizzazioni:

  • Usare zram per comprimere la memoria
  • Eliminare dbus: nel nostro caso non abbiamo altri servizi in esecuzione e questo permette di risparmiare 50-80 MB di memoria
  • Eliminare unbound: sappiamo che e’ indicato come best practice per gli exit node, ma abbiamo scelto di indicare esplicitamente i nostri dns server in /etc/resolv.conf

In questo modo siamo riusciti ad abbassare l’utilizzo di memoria del sistema di base e a lasciare circa 1.6 GB di RAM liberi per le istanze Tor.

Configurazione di rete #

Su un’interfaccia di rete abbiamo assegnato 3 indirizzi IPv4 e 3 indirizzi IPv6 perché ne abbiamo disponibilità, ma spesso si usa lo stesso IP e si scelgono porte diverse (c’è tuttavia un limite imposto dalle directory authority sul numero di nodi che possono avere lo stesso IPv4, attualmente 8).

Abbiamo quindi la seguente interfaccia di rete:

5: enp2s0.835@enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:0d:b9:4a:bf:71 brd ff:ff:ff:ff:ff:ff
    inet 64.190.76.2/24 brd 64.190.76.255 scope global enp2s0.835
       valid_lft forever preferred_lft forever
    inet 64.190.76.3/24 brd 64.190.76.255 scope global secondary enp2s0.835
       valid_lft forever preferred_lft forever
    inet 64.190.76.4/24 brd 64.190.76.255 scope global secondary enp2s0.835
       valid_lft forever preferred_lft forever
    inet6 2001:67c:e28:1::4/64 scope global
       valid_lft forever preferred_lft forever
    inet6 2001:67c:e28:1::3/64 scope global
       valid_lft forever preferred_lft forever
    inet6 2001:67c:e28:1::2/64 scope global
       valid_lft forever preferred_lft forever

Tuttavia, dopo qualche settimana, ci contatta il Network Health Team perché hanno rilevato che i relays, pur avendo indirizzi IPv4 diversi, risultavano uscire tutti sullo stesso.

Nota: è fondamentale fornire informazioni di contatto accurate quando si gestiscono nodi Tor, proprio per questo motivo. Non è la prima volta che riceviamo avvisi o suggerimenti su come migliorare la nostra gestione.

Per cambiare l’IP sorgente di un processo Linux ci sono diverse soluzioni, tra cui:

  1. Regole manuali di iptables
  2. RoutingPolicyRule di systemd
  3. Interfacce di gestione di iptables

Abbiamo scelto la terza opzione con shorewall per comodità. La configurazione si trova in /etc/shorewall.

I file per configurare la mappatura dei processi rispetto agli indirizzi IP di uscita sono:

  • /etc/shorewall/mangle: per marcare i pacchetti in uscita di uno UID
  • /etc/shorewall/snat: per mascherare i pacchetti marcati con gli indirizzi IP scelti

Ecco un esempio di configurazione con cui i pacchetti dello UID tor-bludicapra vengono marcati (2) e viene effettuato il source NAT sull’interfaccia di uscita enp2s0.835 con IP 64.190.76.2.

/etc/shorewall/mangle

#ACTION    SOURCE    DEST        PROTO DPORT SPORT   USER
MARK(2)    $FW       0.0.0.0/0   -    -    -    _tor-bludicapra

/etc/shorewall/snat

#ACTION    SOURCE    DEST         PROTO    DPORT    SPORT    IPSEC    MARK
SNAT(64.190.76.2)    -    enp2s0.835    -    -    -    -    2

Il prerequisito è che gli indirizzi di uscita siano configurati sull’interfaccia WAN (es. via /etc/network/interfaces).

Altri file significativi di shorewall, che non richiedono modifiche per questa configurazione, sono, in ordine di elaborazione del filtro:

  • /etc/shorewall/interfaces: per la configurazione delle interfacce filtrate
  • /etc/shorewall/rules: per le regole del firewall
  • /etc/shorewall/policy: per le policy globali

Dopo ogni modifica si può verificare la configurazione e applicarla:

shorewall check
shorewall reload

I formaggini #

Da questa esperienza è nata una piccola famiglia di formaggi italiani: