onion-grater, a Tor Control Port Filter Proxy - filtering dangerous Tor Control Port commands - Design Documentation

From Whonix
< Dev(Redirected from Dev/CPFP)



Tor's control port has in context of Whonix ™, dangerous features. The answer to the Tor control command GETINFO address will be the real external IP of the Tor client. Other dangerous commands include SETCONF, LOADCONF, GETCONF, getinfo ns/id/<relay-fingerprint>.

This can not be limited any other way, since the feature request Option to limit information Tor's control port discloses against Tor has not been implemented. By the way, this Tor control port feature makes also a Bridge Firewall impossible. Therefore before Whonix ™ 6, Whonix-Workstation ™ had no access to Tor's control port. This was because, Whonix-Workstation ™ is not supposed to have an way of finding out its own external IP address.

Before Whonix ™ 6, this also broke Tor Button's New Identity feature, which essentially sends SIGNAL NEWNYM to Tor's control port. While Tor Button's New Identity is still the only feature that was not available when using Tor Browser in Whonix ™, Tor Button in future will get more and more dependent on Tor's control port.

Tor Browser by default performs its own control port verification. It checks using Tor's control port(!), that the socks port Tor reports, is the same one as Tor Browser is configured to use. If it fails, and it would fail in Whonix ™ 0.5.6, Tor Button would look like disabled and show a failure message. (To see how this would look like, see this screenshot.) (To see how this generates user confusion, see this forum thread.) Since Whonix ™ 6 this check is disabled using environment variable to skip TorButton control port verification (export TOR_SKIP_CONTROLPORTTEST=1) by package anon-ws-disable-stacked-tor. [1]

In future, Tor Button will likely also use something like GETINFO clockskew. Tor Browser developer rejected the idea of not adding the statement require no access to Tor's control port to Tor Browser's design.

Therefore all requirements, Whonix-Workstation ™ having no way of finding its own external IP address, joining Tor Browser's fingerprint for Whonix ™ users, having no access for Whonix-Workstation ™ to Tor's control port with Tor Buttons new requirement to have access to Tor's control port contradicted itself.

onion-grater has been implemented as a solution. It gives Whonix-Workstation ™ access to a limited selection of Tor's control port commands, using white listing (not blacklisting). For example, it allows SIGNAL NEWNYM to make Tor Buttons New Identity feature available for users who use Tor Browser in Whonix-Workstation ™.

Therefore when onion-grater gets asked GETINFO net/listeners/socks, it lies, and answers 250-net/listeners/socks="". This makes Tor Button happy and therefore it shows a "Congratulations!" (success) welcome page on its default homepage about:tor and not the failure page, which would confuse users. Since bug TorButton about:tor fails when using additional socks listeners has been fixed by Tor Tor Project, it that lie wouldn't be necessary anymore. We're keeping it, because it is not necessary for Tor Button get a full list of all ports Tor is listening on. If an attacker compromised Whonix-Workstation ™, hiding that list has an advantage. The attacker can probe what ports are available to that Whonix-Workstation ™, but if the user added extra ports not available to the compromised Whonix-Workstation ™ (only available to another Whonix-Workstation ™ listening on another IP), at least those remain secret. (This is a bit theoretical, because a compromised Whonix-Workstation ™ can spoof its LAN IP and most likely very few users are using ARP spoofing defenses. Should we add ARP spoofing defenses by default at some point, we at least don't have to worry about this point.)

For eventual further Tor control port access requirements by Tor Button, the configuration file of accepted commands has to be extended. If Tor Button would ever ask for anything which violates Whonix ™ design (Whonix-Workstation ™ has no way of finding out its own external IP address in particular), such as GETINFO address, for example if Tor Button wanted to ensure, that the user is not using its own external IP address, a new lie would have to be added to the onion-grater script. In case many more lies are required, lies should go into the config file as well, for now, hard coding is sufficient.

systemcheck asks onion-grater status/bootstrap-phase [2] as well as status/circuit-established [3] in Tor Bootstrap Status Check [4] (usability feature).

onion-grater limits maximum accepted command string length to 128 (configurable) (credits: [5] [6]) for better security.

Advanced users who do not wish to use onion-grater can disable it, see deactivate onion-grater.

TODO: expand - required for OnionShare and others

Whonix-Workstation ™[edit]

Whonix ™ sets appropriate environment variables for control port (9051), control port ip ( and control port password "password". The latter is not really in use, its just to make Tor Button happy, because it doesn't default to some password. Tor Button sends it, but its ignored by onion-grater.

This functionality is implemented by the anon-ws-disable-stacked-tor package. See also Dev/anon-ws-disable-stacked-tor.

Tor Browser (running in Whonix-Workstation ™) is configured by default (not changed by Whonix ™) to connect to Tor control port TODO: document unix domain socket files

Whonix-Gateway ™[edit]

onion-grater listens on Whonix ™ internal network interface [7], port 9051, filters (white list) incoming control port messages and forwards them to the real Tor Control Port listening on ControlSocket /run/tor/control. onion-grater itself uses cookies authentication to authenticate Tor's control port. The latter is not important, since Whonix-Gateway ™ only purpose is running Tor, its not a multi user operating system, and if it were compromised, cookie authentication wouldn't be of help anymore either.

Attack Scenarios[edit]

Once Whonix-Workstation ™ has been compromised, the adversary could continuously and/or using a pattern, send white listed commands to Tor. At the moment, only NEWNYM would be of interest. When the adversary is also an ISP level adversary, the adversary might be able to see the pattern being produced. This however is not a big risk, since once Whonix-Workstation ™ is compromised, more powerful attacks are available - An adversary could also use "Morse Code", i.e. limit the victims traffic for a few seconds to zero or close to zero, then push the traffic to its maximum.

More worrying is the extended attack surface.

Imitating real Tor Control Connection[edit]

Should Tor close the connection, onion-grater will also close client connection. (Same for a real Tor control connection.)

Both real Tor control connection and onion-grater close the connection if commands are sent when the client is not yet authenticated. (With the exception of authenticate, authchallenge and protocolinfo so there is parity.)

Should Tor authentication fail, this is logged and onion-grater closes client connection.


To get a list of Tor ControlPort commands, that TorButton uses, get into TorButton source code, extract TorButton, then run.

grep -r -i torbutton_send_ctrl_cmd *
grep -r -i sendCommand *

TorButton Network Settings[edit]

TorButton → Open Network Settings...

Is using.

   "GETCONF Socks4Proxy"
   "GETCONF Socks5Proxy"
   "GETCONF ReachableAddresses"
   "GETCONF ReachableAddresses"
   "GETCONF UseBridges"
   "GETCONF Bridge"

As the next logical step by the way, they are likely going to add.


We are setting environment variable export TOR_NO_DISPLAY_NETWORK_SETTINGS=1 to disable the "TorButton" → "Open Network Settings..." menu item. It is not useful and confusing to have on a workstation, because Tor must be configured on the gateway, which is for security reasons forbidden from the workstation.


To get a list of Tor ControlPort commands, that TorLauncher uses, get into TorLauncher source code, extract TorLauncher, then run.

grep -r -i getconf

Debugging Inspiration[edit]


Restart onion-grater after making changes to it.

sudo service onion-grater restart

Watch onion-grater's log on Whonix-Gateway ™ while using it in a separate terminal tab.

sudo journalctl -f -u onion-grater

apparmor issues[edit]

Watch kern.log for eventual iptables log messages, run this on Whonix-Gateway ™.

sudo apparmor-info

connect to onion-grater from gateway[edit]

To connect to onion-grater from a Non-Qubes-Whonix ™-Gateway.

nc 9051

To connect to onion-grater from a Qubes-Whonix ™-Gateway.

nc $(qubesdb-read /qubes-netvm-gateway) 9051

connect to onion-grater from workstation[edit]

On the Whonix-Workstation ™ you should be able to run.

nc 9051

Type "something". Enter. Should reply "510 Command filtered".




250 OK


GETINFO net/listeners/socks




GETINFO address


510 Prohibited command "GETINFO address"



tcpdump - Less Important[edit]

Only in case of suspected fundamental issues with low level networking.

To see what's being send to onion-grater's port, run this on Whonix-Gateway ™.


sudo tcpdump -i eth1 -l -s0 -w - tcp dst port 9051 | strings

Qubes: (Note: replace vif18.0.)

sudo tcpdump -i vif18.0 -l -s0 -w - tcp dst port 9051 | strings

onion-grater enable debug mode[edit]

On gateway.

Open file /lib/systemd/system/onion-grater.service.d/50_user.conf in an editor with administrative (root) write permissions.

This box uses sudoedit for better security. This is an example and other tools can also achieve the same goal. If this example does not work for you or if you are not using Whonix ™, please refer to this link.

sudoedit /lib/systemd/system/onion-grater.service.d/50_user.conf


## Clear onion-grater default file '/lib/systemd/system/onion-grater.service'.

## Same as above but enable debug mode.
ExecStart=/usr/lib/onion-grater --listen-interface eth1 --debug

## Same as above but enable complain mode which permits everything (insecure in production).
#ExecStart=/usr/lib/onion-grater --listen-interface eth1 --complain


Reload systemd.

sudo systemctl daemon-reload

Restart onion-grater.

sudo systemctl restart onion-grater

Done, debug mode is now enabled.

onion-grater passthrough allow all commands[edit]

This disables filtering and should be used during development only.

On Whonix-Gateway ™.

sudo systemctl stop onion-grater
sudo /usr/lib/onion-grater-merger
sudo -u onion-grater /usr/lib/onion-grater --listen-interface eth1 --complain

In Whonix-Workstation ™.

sudo apt install netcat-openbsd
netcat 9051


getinfo status/bootstrap-phase

Press Enter.

Talking to the real Tor Control Port[edit]

On Whonix-Gateway ™. (test is the example password being used. Feel free to use a different/stronger one.

tor --hash-password test

Will show something like this.


Open file /usr/local/etc/torrc.d/50_user.conf in a text editor of your choice with sudoedit.

If you are using Qubes-Whonix ™, complete the following steps.

Qubes App Launcher (blue/grey "Q")Whonix-Gateway ™ ProxyVM (commonly named sys-whonix)Tor User Config (Torrc)

If you are using a graphical Whonix-Gateway ™, complete the following steps.

Start MenuApplicationsSettings/usr/local/etc/torrc.d/50_user.conf

If you are using a terminal-only Whonix-Gateway ™, complete the following steps.

sudoedit /usr/local/etc/torrc.d/50_user.conf

HashedControlPassword 16:1CEAF6E6A08E0CF460AFD71772461C5F56BD9738FA8824B882FCA4A785

Reload Tor.

After changing Tor configuration, Tor must be reloaded for changes to take effect.

Note: If Tor does not connect after completing all these steps, then a user mistake is the most likely explanation. Recheck /usr/local/etc/torrc.d/50_user.conf and repeat the steps outlined in the sections above. If Tor then connects successfully, all the necessary changes have been made.

If you are using Qubes-Whonix ™, complete the following steps.

Qubes App Launcher (blue/grey "Q")Whonix-Gateway ™ ProxyVM (commonly named 'sys-whonix')Reload Tor

If you are using a graphical Whonix-Gateway ™, complete the following steps.

Start MenuApplicationsSettingsReload Tor

If you are using a terminal-only Whonix-Gateway ™, click HERE for instructions.

Complete the following steps.

Reload Tor.

sudo service tor@default reload

Check Tor's daemon status.

sudo service tor@default status

It should include a a message saying.

Active: active (running) since ...

In case of issues, try the following debugging steps.

Check Tor's config.

sudo -u debian-tor tor --verify-config

The output should be similar to the following.

Sep 17 17:40:41.416 [notice] Read configuration file "/usr/local/etc/torrc.d/50_user.conf".
Configuration was valid
sudo service tor reload

Connect to Tor's ControlPort.

sudo --non-interactive -u debian-tor socat - UNIX-CONNECT:/var/run/tor/control


authenticate "test"

Should reply.

250 OK

Test your commands. For example.

setevents stream

Will do nothing after this, but when you start using Tor (i.e. by running Tor Browser, APT or so), it will show something like this (events).

650 STREAM 211 NEW 0 pop.riseup.net:995 SOURCE_ADDR= PURPOSE=USER

Indicator for current Circuit Status and Exit IP[edit]

- exe-paths:
    - '*'
    - '*'
    - '*'
      - 'NEWNYM'
      - pattern: 'circuit-status'
        - pattern: '250(.+)circuit-status=(\S+) (\S+) (.+) (\S+) (\S+)'
        - replacement: '250+circuit-status='
      - pattern: 'bridge'
        - pattern:     '250-Bridge=(.+) (\S+) (\S+) (\S+) (\S+)'
          replacement: '250-Bridge='
        - pattern:     '250 Bridge=(.+) (\S+) (\S+) (\S+) (\S+)'
          replacement: '250 Bridge='
  restrict-stream-events: true

UI for ExitNode country selection in tor-launcher[edit]


feedback mechanism for clock-skew and other bad problems[edit]


Whonix ™ Forum Discussion[edit]

new Tor ControlPort commands wanted by TBB 4.5 and above


example command for Tor control protocol:

onion_client_auth_add m5bmcnsk64naezc26scz2xb3l3n2nd5xobsljljrpvf77tclmykn7wid x25519:uBKh6DGrkcFxB1adYuyKQltUDDUT9IZrOsne3nfHbHI=

Test key that can be entered into browser.



https://gitlab.com/whonix/anon-gw-anonymizer-config/-/blob/master/etc/onion-grater-merger.d/30_whonix-default.yml would need extensive modification.

- exe-paths:
    - '*'
    - '*'
    - '*'
      - 'NEWNYM'
      - 'status/circuit-established'
      - 'version'
      - pattern: 'net/listeners/socks'
        - pattern:     '250-net/listeners/socks=".*"'
          replacement: '250-net/listeners/socks=""'
      - 'consensus/valid-after'
      - 'consensus/valid-until'
      - 'consensus/fresh-until'
      - pattern: 'circuit-status'
        - pattern:     '250+circuit-status='
          replacement: '250+circuit-status='
        - pattern:     '250 OK'
          replacement: '250 OK'
        - pattern:     '(.+)'
          replacement: 'redacted'
      - pattern: 'bridge'
        - pattern:     '(.+)'
          replacement: '250 Bridge'
      - 'stream'
        - pattern:     '(.+)'
          replacement: 'redacted'
        - pattern:     '(.+)'
          replacement: 'redacted'
        - pattern:     '(.+)'
          replacement: 'redacted'
        - pattern:     '(.+)'
          replacement: 'redacted'
        - pattern:     '(.+)'
          replacement: 'redacted'

Comparison of Control Port Filters[edit]

roflcoptor by subgraph os[edit]

roflcoptor by subgraph os

  • Many golang dependencies that are not packaged for Debian.
  • Event support.
  • Wildcard support.
  • TODO: expand

surrogate.go by Yawning Angel[edit]

surrogate.go (tor project gitweb) by Yawning Angel

  • golang (build dep, not run dep)
  • AGPL (Achtung!)
  • Part of new/upcoming Sandboxed Tor Browser
  • "Tor control/socks port surrogates." (quoting top comment) Intended to proxy/filter both ControlPort and SOCKSPort of tor process in one bubblewrapped sandbox, while actual Tor Browser runs in another bubblewrapped sandbox.
  • Observed version: 6ff4802
  • So, official TPO Tor Browser variant also has this problem. Oops!

onion-grater by Tails[edit]

onion-grater by Tails (config folder)

  • Written in python3.
  • All dependencies already inside Debian.
  • Wildcard / regex support.
  • Supports rewriting client requests.
  • Supports rewriting Tor replies.
  • Parallel connections support.
  • Can reply to getinfo net/listeners/socks with the lie '250-net/listeners/socks=""'.
  • Logs to journal.
  • Honors signals sigterm, sigint.
  • Supports subscribing Tor ControlPort events (setevent).

onion-grater by Tails forked by Whonix ™[edit]

onion-grater (config folder) (additional onion-grater-merger example profiles) (issue tracker)

legacy control-port-filter-python by Whonix ™[edit]

legacy control-port-filter-python (main script) [Whonix ™ 10 to Whonix ™ 13 (version 1.7-1] (last git commit up to 99e8395fbafcb7789c7d1b5cbf7410ed65192e9a) (issue tracker) [deprecated]

  • A fork of (very early) tor-controlport-filter by Tails. (See above.)
  • Written in python2.7.
  • Configurable by dropping .d-style[10] configuration snippets into /etc/cpfpy.d.
  • Support to answer getinfo net/listeners/socks with the lie '250-net/listeners/socks=""'.
  • Supports logging.
  • Honors signals sigterm, sigint, keyboard interrupt.
  • Supports parallel connections.
  • Supports wildcards, which is for tools such as onionshare that are using add_onion *.
  • Injects workstation IP into add_onion. For example will transform from / to:
    • add_onion new:best port=80,17600
    • add_onion new:best port=80,
  • Support subscribing Tor ControlPort events (setevent). (Whonix ™ 14 and above.) [11]
  • Complete systemd unit file.
  • Lintian clean /debian packaging folder.
  • Will be deprecated when Whonix ™ 14 get released.

legacy2 control-port-filter by Whonix ™[edit]

legacy^2 control-port-filter [up to Whonix ™ 9.x] [deprecated]

  • Supports parallel connections.
  • Written in bash. (github) (archive only)
  • White lists multiple useful Tor ControlPort commands.
  • Configurable using /etc/controlportfilt.d drop-in files.
  • Support to answer getinfo net/listeners/socks with the lie '250-net/listeners/socks=""'.
  • Supports logging.
  • Honors signals sigterm, sigint.
  • Does not support wildcards.
  • Does not support subscribing Tor ControlPort events (setevent).
  • Complete sysvinit script.
  • Lintian clean /debian packaging folder.
  • Deprecated since the release of Whonix ™ 10.

See Also[edit]


  1. https://github.com/Whonix/anon-ws-disable-stacked-tor/blob/master/usr/lib/anon-ws-disable-stacked-tor/torbrowser.sh
  2. Find out what status/bootstrap-phase answers yourself in Whonix-Gateway ™.
    /usr/lib/helper-scripts/tor_bootstrap_check.py 9051 1

    Example answer.

  3. Find out what status/circuit-established answers yourself in Whonix-Gateway ™.
    /usr/lib/helper-scripts/tor_circuit_established_check.py 9051 1

    Example answer.

  4. https://github.com/Whonix/systemcheck/blob/master/usr/libexec/systemcheck/check_tor_bootstrap
    whonixcheck --function check_tor_bootstrap
    whonixcheck --function check_tor_bootstrap --verbose --debug
  5. As done by Tails.
  6. Thanks to HulaHoop for suggesting this.
  7. https://github.com/Whonix/whonix-gw-network-conf/blob/master/lib/systemd/system/onion-grater.service.d/30_cpfpy.conf
  8. https://git-tails.immerda.ch/onion-grater/commit/?id=33ae20850329930bd1a3686cca2a9ac4dc766aea +* **events**: Tor Browser is subscribed to all STREAM events for its + implementation of the circuit view. This means it will know + basically everything Tor is doing which is pretty bad in case Tor + Browser is compromised.
  9. https://phabricator.whonix.org/T631
  10. Whonix_Configuration_Files#.d_Style_Configuration_Folders
  11. https://phabricator.whonix.org/T448